Projects
Mega:24.03
kernel
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 5
View file
_service:tar_scm:kernel.spec
Changed
@@ -16,6 +16,23 @@ %define modsign_cmd %{SOURCE10} +%if 0%{?openEuler_sign_rsa} +# Use the open-source signature when the EBS permission is insufficient. +# Now only the admin user in EBS can send the signature request. But the +# user triggering the acces control build task and the personal build +# task is non-admin. Inorder to avoid build failures caused by failed +# signing, use the open-source signature. +# The flag_openEuler_has_sign_perm used in the rpm execution phase +# The openEuler_has_sign_perm used in the rpm execution phase + +%define openEuler_check_EBS_perm openEuler_has_sign_perm=0 \ +echo "" >> test_openEuler_sign.ko \ +sh /usr/lib/rpm/brp-ebs-sign --module test_openEuler_sign.ko || \ + $? -ne 2 && openEuler_has_sign_perm=1 \ +%global flag_openEuler_has_sign_perm $openEuler_has_sign_perm \ +rm -f test_openEuler_sign.ko test_openEuler_sign.ko.sig +%endif + %global Arch $(echo %{_host_cpu} | sed -e s/i.86/x86/ -e s/x86_64/x86/ -e s/aarch64.*/arm64/ -e s/riscv.*/riscv/ -e s/powerpc64le/powerpc/) %global KernelVer %{version}-%{release}.%{_target_cpu} @@ -23,9 +40,9 @@ %global upstream_version 6.6 %global upstream_sublevel 0 -%global devel_release 19 +%global devel_release 20 %global maintenance_release .0.0 -%global pkg_release .19 +%global pkg_release .21 %define with_debuginfo 1 # Do not recompute the build-id of vmlinux in find-debuginfo.sh @@ -64,10 +81,6 @@ Source10: sign-modules Source11: x509.genkey Source12: extra_certificates -# openEuler RPM PGP certificates: -# 1. openeuler <openeuler@compass-ci.com> -Source13: RPM-GPG-KEY-openEuler-compass-ci -Source14: process_pgp_certs.sh %if 0%{?openEuler_sign_rsa} Source15: openeuler_kernel_cert.cer @@ -288,7 +301,6 @@ %endif %prep - %setup -q -n kernel-%{version} -c %if 0%{?with_patch} @@ -298,12 +310,6 @@ mv kernel linux-%{KernelVer} cd linux-%{KernelVer} -# process PGP certs -cp %{SOURCE13} . -cp %{SOURCE14} . -sh %{SOURCE14} -cp pubring.gpg certs - %if 0%{?with_patch} cp %{SOURCE9000} . cp %{SOURCE9001} . @@ -396,11 +402,14 @@ %endif %if 0%{?openEuler_sign_rsa} - cp %{SOURCE15} ./certs/openeuler-cert.pem + %{openEuler_check_EBS_perm} + if $openEuler_has_sign_perm -eq 1 ; then + cp %{SOURCE15} ./certs/openeuler-cert.pem # close kernel native signature - sed -i 's/CONFIG_MODULE_SIG_KEY=.*$/CONFIG_MODULE_SIG_KEY=""/g' .config - sed -i 's/CONFIG_SYSTEM_TRUSTED_KEYS=.*$/CONFIG_SYSTEM_TRUSTED_KEYS="certs\/openeuler-cert.pem"/g' .config - sed -i 's/CONFIG_MODULE_SIG_ALL=y$/CONFIG_MODULE_SIG_ALL=n/g' .config + sed -i 's/CONFIG_MODULE_SIG_KEY=.*$/CONFIG_MODULE_SIG_KEY=""/g' .config + sed -i 's/CONFIG_SYSTEM_TRUSTED_KEYS=.*$/CONFIG_SYSTEM_TRUSTED_KEYS="certs\/openeuler-cert.pem"/g' .config + sed -i 's/CONFIG_MODULE_SIG_ALL=y$/CONFIG_MODULE_SIG_ALL=n/g' .config + fi %endif TargetImage=$(basename $(make -s image_name)) @@ -528,21 +537,24 @@ install -m 755 $(make -s image_name) $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer} %if 0%{?openEuler_sign_rsa} - echo "start sign" - %ifarch %arm aarch64 - gunzip -c $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}>$RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip.efi - sh /usr/lib/rpm/brp-ebs-sign --efi $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip.efi - mv $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip.efi.sig $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip.efi - mv $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip.efi $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip - gzip -c $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip>$RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer} - rm -f $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip - %endif - %ifarch x86_64 - mv $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer} $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.efi - sh /usr/lib/rpm/brp-ebs-sign --efi $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.efi - mv $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.efi.sig $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.efi - mv $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.efi $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer} - %endif + %{openEuler_check_EBS_perm} + if $openEuler_has_sign_perm -eq 1 ; then + echo "start sign" + %ifarch %arm aarch64 + gunzip -c $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}>$RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip.efi + sh /usr/lib/rpm/brp-ebs-sign --efi $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip.efi + mv $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip.efi.sig $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip.efi + mv $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip.efi $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip + gzip -c $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip>$RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer} + rm -f $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip + %endif + %ifarch x86_64 + mv $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer} $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.efi + sh /usr/lib/rpm/brp-ebs-sign --efi $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.efi + mv $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.efi.sig $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.efi + mv $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.efi $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer} + %endif + fi %endif pushd $RPM_BUILD_ROOT/boot @@ -628,7 +640,14 @@ %if 0%{?openEuler_sign_rsa} %define __modsign_install_post \ if "%{with_signmodules}" -eq "1" ;then \ -sh %{SOURCE16} $RPM_BUILD_ROOT/lib/modules/%{KernelVer} || exit 1 \ + if %flag_openEuler_has_sign_perm -eq 1 ; then \ + sh %{SOURCE16} $RPM_BUILD_ROOT/lib/modules/%{KernelVer} || exit 1 \ + else \ + cp certs/signing_key.pem . \ + cp certs/signing_key.x509 . \ + chmod 0755 %{modsign_cmd} \ + %{modsign_cmd} $RPM_BUILD_ROOT/lib/modules/%{KernelVer} || exit 1 \ + fi \ fi \ find $RPM_BUILD_ROOT/lib/modules/ -type f -name '*.ko' | xargs -n1 -P`nproc --all` xz; \ %{nil} @@ -1000,6 +1019,93 @@ %endif %changelog +* Tue Apr 16 2024 Zheng Zengkai <zhengzengkai@huawei.com> - 6.6.0-20.0.0.21 +- !6048 improve 3SNIC 910/920/930 NIC driver +- improve 3SNIC 910/920/930 NIC driver +- !5815 v2 Support NMI in the virtual machine +- KVM: arm64: vgic-v3: Handle traps of ICV_NMIAR1_EL1 +- arm64: Decouple KVM from CONFIG_ARM64_NMI +- KVM: arm64: Handle traps of ALLINT +- KVM: arm64: Allow GICv3.3 NMI if the host supports it +- KVM: arm64: vgic-v3: Don't inject an NMI if the vcpu doesn't have FEAT_NMI +- KVM: arm64: Don't trap ALLINT accesses if the vcpu has FEAT_NMI +- KVM: arm64: Allow userspace to control ID_AA64PFR1_EL1.NMI +- KVM: arm64: vgic-debug: Add the NMI field to the debug output +- KVM: arm64: vgic-v3: Add userspace selection for GICv3.3 NMI +- KVM: arm64: vgic-v3: Add support for GIC{D,R}_INMIR registers +- KVM: arm64: vgic-v3: Use the NMI attribute as part of the AP-list sorting +- KVM: arm64: vgic-v4: Propagate the NMI state into the GICv4.1 VSGI configuration +- KVM: arm64: vgic-v3: Make NMI priority RES0 +- KVM: arm64: vgic-v3: Allow the NMI state to make it into the LRs +- KVM: arm64: vgic-v3: Upgrade AP1Rn to 64bit. +- !5752 【OLK-6.6】Add Chengdu BeiZhongWangXin Technology N5/N6 Series Network Card Driver +- drivers: add Chengdu BeiZhongWangXin Technology N5/N6 Series Network Card Driver +- !5730 OLK-6.6 Fix warnings for RNPGBEVF driver +- RNPGBEVF: NET: Fix wanrings +- !5726 OLK-6.6 Fix warnings for RNPVF driver +- RNPVF: NET: Fix wanrings +- !5854 OLK-6.6 Make Cluster Scheduling Configurable +- scheduler: Disable cluster scheduling by default +- scheduler: Add boot time enabling/disabling of cluster scheduling +- scheduler: Add runtime knob sysctl_sched_cluster +- scheduler: Create SDTL_SKIP flag to skip topology level +- !6068 mm: batch mm counter updating in filemap_map_pages() +- mm: filemap: batch mm counter updating in filemap_map_pages() +- mm: move mm counter updating out of set_pte_range() +- !5931 irqchip/gicv3-its: Add workaround for hip09 ITS erratum 162100801 +- irqchip/gicv3-its: Add workaround for hip09 ITS erratum 162100801 +- !5678 v2 KVM: arm64: Translate logic cluster id to physical cluster id when updating lsudvmbm +- KVM: arm64: Translate logic cluster id to physical cluster id when updating lsudvmbm +- !5972 Perf-related bugfix +- docs: perf: Fix build warning of hisi-pcie-pmu.rst +- drivers/perf: hisi_pcie: Merge find_related_event() and get_event_idx() +- drivers/perf: hisi_pcie: Relax the check on related events +- drivers/perf: hisi_pcie: Check the target filter properly +- drivers/perf: hisi_pcie: Add more events for counting TLP bandwidth +- drivers/perf: hisi_pcie: Fix incorrect counting under metric mode +- drivers/perf: hisi_pcie: Introduce hisi_pcie_pmu_get_event_ctrl_val() +- drivers/perf: hisi_pcie: Rename hisi_pcie_pmu_{config,clear}_filter() +- drivers/perf: hisi: Enable HiSilicon Erratum 162700402 quirk for HIP09 +- docs: perf: Update usage for target filter of hisi-pcie-pmu +- !6063 RDMA/hns: Some bugfixes and cleanups +- RDMA/hns: Fix long waiting cmd event when reset +- RDMA/hns: Fix the overflow risk of hem_list_calc_ba_range() +- RDMA/hns: Fix simultaneous reset and resource deregistration +- RDMA/hns: Fix cpu stuck by printings during reset +- RDMA/hns: Fix missing capacities in query_device() +- RDMA/hns: Fix missing resetting notify +- RDMA/hns: Remove extra blank line in get_sge_num_from_max_inl_data() +- RDMA/hns: Use complete parentheses in macros +- RDMA/hns: fix iommu_map_sg() failed when MR bigger than 4G +- !6069 RDMA/hns: support roh +- RDMA/hns: Support RDMA_CM in ROH mode +- RDMA/hns: Support for ROH +- RDMA/hns: Add new device ID +- !6008 locking/osq_lock: Avoid false sharing in optimistic_spin_node +- locking/osq_lock: Avoid false sharing in optimistic_spin_node +- !5774 irqdomain: Fix driver re-inserting failures when IRQs not being freed +- irqdomain: Fix driver re-inserting failures when IRQs not being freed +- !5709 【OLK-6.6】configs: arm64: Enable CONFIG_DLM +- configs: arm64: Enable CONFIG_DLM +- !5971 RDMA/hns: Support hns roce DCA mode +- RDMA/hns: Fix DCA's dependence on ib_uverbs +- RDMA/hns: Fixes concurrent ressetting and post_recv in DCA mode +- RDMA/hns: Optimize user DCA perfermance by sharing DCA status +- RDMA/hns: Add debugfs support for DCA +- RDMA/hns: Add DCA support for kernel space +- RDMA/hns: Add method to query WQE buffer's address +- RDMA/hns: Add method to detach WQE buffer +- RDMA/hns: Setup the configuration of WQE addressing to QPC +- RDMA/hns: Add method for attaching WQE buffer +- RDMA/hns: Configure DCA mode for the userspace QP +- RDMA/hns: Add method for shrinking DCA memory pool +- RDMA/hns: Introduce DCA for RC QP + +* Fri Apr 12 2024 Jin Lun <jinlun@huawei.com> - 6.6.0-19.0.0.20 +- Remove PGP certificates. +- Optimize the signing process, if the project has no permission + to send sign request, use the kernel native signing. + * Wed Apr 10 2024 ZhangPeng <zhangpeng362@huawei.com> - 6.6.0-19.0.0.19 - !5877 optimize eevdf scheduler - sched/eevdf: Skip eligibility check for current entity during wakeup preemption
View file
_service:tar_scm:raspberrypi-kernel.spec
Changed
@@ -2,13 +2,13 @@ %global KernelVer %{version}-%{release}.raspi.%{_target_cpu} -%global hulkrelease 95.0.0 +%global hulkrelease 19.0.0 %global debug_package %{nil} Name: raspberrypi-kernel -Version: 5.10.0 -Release: %{hulkrelease}.8 +Version: 6.6.0 +Release: %{hulkrelease}.1 Summary: Linux Kernel License: GPLv2 URL: http://www.kernel.org/ @@ -166,6 +166,9 @@ /lib/modules/%{KernelVer} %changelog +* Wed Apr 17 2024 Yafen Fang <yafen@iscas.ac.cn> - 6.6.0-19.0.0.1 +- update kernel version to openEuler 6.6.0-19.0.0 + * Mon May 30 2022 Yafen Fang <yafen@iscas.ac.cn> - 5.10.0-95.0.0.8 - update kernel version to openEuler 5.10.0-95.0.0
View file
_service:tar_scm:0000-raspberrypi-kernel.patch
Changed
@@ -1,162 +1,187 @@ -From 841ff0f5f922bae6091ade91698cbe5c3b5650cb Mon Sep 17 00:00:00 2001 -From: yafen <yafen@iscas.ac.cn> -Date: Sun, 22 May 2022 05:00:13 +0800 -Subject: PATCH apply RPi patch of 5.10.95 +From b609199a78451b9d24d2432728a2fba22afc3bff Mon Sep 17 00:00:00 2001 +From: Yafen <yafen@iscas.ac.cn> +Date: Tue, 16 Apr 2024 06:59:06 +0800 +Subject: PATCH apply RPi patch of 6.6.26 (openEuler 6.6.0-19.0.0) --- .../admin-guide/media/bcm2835-isp.rst | 127 + - .../clock/raspberrypi,firmware-clocks.yaml | 32 + - .../bindings/display/brcm,bcm2711-hdmi.yaml | 20 +- + .../bindings/display/brcm,bcm2711-hdmi.yaml | 2 + .../bindings/display/brcm,bcm2835-dsi0.yaml | 1 + - .../bindings/display/brcm,bcm2835-hdmi.yaml | 118 +- - .../bindings/display/brcm,bcm2835-vc4.yaml | 5 + - .../bindings/display/brcm,bcm2835-vec.yaml | 4 +- + .../bindings/display/brcm,bcm2835-hvs.yaml | 5 +- + .../display/brcm,bcm2835-pixelvalve0.yaml | 3 + + .../bindings/display/brcm,bcm2835-txp.yaml | 5 +- + .../bindings/display/brcm,bcm2835-vc4.yaml | 1 + + .../display/panel/ilitek,ili9881c.yaml | 2 + + .../bindings/display/panel/panel-dsi.yaml | 118 + .../bindings/display/panel/panel-simple.yaml | 4 + - .../devicetree/bindings/hwmon/rpi-poe-fan.txt | 55 + + .../devicetree/bindings/gpu/brcm,bcm-v3d.yaml | 1 + + .../bindings/hwmon/microchip,emc2305.yaml | 54 + .../bindings/media/bcm2835-unicam.txt | 85 + - .../devicetree/bindings/media/i2c/imx219.txt | 59 + - .../devicetree/bindings/media/i2c/imx290.txt | 7 +- + .../devicetree/bindings/media/i2c/ad5398.txt | 20 + + .../bindings/media/i2c/arducam,64mp.yaml | 115 + + .../bindings/media/i2c/arducam-pivariety.yaml | 112 + + .../media/i2c/dongwoon,dw9807-vcm.yaml | 16 +- .../devicetree/bindings/media/i2c/imx378.yaml | 113 + .../devicetree/bindings/media/i2c/imx477.yaml | 113 + .../devicetree/bindings/media/i2c/imx519.yaml | 113 + .../devicetree/bindings/media/i2c/irs1125.txt | 48 + + .../bindings/media/i2c/ovti,ov64a40.yaml | 98 + + .../bindings/media/i2c/rohm,bu64754.yaml | 48 + + .../i2c/{imx258.yaml => sony,imx258.yaml} | 9 +- + .../bindings/media/i2c/sony,imx708.yaml | 128 + .../bindings/media/rpivid_hevc.yaml | 72 + .../bindings/misc/brcm,bcm2835-smi-dev.txt | 17 + .../bindings/misc/brcm,bcm2835-smi.txt | 48 + + .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 5 + + .../devicetree/bindings/net/cdns,macb.yaml | 16 + .../bindings/net/microchip,lan78xx.txt | 3 + - .../devicetree/bindings/nvmem/rmem.yaml | 49 + + .../bindings/pci/brcm,stb-pcie.yaml | 8 + .../devicetree/bindings/pci/brcmstb-pcie.txt | 59 + - .../bindings/power/reset/gpio-poweroff.txt | 1 + + .../bindings/power/reset/gpio-poweroff.txt | 42 + + .../devicetree/bindings/pwm/pwm-rp1.yaml | 38 + + .../devicetree/bindings/rtc/rtc-rpi.txt | 22 + .../devicetree/bindings/serial/pl011.yaml | 6 + + .../devicetree/bindings/sound/pcm512x.txt | 9 +- + .../devicetree/bindings/spi/spi-gpio.yaml | 4 + + .../devicetree/bindings/usb/snps,dwc3.yaml | 9 +- .../devicetree/bindings/vendor-prefixes.txt | 463 ++ - .../devicetree/bindings/vendor-prefixes.yaml | 4 + + .../devicetree/bindings/vendor-prefixes.yaml | 6 + .../devicetree/configfs-overlays.txt | 31 + - Documentation/hwmon/rpi-poe-fan | 15 + + Documentation/driver-api/pwm.rst | 17 +- .../userspace-api/media/drivers/index.rst | 1 + - .../media/v4l/ext-ctrls-codec.rst | 46 +- - .../media/v4l/ext-ctrls-image-source.rst | 20 + .../userspace-api/media/v4l/meta-formats.rst | 2 + - .../media/v4l/pixfmt-compressed.rst | 1 + .../v4l/pixfmt-meta-bcm2835-isp-stats.rst | 41 + .../media/v4l/pixfmt-meta-sensor-data.rst | 32 + .../media/v4l/pixfmt-nv12-col128.rst | 215 + - .../userspace-api/media/v4l/pixfmt-nv12.rst | 14 +- .../userspace-api/media/v4l/pixfmt-y12p.rst | 45 + .../userspace-api/media/v4l/pixfmt-y14p.rst | 54 + - .../media/v4l/subdev-formats.rst | 144 + - .../userspace-api/media/v4l/yuv-formats.rst | 3 + - MAINTAINERS | 48 + - Makefile | 3 + - arch/arm/boot/dts/Makefile | 31 +- - arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 131 + - arch/arm/boot/dts/bcm2708-rpi-b-rev1.dts | 134 + - arch/arm/boot/dts/bcm2708-rpi-b.dts | 121 + - arch/arm/boot/dts/bcm2708-rpi-bt.dtsi | 26 + - arch/arm/boot/dts/bcm2708-rpi-cm.dts | 106 + - arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 22 + - arch/arm/boot/dts/bcm2708-rpi-zero-w.dts | 178 + - arch/arm/boot/dts/bcm2708-rpi-zero.dts | 125 + - arch/arm/boot/dts/bcm2708-rpi.dtsi | 36 + - arch/arm/boot/dts/bcm2708.dtsi | 12 + - arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 131 + - arch/arm/boot/dts/bcm2709-rpi.dtsi | 5 + - arch/arm/boot/dts/bcm2709.dtsi | 22 + - arch/arm/boot/dts/bcm270x-rpi.dtsi | 155 + - arch/arm/boot/dts/bcm270x.dtsi | 272 + - arch/arm/boot/dts/bcm2710-rpi-2-b.dts | 131 + - arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts | 210 + - arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 212 + - arch/arm/boot/dts/bcm2710-rpi-cm3.dts | 146 + - arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts | 199 + - arch/arm/boot/dts/bcm2710-rpi-zero-2.dts | 1 + - arch/arm/boot/dts/bcm2710.dtsi | 25 + - arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 330 +- - arch/arm/boot/dts/bcm2711-rpi-400.dts | 637 ++ - arch/arm/boot/dts/bcm2711-rpi-cm4.dts | 652 ++ - arch/arm/boot/dts/bcm2711-rpi-cm4s.dts | 467 ++ - arch/arm/boot/dts/bcm2711-rpi.dtsi | 205 + - arch/arm/boot/dts/bcm2711.dtsi | 72 +- - arch/arm/boot/dts/bcm271x-rpi-bt.dtsi | 26 + - arch/arm/boot/dts/bcm2835-common.dtsi | 14 +- - arch/arm/boot/dts/bcm2835-rpi-a-plus.dts | 5 + - arch/arm/boot/dts/bcm2835-rpi-a.dts | 7 + - arch/arm/boot/dts/bcm2835-rpi-b-plus.dts | 5 + - arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts | 7 + - arch/arm/boot/dts/bcm2835-rpi-b.dts | 7 + - arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts | 5 + - arch/arm/boot/dts/bcm2835-rpi-zero-w.dts | 5 + - arch/arm/boot/dts/bcm2835-rpi-zero.dts | 5 + - arch/arm/boot/dts/bcm2835-rpi.dtsi | 19 +- - arch/arm/boot/dts/bcm2835.dtsi | 2 +- - arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 5 + - arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts | 5 + - arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts | 5 + - arch/arm/boot/dts/bcm2837-rpi-3-b.dts | 5 + - arch/arm/boot/dts/bcm2837-rpi-cm3-io3.dts | 5 + - arch/arm/boot/dts/bcm283x-rpi-csi0-2lane.dtsi | 4 + - arch/arm/boot/dts/bcm283x-rpi-csi1-2lane.dtsi | 4 + - arch/arm/boot/dts/bcm283x-rpi-csi1-4lane.dtsi | 4 + - .../boot/dts/bcm283x-rpi-i2c0mux_0_28.dtsi | 4 + - .../boot/dts/bcm283x-rpi-i2c0mux_0_44.dtsi | 4 + - .../boot/dts/bcm283x-rpi-usb-peripheral.dtsi | 7 - - arch/arm/boot/dts/bcm283x.dtsi | 34 +- - arch/arm/boot/dts/overlays/Makefile | 257 + - arch/arm/boot/dts/overlays/README | 3861 +++++++++ - .../arm/boot/dts/overlays/act-led-overlay.dts | 27 + + .../media/v4l/pixfmt-yuv-planar.rst | 12 + + .../media/v4l/subdev-formats.rst | 143 + + .../userspace-api/media/v4l/yuv-formats.rst | 21 + + MAINTAINERS | 83 +- + README.md | 30 + + arch/arm/boot/dts/Makefile | 5 + + arch/arm/boot/dts/broadcom/Makefile | 35 + + .../boot/dts/broadcom/bcm2708-rpi-b-plus.dts | 210 + + .../boot/dts/broadcom/bcm2708-rpi-b-rev1.dts | 223 + + arch/arm/boot/dts/broadcom/bcm2708-rpi-b.dts | 198 + + .../arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi | 38 + + arch/arm/boot/dts/broadcom/bcm2708-rpi-cm.dts | 174 + + .../arm/boot/dts/broadcom/bcm2708-rpi-cm.dtsi | 27 + + .../boot/dts/broadcom/bcm2708-rpi-zero-w.dts | 254 + + .../boot/dts/broadcom/bcm2708-rpi-zero.dts | 189 + + arch/arm/boot/dts/broadcom/bcm2708-rpi.dtsi | 57 + + arch/arm/boot/dts/broadcom/bcm2708.dtsi | 19 + + .../arm/boot/dts/broadcom/bcm2709-rpi-2-b.dts | 204 + + .../arm/boot/dts/broadcom/bcm2709-rpi-cm2.dts | 223 + + arch/arm/boot/dts/broadcom/bcm2709-rpi.dtsi | 8 + + arch/arm/boot/dts/broadcom/bcm2709.dtsi | 29 + + arch/arm/boot/dts/broadcom/bcm270x-rpi.dtsi | 186 + + arch/arm/boot/dts/broadcom/bcm270x.dtsi | 294 + + .../arm/boot/dts/broadcom/bcm2710-rpi-2-b.dts | 204 + + .../dts/broadcom/bcm2710-rpi-3-b-plus.dts | 299 + + .../arm/boot/dts/broadcom/bcm2710-rpi-3-b.dts | 297 + + .../arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts | 223 + + .../dts/broadcom/bcm2710-rpi-zero-2-w.dts | 261 + + .../boot/dts/broadcom/bcm2710-rpi-zero-2.dts | 1 + + arch/arm/boot/dts/broadcom/bcm2710.dtsi | 32 + + .../arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts | 262 +- + .../arm/boot/dts/broadcom/bcm2711-rpi-400.dts | 49 +- + .../arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts | 510 ++ + .../boot/dts/broadcom/bcm2711-rpi-cm4s.dts | 297 + + .../arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi | 561 ++ + arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi | 13 + + arch/arm/boot/dts/broadcom/bcm2711.dtsi | 2 +- + .../arm/boot/dts/broadcom/bcm2712-rpi-5-b.dts | 863 ++ + .../dts/broadcom/bcm2712-rpi-cm5-cm4io.dts | 20 + + .../dts/broadcom/bcm2712-rpi-cm5-cm5io.dts | 10 + + .../boot/dts/broadcom/bcm2712-rpi-cm5.dtsi | 860 ++ + arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi | 336 + + arch/arm/boot/dts/broadcom/bcm2712.dtsi | 1304 +++ + .../boot/dts/broadcom/bcm2712d0-rpi-5-b.dts | 107 + + .../arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi | 38 + + .../dts/broadcom/bcm283x-rpi-csi0-2lane.dtsi | 4 + + .../dts/broadcom/bcm283x-rpi-csi1-2lane.dtsi | 4 + + .../dts/broadcom/bcm283x-rpi-csi1-4lane.dtsi | 4 + + .../broadcom/bcm283x-rpi-i2c0mux_0_28.dtsi | 4 + + .../broadcom/bcm283x-rpi-i2c0mux_0_44.dtsi | 4 + + arch/arm/boot/dts/broadcom/bcm283x.dtsi | 2 +- + arch/arm/boot/dts/broadcom/rp1.dtsi | 1306 +++ + arch/arm/boot/dts/overlays/Makefile | 333 + + arch/arm/boot/dts/overlays/README | 5346 ++++++++++++ + .../arm/boot/dts/overlays/act-led-overlay.dts | 28 + .../dts/overlays/adafruit-st7735r-overlay.dts | 83 + .../boot/dts/overlays/adafruit18-overlay.dts | 55 + .../dts/overlays/adau1977-adc-overlay.dts | 40 + .../dts/overlays/adau7002-simple-overlay.dts | 52 + .../arm/boot/dts/overlays/ads1015-overlay.dts | 98 + - .../arm/boot/dts/overlays/ads1115-overlay.dts | 103 + + .../arm/boot/dts/overlays/ads1115-overlay.dts | 135 + .../arm/boot/dts/overlays/ads7846-overlay.dts | 89 + .../boot/dts/overlays/adv7282m-overlay.dts | 73 + .../boot/dts/overlays/adv728x-m-overlay.dts | 37 + .../overlays/akkordion-iqdacplus-overlay.dts | 49 + - .../allo-boss-dac-pcm512x-audio-overlay.dts | 59 + + .../allo-boss-dac-pcm512x-audio-overlay.dts | 61 + .../overlays/allo-boss2-dac-audio-overlay.dts | 57 + .../dts/overlays/allo-digione-overlay.dts | 44 + - .../allo-katana-dac-audio-overlay.dts | 57 + + .../allo-katana-dac-audio-overlay.dts | 58 + .../allo-piano-dac-pcm512x-audio-overlay.dts | 54 + ...o-piano-dac-plus-pcm512x-audio-overlay.dts | 57 + arch/arm/boot/dts/overlays/anyspi-overlay.dts | 205 + - .../boot/dts/overlays/apds9960-overlay.dts | 57 + + .../boot/dts/overlays/apds9960-overlay.dts | 55 + .../boot/dts/overlays/applepi-dac-overlay.dts | 57 + + .../dts/overlays/arducam-64mp-overlay.dts | 91 + + arch/arm/boot/dts/overlays/arducam-64mp.dtsi | 34 + + .../overlays/arducam-pivariety-overlay.dts | 94 + .../boot/dts/overlays/at86rf233-overlay.dts | 57 + .../overlays/audioinjector-addons-overlay.dts | 60 + + .../audioinjector-bare-i2s-overlay.dts | 50 + ...dioinjector-isolated-soundcard-overlay.dts | 55 + .../overlays/audioinjector-ultra-overlay.dts | 71 + .../audioinjector-wm8731-audio-overlay.dts | 39 + .../dts/overlays/audiosense-pi-overlay.dts | 82 + - .../boot/dts/overlays/audremap-overlay.dts | 42 + + .../boot/dts/overlays/audremap-overlay.dts | 38 + .../boot/dts/overlays/balena-fin-overlay.dts | 125 + + .../boot/dts/overlays/bcm2712d0-overlay.dts | 75 + + .../dts/overlays/camera-mux-2port-overlay.dts | 545 ++ + .../dts/overlays/camera-mux-4port-overlay.dts | 952 +++ .../arm/boot/dts/overlays/cap1106-overlay.dts | 52 + .../boot/dts/overlays/chipdip-dac-overlay.dts | 46 + + .../dts/overlays/cirrus-wm5102-overlay.dts | 172 + + .../dts/overlays/cm-swap-i2c0-overlay.dts | 27 + arch/arm/boot/dts/overlays/cma-overlay.dts | 36 + + .../crystalfontz-cfa050_pi_m-overlay.dts | 124 + .../dts/overlays/cutiepi-panel-overlay.dts | 117 + - arch/arm/boot/dts/overlays/dht11-overlay.dts | 41 + + .../boot/dts/overlays/dacberry400-overlay.dts | 71 + + arch/arm/boot/dts/overlays/dht11-overlay.dts | 48 + + .../dts/overlays/dionaudio-kiwi-overlay.dts | 39 + .../dts/overlays/dionaudio-loco-overlay.dts | 39 + .../overlays/dionaudio-loco-v2-overlay.dts | 49 + - .../boot/dts/overlays/disable-bt-overlay.dts | 64 + + .../boot/dts/overlays/disable-bt-overlay.dts | 59 + + .../dts/overlays/disable-bt-pi5-overlay.dts | 17 + + .../dts/overlays/disable-emmc2-overlay.dts | 13 + .../dts/overlays/disable-wifi-overlay.dts | 20 + + .../dts/overlays/disable-wifi-pi5-overlay.dts | 13 + arch/arm/boot/dts/overlays/dpi18-overlay.dts | 39 + .../boot/dts/overlays/dpi18cpadhi-overlay.dts | 26 + arch/arm/boot/dts/overlays/dpi24-overlay.dts | 39 + arch/arm/boot/dts/overlays/draws-overlay.dts | 208 + .../arm/boot/dts/overlays/dwc-otg-overlay.dts | 14 + arch/arm/boot/dts/overlays/dwc2-overlay.dts | 26 + - .../boot/dts/overlays/edt-ft5406-overlay.dts | 26 + - arch/arm/boot/dts/overlays/edt-ft5406.dtsi | 47 + + .../boot/dts/overlays/edt-ft5406-overlay.dts | 46 + + arch/arm/boot/dts/overlays/edt-ft5406.dtsi | 49 + .../boot/dts/overlays/enc28j60-overlay.dts | 53 + .../dts/overlays/enc28j60-spi2-overlay.dts | 47 + .../arm/boot/dts/overlays/exc3000-overlay.dts | 48 + arch/arm/boot/dts/overlays/fbtft-overlay.dts | 611 ++ .../boot/dts/overlays/fe-pi-audio-overlay.dts | 70 + .../boot/dts/overlays/fsm-demo-overlay.dts | 104 + + arch/arm/boot/dts/overlays/gc9a01-overlay.dts | 151 + .../boot/dts/overlays/ghost-amp-overlay.dts | 145 + arch/arm/boot/dts/overlays/goodix-overlay.dts | 46 + .../googlevoicehat-soundcard-overlay.dts | 49 + - .../boot/dts/overlays/gpio-fan-overlay.dts | 79 + + .../dts/overlays/gpio-charger-overlay.dts | 42 + + .../boot/dts/overlays/gpio-fan-overlay.dts | 89 + + .../boot/dts/overlays/gpio-hog-overlay.dts | 27 + .../arm/boot/dts/overlays/gpio-ir-overlay.dts | 49 + .../boot/dts/overlays/gpio-ir-tx-overlay.dts | 36 + .../boot/dts/overlays/gpio-key-overlay.dts | 48 + @@ -165,16 +190,22 @@ .../boot/dts/overlays/gpio-no-irq-overlay.dts | 14 + .../dts/overlays/gpio-poweroff-overlay.dts | 39 + .../dts/overlays/gpio-shutdown-overlay.dts | 86 + + arch/arm/boot/dts/overlays/hat_map.dts | 98 + .../boot/dts/overlays/hd44780-lcd-overlay.dts | 46 + .../hdmi-backlight-hwhack-gpio-overlay.dts | 47 + .../dts/overlays/hifiberry-amp-overlay.dts | 39 + - .../dts/overlays/hifiberry-amp100-overlay.dts | 64 + + .../dts/overlays/hifiberry-amp100-overlay.dts | 67 + + .../dts/overlays/hifiberry-amp3-overlay.dts | 57 + + .../overlays/hifiberry-amp4pro-overlay.dts | 63 + .../dts/overlays/hifiberry-dac-overlay.dts | 34 + - .../overlays/hifiberry-dacplus-overlay.dts | 65 + + .../dts/overlays/hifiberry-dac8x-overlay.dts | 50 + + .../overlays/hifiberry-dacplus-overlay.dts | 68 + + .../hifiberry-dacplus-pro-overlay.dts | 64 + + .../hifiberry-dacplus-std-overlay.dts | 65 + .../overlays/hifiberry-dacplusadc-overlay.dts | 72 + - .../hifiberry-dacplusadcpro-overlay.dts | 70 + + .../hifiberry-dacplusadcpro-overlay.dts | 72 + .../overlays/hifiberry-dacplusdsp-overlay.dts | 34 + - .../overlays/hifiberry-dacplushd-overlay.dts | 106 + + .../overlays/hifiberry-dacplushd-overlay.dts | 94 + .../dts/overlays/hifiberry-digi-overlay.dts | 41 + .../overlays/hifiberry-digi-pro-overlay.dts | 43 + .../boot/dts/overlays/highperi-overlay.dts | 63 + @@ -183,34 +214,55 @@ arch/arm/boot/dts/overlays/hy28b-overlay.dts | 148 + .../boot/dts/overlays/i-sabre-q2m-overlay.dts | 39 + .../boot/dts/overlays/i2c-bcm2708-overlay.dts | 13 + + .../arm/boot/dts/overlays/i2c-fan-overlay.dts | 108 + .../boot/dts/overlays/i2c-gpio-overlay.dts | 47 + - .../arm/boot/dts/overlays/i2c-mux-overlay.dts | 139 + - .../dts/overlays/i2c-pwm-pca9685a-overlay.dts | 26 + - .../arm/boot/dts/overlays/i2c-rtc-common.dtsi | 323 + + .../arm/boot/dts/overlays/i2c-mux-overlay.dts | 183 + + .../dts/overlays/i2c-pwm-pca9685a-overlay.dts | 61 + + .../arm/boot/dts/overlays/i2c-rtc-common.dtsi | 367 + .../dts/overlays/i2c-rtc-gpio-overlay.dts | 31 + - .../arm/boot/dts/overlays/i2c-rtc-overlay.dts | 34 + - .../boot/dts/overlays/i2c-sensor-overlay.dts | 340 + + .../arm/boot/dts/overlays/i2c-rtc-overlay.dts | 42 + + .../boot/dts/overlays/i2c-sensor-common.dtsi | 578 ++ + .../boot/dts/overlays/i2c-sensor-overlay.dts | 42 + arch/arm/boot/dts/overlays/i2c0-overlay.dts | 83 + + .../boot/dts/overlays/i2c0-pi5-overlay.dts | 34 + arch/arm/boot/dts/overlays/i2c1-overlay.dts | 44 + - arch/arm/boot/dts/overlays/i2c3-overlay.dts | 36 + - arch/arm/boot/dts/overlays/i2c4-overlay.dts | 36 + - arch/arm/boot/dts/overlays/i2c5-overlay.dts | 36 + - arch/arm/boot/dts/overlays/i2c6-overlay.dts | 36 + + .../boot/dts/overlays/i2c1-pi5-overlay.dts | 34 + + .../boot/dts/overlays/i2c2-pi5-overlay.dts | 21 + + arch/arm/boot/dts/overlays/i2c3-overlay.dts | 34 + + .../boot/dts/overlays/i2c3-pi5-overlay.dts | 22 + + arch/arm/boot/dts/overlays/i2c4-overlay.dts | 34 + + arch/arm/boot/dts/overlays/i2c5-overlay.dts | 34 + + arch/arm/boot/dts/overlays/i2c6-overlay.dts | 34 + + .../arm/boot/dts/overlays/i2s-dac-overlay.dts | 34 + .../dts/overlays/i2s-gpio28-31-overlay.dts | 18 + .../boot/dts/overlays/ilitek251x-overlay.dts | 45 + - arch/arm/boot/dts/overlays/imx219-overlay.dts | 96 + + arch/arm/boot/dts/overlays/imx219-overlay.dts | 89 + + arch/arm/boot/dts/overlays/imx219.dtsi | 27 + + arch/arm/boot/dts/overlays/imx258-overlay.dts | 131 + + arch/arm/boot/dts/overlays/imx258.dtsi | 27 + arch/arm/boot/dts/overlays/imx290-overlay.dts | 32 + - .../boot/dts/overlays/imx290_327-overlay.dtsi | 125 + - arch/arm/boot/dts/overlays/imx378-overlay.dts | 10 + - arch/arm/boot/dts/overlays/imx477-overlay.dts | 10 + - .../boot/dts/overlays/imx477_378-overlay.dtsi | 99 + - arch/arm/boot/dts/overlays/imx519-overlay.dts | 96 + + .../boot/dts/overlays/imx290_327-overlay.dtsi | 112 + + arch/arm/boot/dts/overlays/imx290_327.dtsi | 24 + + arch/arm/boot/dts/overlays/imx296-overlay.dts | 114 + + arch/arm/boot/dts/overlays/imx327-overlay.dts | 33 + + arch/arm/boot/dts/overlays/imx378-overlay.dts | 17 + + arch/arm/boot/dts/overlays/imx462-overlay.dts | 39 + + arch/arm/boot/dts/overlays/imx477-overlay.dts | 17 + + .../boot/dts/overlays/imx477_378-overlay.dtsi | 92 + + arch/arm/boot/dts/overlays/imx477_378.dtsi | 24 + + arch/arm/boot/dts/overlays/imx519-overlay.dts | 93 + + arch/arm/boot/dts/overlays/imx519.dtsi | 34 + + arch/arm/boot/dts/overlays/imx708-overlay.dts | 105 + + arch/arm/boot/dts/overlays/imx708.dtsi | 35 + + .../interludeaudio-analog-overlay.dts | 73 + + .../interludeaudio-digital-overlay.dts | 49 + .../dts/overlays/iqaudio-codec-overlay.dts | 42 + .../boot/dts/overlays/iqaudio-dac-overlay.dts | 46 + .../dts/overlays/iqaudio-dacplus-overlay.dts | 49 + .../iqaudio-digi-wm8804-audio-overlay.dts | 47 + + arch/arm/boot/dts/overlays/iqs550-overlay.dts | 59 + .../arm/boot/dts/overlays/irs1125-overlay.dts | 90 + - .../dts/overlays/jedec-spi-nor-overlay.dts | 309 + + .../dts/overlays/jedec-spi-nor-overlay.dts | 136 + .../dts/overlays/justboom-both-overlay.dts | 65 + .../dts/overlays/justboom-dac-overlay.dts | 46 + .../dts/overlays/justboom-digi-overlay.dts | 41 + @@ -218,7 +270,7 @@ .../boot/dts/overlays/max98357a-overlay.dts | 84 + .../boot/dts/overlays/maxtherm-overlay.dts | 186 + .../boot/dts/overlays/mbed-dac-overlay.dts | 64 + - .../boot/dts/overlays/mcp23017-overlay.dts | 69 + + .../boot/dts/overlays/mcp23017-overlay.dts | 103 + .../boot/dts/overlays/mcp23s17-overlay.dts | 732 ++ .../dts/overlays/mcp2515-can0-overlay.dts | 73 + .../dts/overlays/mcp2515-can1-overlay.dts | 73 + @@ -227,27 +279,41 @@ .../arm/boot/dts/overlays/mcp3008-overlay.dts | 205 + .../arm/boot/dts/overlays/mcp3202-overlay.dts | 205 + .../arm/boot/dts/overlays/mcp342x-overlay.dts | 164 + - .../dts/overlays/media-center-overlay.dts | 134 + - .../boot/dts/overlays/merus-amp-overlay.dts | 60 + + .../dts/overlays/media-center-overlay.dts | 86 + + .../boot/dts/overlays/merus-amp-overlay.dts | 59 + .../boot/dts/overlays/midi-uart0-overlay.dts | 36 + + .../dts/overlays/midi-uart0-pi5-overlay.dts | 35 + .../boot/dts/overlays/midi-uart1-overlay.dts | 43 + + .../dts/overlays/midi-uart1-pi5-overlay.dts | 35 + .../boot/dts/overlays/midi-uart2-overlay.dts | 37 + + .../dts/overlays/midi-uart2-pi5-overlay.dts | 35 + .../boot/dts/overlays/midi-uart3-overlay.dts | 38 + + .../dts/overlays/midi-uart3-pi5-overlay.dts | 35 + .../boot/dts/overlays/midi-uart4-overlay.dts | 38 + + .../dts/overlays/midi-uart4-pi5-overlay.dts | 35 + .../boot/dts/overlays/midi-uart5-overlay.dts | 38 + .../boot/dts/overlays/minipitft13-overlay.dts | 70 + - .../boot/dts/overlays/miniuart-bt-overlay.dts | 93 + + .../boot/dts/overlays/miniuart-bt-overlay.dts | 83 + + .../dts/overlays/mipi-dbi-spi-overlay.dts | 175 + .../boot/dts/overlays/mlx90640-overlay.dts | 22 + arch/arm/boot/dts/overlays/mmc-overlay.dts | 46 + - .../arm/boot/dts/overlays/mpu6050-overlay.dts | 29 + .../arm/boot/dts/overlays/mz61581-overlay.dts | 117 + - arch/arm/boot/dts/overlays/ov5647-overlay.dts | 99 + - arch/arm/boot/dts/overlays/ov7251-overlay.dts | 94 + - arch/arm/boot/dts/overlays/ov9281-overlay.dts | 95 + - arch/arm/boot/dts/overlays/overlay_map.dts | 166 + - .../arm/boot/dts/overlays/papirus-overlay.dts | 89 + + arch/arm/boot/dts/overlays/ov2311-overlay.dts | 77 + + arch/arm/boot/dts/overlays/ov2311.dtsi | 26 + + arch/arm/boot/dts/overlays/ov5647-overlay.dts | 93 + + arch/arm/boot/dts/overlays/ov5647.dtsi | 25 + + .../arm/boot/dts/overlays/ov64a40-overlay.dts | 91 + + arch/arm/boot/dts/overlays/ov64a40.dtsi | 34 + + arch/arm/boot/dts/overlays/ov7251-overlay.dts | 77 + + arch/arm/boot/dts/overlays/ov7251.dtsi | 28 + + arch/arm/boot/dts/overlays/ov9281-overlay.dts | 78 + + arch/arm/boot/dts/overlays/ov9281.dtsi | 27 + + arch/arm/boot/dts/overlays/overlay_map.dts | 493 ++ + .../arm/boot/dts/overlays/papirus-overlay.dts | 84 + .../arm/boot/dts/overlays/pca953x-overlay.dts | 240 + + .../arm/boot/dts/overlays/pcf857x-overlay.dts | 32 + .../dts/overlays/pcie-32bit-dma-overlay.dts | 38 + + .../overlays/pcie-32bit-dma-pi5-overlay.dts | 26 + arch/arm/boot/dts/overlays/pibell-overlay.dts | 81 + .../dts/overlays/pifacedigital-overlay.dts | 144 + .../arm/boot/dts/overlays/pifi-40-overlay.dts | 50 + @@ -255,31 +321,36 @@ .../dts/overlays/pifi-dac-zero-overlay.dts | 49 + .../dts/overlays/pifi-mini-210-overlay.dts | 42 + arch/arm/boot/dts/overlays/piglow-overlay.dts | 97 + - .../boot/dts/overlays/piscreen-overlay.dts | 102 + + .../boot/dts/overlays/piscreen-overlay.dts | 107 + .../boot/dts/overlays/piscreen2r-overlay.dts | 106 + - .../arm/boot/dts/overlays/pisound-overlay.dts | 120 + - .../arm/boot/dts/overlays/pitft22-overlay.dts | 69 + - .../overlays/pitft28-capacitive-overlay.dts | 91 + - .../overlays/pitft28-resistive-overlay.dts | 119 + - .../overlays/pitft35-resistive-overlay.dts | 119 + - .../boot/dts/overlays/pps-gpio-overlay.dts | 38 + - .../boot/dts/overlays/pwm-2chan-overlay.dts | 49 + + .../arm/boot/dts/overlays/pisound-overlay.dts | 118 + + .../boot/dts/overlays/pisound-pi5-overlay.dts | 31 + + .../arm/boot/dts/overlays/pitft22-overlay.dts | 71 + + .../overlays/pitft28-capacitive-overlay.dts | 93 + + .../overlays/pitft28-resistive-overlay.dts | 126 + + .../overlays/pitft35-resistive-overlay.dts | 127 + + .../boot/dts/overlays/pps-gpio-overlay.dts | 39 + + .../boot/dts/overlays/proto-codec-overlay.dts | 39 + + .../boot/dts/overlays/pwm-2chan-overlay.dts | 48 + .../boot/dts/overlays/pwm-ir-tx-overlay.dts | 40 + - arch/arm/boot/dts/overlays/pwm-overlay.dts | 45 + + arch/arm/boot/dts/overlays/pwm-overlay.dts | 44 + + arch/arm/boot/dts/overlays/pwm1-overlay.dts | 59 + .../arm/boot/dts/overlays/qca7000-overlay.dts | 55 + .../dts/overlays/qca7000-uart0-overlay.dts | 46 + + .../arm/boot/dts/overlays/ramoops-overlay.dts | 25 + + .../boot/dts/overlays/ramoops-pi4-overlay.dts | 25 + .../dts/overlays/rotary-encoder-overlay.dts | 59 + .../dts/overlays/rpi-backlight-overlay.dts | 21 + - .../overlays/rpi-cirrus-wm5102-overlay.dts | 172 + - .../arm/boot/dts/overlays/rpi-dac-overlay.dts | 34 + - .../boot/dts/overlays/rpi-display-overlay.dts | 91 + + .../dts/overlays/rpi-codeczero-overlay.dts | 9 + + .../boot/dts/overlays/rpi-dacplus-overlay.dts | 17 + + .../boot/dts/overlays/rpi-dacpro-overlay.dts | 17 + + .../dts/overlays/rpi-digiampplus-overlay.dts | 17 + .../boot/dts/overlays/rpi-ft5406-overlay.dts | 25 + - .../arm/boot/dts/overlays/rpi-poe-overlay.dts | 95 + - .../dts/overlays/rpi-poe-plus-overlay.dts | 23 + - .../boot/dts/overlays/rpi-proto-overlay.dts | 39 + + .../arm/boot/dts/overlays/rpi-poe-overlay.dts | 154 + + .../dts/overlays/rpi-poe-plus-overlay.dts | 49 + .../boot/dts/overlays/rpi-sense-overlay.dts | 47 + + .../dts/overlays/rpi-sense-v2-overlay.dts | 47 + arch/arm/boot/dts/overlays/rpi-tv-overlay.dts | 34 + - .../boot/dts/overlays/rpivid-v4l2-overlay.dts | 50 + .../rra-digidac1-wm8741-audio-overlay.dts | 49 + .../boot/dts/overlays/sainsmart18-overlay.dts | 52 + .../dts/overlays/sc16is750-i2c-overlay.dts | 43 + @@ -288,6 +359,7 @@ .../dts/overlays/sc16is752-spi1-overlay.dts | 67 + arch/arm/boot/dts/overlays/sdhost-overlay.dts | 38 + arch/arm/boot/dts/overlays/sdio-overlay.dts | 77 + + .../boot/dts/overlays/sdio-pi5-overlay.dts | 24 + .../overlays/seeed-can-fd-hat-v1-overlay.dts | 138 + .../overlays/seeed-can-fd-hat-v2-overlay.dts | 117 + .../boot/dts/overlays/sh1106-spi-overlay.dts | 84 + @@ -305,18 +377,24 @@ .../boot/dts/overlays/spi1-2cs-overlay.dts | 69 + .../boot/dts/overlays/spi1-3cs-overlay.dts | 81 + .../boot/dts/overlays/spi2-1cs-overlay.dts | 57 + + .../dts/overlays/spi2-1cs-pi5-overlay.dts | 33 + .../boot/dts/overlays/spi2-2cs-overlay.dts | 69 + + .../dts/overlays/spi2-2cs-pi5-overlay.dts | 44 + .../boot/dts/overlays/spi2-3cs-overlay.dts | 81 + - .../boot/dts/overlays/spi3-1cs-overlay.dts | 44 + - .../boot/dts/overlays/spi3-2cs-overlay.dts | 56 + - .../boot/dts/overlays/spi4-1cs-overlay.dts | 44 + - .../boot/dts/overlays/spi4-2cs-overlay.dts | 56 + - .../boot/dts/overlays/spi5-1cs-overlay.dts | 44 + - .../boot/dts/overlays/spi5-2cs-overlay.dts | 56 + - .../boot/dts/overlays/spi6-1cs-overlay.dts | 44 + - .../boot/dts/overlays/spi6-2cs-overlay.dts | 56 + + .../boot/dts/overlays/spi3-1cs-overlay.dts | 42 + + .../dts/overlays/spi3-1cs-pi5-overlay.dts | 33 + + .../boot/dts/overlays/spi3-2cs-overlay.dts | 54 + + .../dts/overlays/spi3-2cs-pi5-overlay.dts | 44 + + .../boot/dts/overlays/spi4-1cs-overlay.dts | 42 + + .../boot/dts/overlays/spi4-2cs-overlay.dts | 54 + + .../boot/dts/overlays/spi5-1cs-overlay.dts | 42 + + .../dts/overlays/spi5-1cs-pi5-overlay.dts | 33 + + .../boot/dts/overlays/spi5-2cs-overlay.dts | 54 + + .../dts/overlays/spi5-2cs-pi5-overlay.dts | 44 + + .../boot/dts/overlays/spi6-1cs-overlay.dts | 42 + + .../boot/dts/overlays/spi6-2cs-overlay.dts | 54 + .../arm/boot/dts/overlays/ssd1306-overlay.dts | 36 + - .../boot/dts/overlays/ssd1306-spi-overlay.dts | 84 + + .../boot/dts/overlays/ssd1306-spi-overlay.dts | 85 + .../boot/dts/overlays/ssd1331-spi-overlay.dts | 83 + .../boot/dts/overlays/ssd1351-spi-overlay.dts | 83 + .../dts/overlays/superaudioboard-overlay.dts | 73 + @@ -325,39 +403,58 @@ .../boot/dts/overlays/tc358743-overlay.dts | 109 + .../boot/dts/overlays/tinylcd35-overlay.dts | 222 + .../boot/dts/overlays/tpm-slb9670-overlay.dts | 44 + + .../boot/dts/overlays/tpm-slb9673-overlay.dts | 50 + arch/arm/boot/dts/overlays/uart0-overlay.dts | 32 + + .../boot/dts/overlays/uart0-pi5-overlay.dts | 18 + arch/arm/boot/dts/overlays/uart1-overlay.dts | 38 + - arch/arm/boot/dts/overlays/uart2-overlay.dts | 27 + - arch/arm/boot/dts/overlays/uart3-overlay.dts | 27 + - arch/arm/boot/dts/overlays/uart4-overlay.dts | 27 + - arch/arm/boot/dts/overlays/uart5-overlay.dts | 27 + + .../boot/dts/overlays/uart1-pi5-overlay.dts | 18 + + arch/arm/boot/dts/overlays/uart2-overlay.dts | 25 + + .../boot/dts/overlays/uart2-pi5-overlay.dts | 18 + + arch/arm/boot/dts/overlays/uart3-overlay.dts | 25 + + .../boot/dts/overlays/uart3-pi5-overlay.dts | 18 + + arch/arm/boot/dts/overlays/uart4-overlay.dts | 25 + + .../boot/dts/overlays/uart4-pi5-overlay.dts | 18 + + arch/arm/boot/dts/overlays/uart5-overlay.dts | 25 + arch/arm/boot/dts/overlays/udrc-overlay.dts | 128 + .../dts/overlays/ugreen-dabboard-overlay.dts | 49 + .../boot/dts/overlays/upstream-overlay.dts | 101 + .../dts/overlays/upstream-pi4-overlay.dts | 137 + - .../dts/overlays/vc4-fkms-v3d-overlay.dts | 40 + - .../dts/overlays/vc4-fkms-v3d-pi4-overlay.dts | 44 + - .../overlays/vc4-kms-dpi-generic-overlay.dts | 74 + + .../dts/overlays/vc4-fkms-v3d-overlay.dts | 46 + + .../dts/overlays/vc4-fkms-v3d-pi4-overlay.dts | 50 + + .../overlays/vc4-kms-dpi-generic-overlay.dts | 81 + + .../dts/overlays/vc4-kms-dpi-hyperpixel.dtsi | 94 + + .../vc4-kms-dpi-hyperpixel2r-overlay.dts | 114 + + .../vc4-kms-dpi-hyperpixel4-overlay.dts | 57 + + .../vc4-kms-dpi-hyperpixel4sq-overlay.dts | 36 + .../overlays/vc4-kms-dpi-panel-overlay.dts | 69 + arch/arm/boot/dts/overlays/vc4-kms-dpi.dtsi | 111 + - .../overlays/vc4-kms-dsi-7inch-overlay.dts | 118 + + .../overlays/vc4-kms-dsi-7inch-overlay.dts | 124 + + .../overlays/vc4-kms-dsi-generic-overlay.dts | 106 + + .../vc4-kms-dsi-ili9881-5inch-overlay.dts | 122 + + .../vc4-kms-dsi-ili9881-7inch-overlay.dts | 122 + .../vc4-kms-dsi-lt070me05000-overlay.dts | 69 + .../vc4-kms-dsi-lt070me05000-v2-overlay.dts | 64 + + .../vc4-kms-dsi-waveshare-panel-overlay.dts | 126 + .../overlays/vc4-kms-kippah-7inch-overlay.dts | 26 + - .../boot/dts/overlays/vc4-kms-v3d-overlay.dts | 123 + - .../dts/overlays/vc4-kms-v3d-pi4-overlay.dts | 197 + - .../dts/overlays/vc4-kms-vga666-overlay.dts | 100 + + .../boot/dts/overlays/vc4-kms-v3d-overlay.dts | 124 + + .../dts/overlays/vc4-kms-v3d-pi4-overlay.dts | 200 + + .../dts/overlays/vc4-kms-v3d-pi5-overlay.dts | 147 + + .../dts/overlays/vc4-kms-vga666-overlay.dts | 107 + arch/arm/boot/dts/overlays/vga666-overlay.dts | 30 + arch/arm/boot/dts/overlays/vl805-overlay.dts | 18 + .../arm/boot/dts/overlays/w1-gpio-overlay.dts | 40 + + .../boot/dts/overlays/w1-gpio-pi5-overlay.dts | 15 + .../dts/overlays/w1-gpio-pullup-overlay.dts | 42 + + .../overlays/w1-gpio-pullup-pi5-overlay.dts | 15 + arch/arm/boot/dts/overlays/w5500-overlay.dts | 63 + + .../overlays/watterott-display-overlay.dts | 150 + + .../waveshare-can-fd-hat-mode-a-overlay.dts | 140 + + .../waveshare-can-fd-hat-mode-b-overlay.dts | 103 + .../arm/boot/dts/overlays/wittypi-overlay.dts | 44 + .../dts/overlays/wm8960-soundcard-overlay.dts | 82 + - arch/arm/configs/bcm2709_defconfig | 1533 ++++ - arch/arm/configs/bcm2711_defconfig | 1557 ++++ - arch/arm/configs/bcmrpi_defconfig | 1528 ++++ - arch/arm/configs/multi_v7_defconfig | 1 + + arch/arm/configs/bcm2709_defconfig | 1583 ++++ + arch/arm/configs/bcm2711_defconfig | 1610 ++++ + arch/arm/configs/bcmrpi_defconfig | 1576 ++++ arch/arm/include/asm/cacheflush.h | 21 + arch/arm/include/asm/glue-cache.h | 2 + arch/arm/include/asm/irqflags.h | 16 +- @@ -372,12 +469,12 @@ arch/arm/lib/copy_from_user.S | 4 +- arch/arm/lib/exports_rpi.c | 37 + arch/arm/lib/memcmp_rpi.S | 285 + - arch/arm/lib/memcpy_rpi.S | 63 + + arch/arm/lib/memcpy_rpi.S | 65 + arch/arm/lib/memcpymove.h | 488 ++ arch/arm/lib/memmove_rpi.S | 63 + - arch/arm/lib/memset_rpi.S | 130 + - arch/arm/lib/uaccess_with_memcpy.c | 130 +- - arch/arm/mach-bcm/Kconfig | 10 + + arch/arm/lib/memset_rpi.S | 132 + + arch/arm/lib/uaccess_with_memcpy.c | 125 +- + arch/arm/mach-bcm/Kconfig | 26 + arch/arm/mach-bcm/board_bcm2835.c | 109 + arch/arm/mm/cache-v6.S | 4 +- arch/arm/mm/cache-v7.S | 6 +- @@ -385,345 +482,472 @@ arch/arm/mm/proc-syms.c | 3 + arch/arm/mm/proc-v6.S | 15 +- arch/arm/vfp/vfpmodule.c | 25 +- - arch/arm64/Kconfig.platforms | 1 + + arch/arm64/Kconfig | 3 +- arch/arm64/boot/dts/Makefile | 2 + - arch/arm64/boot/dts/broadcom/Makefile | 16 +- + arch/arm64/boot/dts/broadcom/Makefile | 18 + .../boot/dts/broadcom/bcm2710-rpi-2-b.dts | 1 + .../dts/broadcom/bcm2710-rpi-3-b-plus.dts | 1 + .../boot/dts/broadcom/bcm2710-rpi-3-b.dts | 1 + .../boot/dts/broadcom/bcm2710-rpi-cm3.dts | 1 + + .../dts/broadcom/bcm2710-rpi-zero-2-w.dts | 1 + .../boot/dts/broadcom/bcm2710-rpi-zero-2.dts | 1 + - .../boot/dts/broadcom/bcm2711-rpi-4-b.dts | 3 +- - .../boot/dts/broadcom/bcm2711-rpi-400.dts | 1 + .../boot/dts/broadcom/bcm2711-rpi-cm4.dts | 1 + + .../boot/dts/broadcom/bcm2711-rpi-cm4s.dts | 1 + + .../boot/dts/broadcom/bcm2712-rpi-5-b.dts | 2 + + .../dts/broadcom/bcm2712-rpi-cm5-cm4io.dts | 2 + + .../dts/broadcom/bcm2712-rpi-cm5-cm5io.dts | 2 + + .../boot/dts/broadcom/bcm2712d0-rpi-5-b.dts | 2 + .../dts/broadcom/bcm283x-rpi-csi1-2lane.dtsi | 1 + .../dts/broadcom/bcm283x-rpi-lan7515.dtsi | 1 + arch/arm64/boot/dts/overlays | 1 + - arch/arm64/configs/bcm2711_defconfig | 1566 ++++ - arch/arm64/configs/bcmrpi3_defconfig | 1411 ++++ - arch/arm64/configs/defconfig | 1 + - arch/arm64/crypto/aes-cipher-glue.c | 10 + + arch/arm64/configs/bcm2711_defconfig | 1672 ++++ + arch/arm64/configs/bcm2712_defconfig | 1675 ++++ + arch/arm64/configs/bcmrpi3_defconfig | 1560 ++++ + arch/arm64/crypto/aes-cipher-glue.c | 11 + arch/arm64/crypto/aes-glue.c | 4 +- arch/arm64/crypto/aes-neonbs-glue.c | 5 - arch/arm64/kernel/armv8_deprecated.c | 5 + - arch/arm64/kernel/cpuinfo.c | 25 + - drivers/bluetooth/btusb.c | 8 + + arch/arm64/kernel/cpuinfo.c | 23 + + arch/arm64/kernel/process.c | 4 +- + arch/arm64/kernel/setup.c | 4 +- + drivers/bluetooth/btbcm.c | 9 +- drivers/bluetooth/hci_h5.c | 3 +- - drivers/char/Kconfig | 2 + - drivers/char/Makefile | 1 + - drivers/char/broadcom/Kconfig | 49 + - drivers/char/broadcom/Makefile | 5 + - drivers/char/broadcom/bcm2835-gpiomem.c | 258 + + drivers/char/Kconfig | 10 + + drivers/char/Makefile | 2 + + drivers/char/broadcom/Kconfig | 33 + + drivers/char/broadcom/Makefile | 3 + drivers/char/broadcom/bcm2835_smi_dev.c | 409 + - drivers/char/broadcom/rpivid-mem.c | 270 + - drivers/char/broadcom/vc_mem.c | 373 + + drivers/char/broadcom/vc_mem.c | 632 ++ drivers/char/broadcom/vcio.c | 186 + drivers/char/hw_random/Kconfig | 2 +- - drivers/char/hw_random/bcm2835-rng.c | 6 +- - drivers/char/hw_random/iproc-rng200.c | 78 +- - drivers/clk/Kconfig | 6 + - drivers/clk/Makefile | 3 + - drivers/clk/bcm/clk-bcm2835.c | 202 +- - drivers/clk/bcm/clk-raspberrypi.c | 7 +- - drivers/clk/clk-allo-dac.c | 161 + - drivers/clk/clk-hifiberry-dachd.c | 333 + - drivers/clk/clk-hifiberry-dacpro.c | 160 + - drivers/clk/clk.c | 127 + + drivers/char/hw_random/bcm2835-rng.c | 26 +- + drivers/char/hw_random/iproc-rng200.c | 79 +- + drivers/char/random.c | 8 + + drivers/char/raspberrypi-gpiomem.c | 276 + + drivers/char/tpm/tpm_tis_spi_main.c | 4 + + drivers/clk/Kconfig | 19 + + drivers/clk/Makefile | 4 + + drivers/clk/bcm/clk-bcm2835.c | 206 +- + drivers/clk/bcm/clk-raspberrypi.c | 34 +- + drivers/clk/clk-hifiberry-dachd.c | 331 + + drivers/clk/clk-hifiberry-dacpro.c | 181 + + drivers/clk/clk-rp1-sdio.c | 600 ++ + drivers/clk/clk-rp1.c | 2422 ++++++ drivers/dma/Kconfig | 4 + drivers/dma/Makefile | 1 + drivers/dma/bcm2708-dmaengine.c | 281 + - drivers/dma/bcm2835-dma.c | 545 +- + drivers/dma/bcm2835-dma.c | 735 +- + .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 134 +- + drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 1 + + drivers/firmware/psci/psci.c | 9 +- drivers/firmware/raspberrypi.c | 149 +- - drivers/gpio/Kconfig | 23 + + drivers/gpio/Kconfig | 25 +- drivers/gpio/Makefile | 3 + drivers/gpio/gpio-bcm-virt.c | 214 + - drivers/gpio/gpio-fsm.c | 1210 +++ + drivers/gpio/gpio-brcmstb.c | 35 +- + drivers/gpio/gpio-fsm.c | 1212 +++ + drivers/gpio/gpio-mmio.c | 124 +- + drivers/gpio/gpio-pca953x.c | 1 + drivers/gpio/gpio-pwm.c | 144 + drivers/gpio/gpiolib.c | 10 +- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + - .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 42 +- - .../display/amdgpu_dm/amdgpu_dm_mst_types.c | 5 +- - drivers/gpu/drm/arc/arcpgu_crtc.c | 4 +- - .../gpu/drm/arm/display/komeda/komeda_crtc.c | 23 +- - drivers/gpu/drm/arm/hdlcd_crtc.c | 6 +- - drivers/gpu/drm/arm/malidp_crtc.c | 27 +- - drivers/gpu/drm/armada/armada_crtc.c | 23 +- - drivers/gpu/drm/ast/ast_mode.c | 19 +- - .../gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c | 12 +- - drivers/gpu/drm/bridge/panel.c | 4 + - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 20 +- - drivers/gpu/drm/drm_atomic_helper.c | 106 +- - drivers/gpu/drm/drm_color_mgmt.c | 114 +- - drivers/gpu/drm/drm_connector.c | 70 + - drivers/gpu/drm/drm_edid.c | 13 +- - drivers/gpu/drm/drm_fourcc.c | 3 + - drivers/gpu/drm/drm_framebuffer.c | 16 +- - drivers/gpu/drm/drm_panel.c | 15 +- - drivers/gpu/drm/drm_probe_helper.c | 111 +- - drivers/gpu/drm/drm_simple_kms_helper.c | 14 +- - drivers/gpu/drm/exynos/exynos_drm_crtc.c | 16 +- - drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c | 8 +- - drivers/gpu/drm/gud/Kconfig | 14 + - drivers/gpu/drm/gud/Makefile | 4 + - drivers/gpu/drm/gud/gud_connector.c | 729 ++ - drivers/gpu/drm/gud/gud_drv.c | 696 ++ - drivers/gpu/drm/gud/gud_internal.h | 156 + - drivers/gpu/drm/gud/gud_pipe.c | 601 ++ - .../gpu/drm/hisilicon/hibmc/hibmc_drm_de.c | 8 +- - .../gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 8 +- - drivers/gpu/drm/i915/display/intel_atomic.c | 13 +- - .../gpu/drm/i915/display/intel_connector.c | 3 +- - drivers/gpu/drm/i915/display/intel_display.c | 1 - - drivers/gpu/drm/i915/display/intel_dp_mst.c | 7 +- - drivers/gpu/drm/i915/display/intel_hdmi.c | 5 +- - drivers/gpu/drm/imx/dcss/dcss-crtc.c | 13 +- - drivers/gpu/drm/imx/ipuv3-crtc.c | 16 +- - drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 35 +- - drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 21 +- - drivers/gpu/drm/meson/meson_crtc.c | 12 +- - drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 34 +- - drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c | 10 +- - drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c | 21 +- - drivers/gpu/drm/mxsfb/mxsfb_kms.c | 16 +- - drivers/gpu/drm/nouveau/dispnv50/disp.c | 5 +- - drivers/gpu/drm/nouveau/dispnv50/head.c | 9 +- - drivers/gpu/drm/omapdrm/omap_crtc.c | 22 +- - drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 253 +- - .../gpu/drm/panel/panel-jdi-lt070me05000.c | 18 +- - .../drm/panel/panel-raspberrypi-touchscreen.c | 49 +- - drivers/gpu/drm/panel/panel-simple.c | 106 +- - drivers/gpu/drm/qxl/qxl_display.c | 6 +- - drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 22 +- - drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 19 +- - drivers/gpu/drm/sti/sti_crtc.c | 6 +- - drivers/gpu/drm/stm/ltdc.c | 7 +- - drivers/gpu/drm/sun4i/sun4i_crtc.c | 17 +- - drivers/gpu/drm/tegra/dc.c | 18 +- - drivers/gpu/drm/tidss/tidss_crtc.c | 20 +- - drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 18 +- - drivers/gpu/drm/v3d/Kconfig | 2 +- - drivers/gpu/drm/v3d/v3d_debugfs.c | 16 +- - drivers/gpu/drm/v3d/v3d_drv.c | 35 +- - drivers/gpu/drm/v3d/v3d_drv.h | 6 + - drivers/gpu/drm/v3d/v3d_gem.c | 59 +- - drivers/gpu/drm/v3d/v3d_irq.c | 10 +- - drivers/gpu/drm/v3d/v3d_mmu.c | 2 + - drivers/gpu/drm/vboxvideo/vbox_mode.c | 6 +- - drivers/gpu/drm/vc4/Kconfig | 1 + - drivers/gpu/drm/vc4/Makefile | 1 + - drivers/gpu/drm/vc4/vc4_crtc.c | 289 +- - drivers/gpu/drm/vc4/vc4_debugfs.c | 7 +- - drivers/gpu/drm/vc4/vc4_dpi.c | 113 +- - drivers/gpu/drm/vc4/vc4_drv.c | 81 +- - drivers/gpu/drm/vc4/vc4_drv.h | 96 +- - drivers/gpu/drm/vc4/vc4_dsi.c | 277 +- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 1992 +++++ - drivers/gpu/drm/vc4/vc4_gem.c | 3 +- - drivers/gpu/drm/vc4/vc4_hdmi.c | 2207 ++++- - drivers/gpu/drm/vc4/vc4_hdmi.h | 148 +- - drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 45 +- - drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 35 +- - drivers/gpu/drm/vc4/vc4_hvs.c | 309 +- - drivers/gpu/drm/vc4/vc4_kms.c | 181 +- - drivers/gpu/drm/vc4/vc4_perfmon.c | 2 +- - drivers/gpu/drm/vc4/vc4_plane.c | 330 +- - drivers/gpu/drm/vc4/vc4_regs.h | 90 +- - drivers/gpu/drm/vc4/vc4_txp.c | 24 +- - drivers/gpu/drm/vc4/vc4_vec.c | 397 +- + drivers/gpu/drm/bridge/Kconfig | 1 + + drivers/gpu/drm/bridge/tc358762.c | 2 +- + drivers/gpu/drm/drm_atomic_helper.c | 18 +- + drivers/gpu/drm/drm_atomic_state_helper.c | 14 + + drivers/gpu/drm/drm_atomic_uapi.c | 19 + + drivers/gpu/drm/drm_color_mgmt.c | 40 +- + drivers/gpu/drm/drm_connector.c | 68 +- + drivers/gpu/drm/drm_fb_helper.c | 11 +- + drivers/gpu/drm/drm_modes.c | 5 +- + drivers/gpu/drm/drm_probe_helper.c | 5 +- + .../gpu/drm/i915/display/intel_backlight.c | 6 +- + drivers/gpu/drm/i915/display/intel_display.c | 13 + + drivers/gpu/drm/msm/msm_atomic.c | 2 + + drivers/gpu/drm/panel/Kconfig | 32 + + drivers/gpu/drm/panel/Makefile | 3 + + drivers/gpu/drm/panel/panel-ilitek-ili9806e.c | 484 ++ + drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 955 ++- + .../gpu/drm/panel/panel-jdi-lt070me05000.c | 19 +- + .../drm/panel/panel-raspberrypi-touchscreen.c | 44 +- + drivers/gpu/drm/panel/panel-simple.c | 234 +- + drivers/gpu/drm/panel/panel-sitronix-st7701.c | 407 +- + drivers/gpu/drm/panel/panel-tdo-y17p.c | 277 + + drivers/gpu/drm/panel/panel-waveshare-dsi.c | 434 + + drivers/gpu/drm/rp1/Kconfig | 5 + + drivers/gpu/drm/rp1/Makefile | 4 + + drivers/gpu/drm/rp1/rp1-dpi/Kconfig | 11 + + drivers/gpu/drm/rp1/rp1-dpi/Makefile | 5 + + drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c | 415 + + drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h | 69 + + drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_cfg.c | 510 ++ + drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c | 486 ++ + drivers/gpu/drm/rp1/rp1-dsi/Kconfig | 14 + + drivers/gpu/drm/rp1/rp1-dsi/Makefile | 5 + + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c | 535 ++ + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h | 94 + + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c | 443 + + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c | 1504 ++++ + drivers/gpu/drm/rp1/rp1-vec/Kconfig | 11 + + drivers/gpu/drm/rp1/rp1-vec/Makefile | 5 + + drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c | 506 ++ + drivers/gpu/drm/rp1/rp1-vec/rp1_vec.h | 69 + + drivers/gpu/drm/rp1/rp1-vec/rp1_vec_cfg.c | 508 ++ + drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c | 508 ++ + drivers/gpu/drm/rp1/rp1-vec/vec_regs.h | 1420 ++++ + drivers/gpu/drm/solomon/ssd130x.c | 2 +- + drivers/gpu/drm/tiny/ili9486.c | 1 - + drivers/gpu/drm/v3d/v3d_bo.c | 12 +- + drivers/gpu/drm/v3d/v3d_debugfs.c | 258 +- + drivers/gpu/drm/v3d/v3d_drv.c | 37 + + drivers/gpu/drm/v3d/v3d_drv.h | 67 + + drivers/gpu/drm/v3d/v3d_gem.c | 57 + + drivers/gpu/drm/v3d/v3d_irq.c | 55 +- + drivers/gpu/drm/v3d/v3d_mmu.c | 2 - + drivers/gpu/drm/v3d/v3d_regs.h | 51 +- + drivers/gpu/drm/v3d/v3d_sched.c | 180 +- + drivers/gpu/drm/vc4/Makefile | 4 +- + drivers/gpu/drm/vc4/tests/vc4_mock.c | 65 +- + drivers/gpu/drm/vc4/tests/vc4_mock.h | 28 +- + drivers/gpu/drm/vc4/tests/vc4_mock_output.c | 13 +- + drivers/gpu/drm/vc4/tests/vc4_mock_plane.c | 32 +- + drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c | 308 + + .../gpu/drm/vc4/tests/vc4_test_pv_muxing.c | 225 +- + drivers/gpu/drm/vc4/vc4_bo.c | 28 +- + drivers/gpu/drm/vc4/vc4_crtc.c | 185 +- + drivers/gpu/drm/vc4/vc4_debugfs.c | 3 +- + drivers/gpu/drm/vc4/vc4_drv.c | 90 +- + drivers/gpu/drm/vc4/vc4_drv.h | 143 +- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 2077 +++++ + drivers/gpu/drm/vc4/vc4_gem.c | 24 +- + drivers/gpu/drm/vc4/vc4_hdmi.c | 214 +- + drivers/gpu/drm/vc4/vc4_hdmi.h | 31 + + drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 640 ++ + drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 222 +- + drivers/gpu/drm/vc4/vc4_hvs.c | 1878 ++++- + drivers/gpu/drm/vc4/vc4_irq.c | 10 +- + drivers/gpu/drm/vc4/vc4_kms.c | 135 +- + drivers/gpu/drm/vc4/vc4_perfmon.c | 20 +- + drivers/gpu/drm/vc4/vc4_plane.c | 1036 ++- + drivers/gpu/drm/vc4/vc4_regs.h | 357 +- + drivers/gpu/drm/vc4/vc4_render_cl.c | 2 +- + drivers/gpu/drm/vc4/vc4_txp.c | 91 +- + drivers/gpu/drm/vc4/vc4_v3d.c | 10 +- + drivers/gpu/drm/vc4/vc4_validate.c | 8 +- + drivers/gpu/drm/vc4/vc4_validate_shaders.c | 2 +- + drivers/gpu/drm/vc4/vc4_vec.c | 172 +- drivers/gpu/drm/vc4/vc_image_types.h | 175 + - drivers/gpu/drm/virtio/virtgpu_display.c | 8 +- - drivers/gpu/drm/vkms/vkms_crtc.c | 24 +- - drivers/gpu/drm/vkms/vkms_writeback.c | 8 +- - drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 8 +- - drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 6 +- - drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 4 +- - drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 4 +- - drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 4 +- - drivers/gpu/drm/xlnx/zynqmp_disp.c | 14 +- - drivers/gpu/drm/zte/zx_vou.c | 6 +- drivers/hid/hid-ids.h | 6 + drivers/hid/hid-quirks.c | 2 + drivers/hid/usbhid/hid-core.c | 7 +- - drivers/hwmon/Kconfig | 11 + + drivers/hwmon/Kconfig | 7 + drivers/hwmon/Makefile | 1 + - drivers/hwmon/raspberrypi-hwmon.c | 41 +- - drivers/hwmon/rpi-poe-fan.c | 451 ++ + drivers/hwmon/aht10.c | 7 + + drivers/hwmon/ds1621.c | 10 + + drivers/hwmon/emc2305.c | 95 +- + drivers/hwmon/pwm-fan.c | 67 +- + drivers/hwmon/rp1-adc.c | 307 + + drivers/hwmon/sht3x.c | 12 +- drivers/i2c/busses/Kconfig | 19 + drivers/i2c/busses/Makefile | 2 + drivers/i2c/busses/i2c-bcm2708.c | 512 ++ - drivers/i2c/busses/i2c-bcm2835.c | 115 +- + drivers/i2c/busses/i2c-bcm2835.c | 133 +- + drivers/i2c/busses/i2c-designware-common.c | 39 + + drivers/i2c/busses/i2c-designware-core.h | 11 + + drivers/i2c/busses/i2c-designware-master.c | 76 +- drivers/i2c/busses/i2c-gpio.c | 4 +- + drivers/i2c/i2c-mux.c | 5 + + drivers/iio/adc/mcp3422.c | 9 +- + drivers/iio/light/tsl4531.c | 7 + + drivers/iio/light/veml6070.c | 7 + drivers/input/joystick/Kconfig | 8 + - drivers/input/joystick/Makefile | 2 +- + drivers/input/joystick/Makefile | 1 + drivers/input/joystick/rpisense-js.c | 153 + - drivers/input/touchscreen/edt-ft5x06.c | 85 +- - drivers/irqchip/irq-bcm2835.c | 104 +- + drivers/input/misc/da7280.c | 4 +- + drivers/input/misc/pwm-beeper.c | 4 +- + drivers/input/misc/pwm-vibra.c | 8 +- + drivers/input/touchscreen/ads7846.c | 11 + + drivers/input/touchscreen/edt-ft5x06.c | 124 +- + drivers/input/touchscreen/goodix.c | 75 +- + drivers/input/touchscreen/goodix.h | 5 + + drivers/iommu/Kconfig | 7 + + drivers/iommu/Makefile | 1 + + drivers/iommu/bcm2712-iommu-cache.c | 77 + + drivers/iommu/bcm2712-iommu.c | 665 ++ + drivers/iommu/bcm2712-iommu.h | 45 + + drivers/iommu/iommu.c | 14 +- + drivers/irqchip/Kconfig | 8 + + drivers/irqchip/Makefile | 1 + + drivers/irqchip/irq-bcm2712-mip.c | 323 + + drivers/irqchip/irq-bcm2835.c | 107 +- drivers/irqchip/irq-bcm2836.c | 28 +- + drivers/irqchip/irq-brcmstb-l2.c | 17 + drivers/leds/leds-gpio.c | 17 +- + drivers/leds/leds-pwm.c | 2 +- + drivers/leds/rgb/leds-pwm-multicolor.c | 4 +- drivers/leds/trigger/Kconfig | 18 + drivers/leds/trigger/Makefile | 2 + drivers/leds/trigger/ledtrig-actpwr.c | 190 + drivers/leds/trigger/ledtrig-input.c | 55 + drivers/mailbox/bcm2835-mailbox.c | 18 +- - drivers/mailbox/mailbox.c | 12 +- .../media/common/videobuf2/videobuf2-core.c | 21 +- - drivers/media/i2c/Kconfig | 45 + - drivers/media/i2c/Makefile | 4 + - drivers/media/i2c/adv7180.c | 14 + - drivers/media/i2c/imx219.c | 235 +- - drivers/media/i2c/imx290.c | 613 +- - drivers/media/i2c/imx477.c | 2309 ++++++ - drivers/media/i2c/imx519.c | 2091 +++++ - drivers/media/i2c/irs1125.c | 1200 +++ + drivers/media/i2c/Kconfig | 115 + + drivers/media/i2c/Makefile | 10 + + drivers/media/i2c/ad5398_vcm.c | 340 + + drivers/media/i2c/adv7180.c | 88 +- + drivers/media/i2c/arducam-pivariety.c | 1472 ++++ + drivers/media/i2c/arducam-pivariety.h | 110 + + drivers/media/i2c/arducam_64mp.c | 2618 ++++++ + drivers/media/i2c/bu64754.c | 315 + + drivers/media/i2c/dw9807-vcm.c | 227 +- + drivers/media/i2c/imx219.c | 330 +- + drivers/media/i2c/imx258.c | 799 +- + drivers/media/i2c/imx296.c | 166 +- + drivers/media/i2c/imx477.c | 2339 ++++++ + drivers/media/i2c/imx519.c | 2146 +++++ + drivers/media/i2c/imx708.c | 2116 +++++ + drivers/media/i2c/irs1125.c | 1197 +++ drivers/media/i2c/irs1125.h | 95 + - drivers/media/i2c/ov5647.c | 1343 +++- - drivers/media/i2c/ov7251.c | 15 +- - drivers/media/i2c/ov9281.c | 1294 +++ - drivers/media/i2c/tc358743.c | 135 +- + drivers/media/i2c/ov2311.c | 1178 +++ + drivers/media/i2c/ov5647.c | 158 +- + drivers/media/i2c/ov64a40.c | 3686 +++++++++ + drivers/media/i2c/ov7251.c | 62 +- + drivers/media/i2c/ov9282.c | 8 +- + drivers/media/i2c/tc358743.c | 121 +- drivers/media/mc/mc-request.c | 35 + - drivers/media/platform/Kconfig | 1 + + drivers/media/platform/Kconfig | 2 + drivers/media/platform/Makefile | 2 + drivers/media/platform/bcm2835/Kconfig | 21 + drivers/media/platform/bcm2835/Makefile | 3 + - .../media/platform/bcm2835/bcm2835-unicam.c | 3434 ++++++++ + .../media/platform/bcm2835/bcm2835-unicam.c | 3516 ++++++++ .../media/platform/bcm2835/vc4-regs-unicam.h | 253 + + drivers/media/platform/raspberrypi/Kconfig | 6 + + drivers/media/platform/raspberrypi/Makefile | 4 + + .../platform/raspberrypi/pisp_be/Kconfig | 12 + + .../platform/raspberrypi/pisp_be/Makefile | 6 + + .../platform/raspberrypi/pisp_be/pisp_be.c | 1993 +++++ + .../raspberrypi/pisp_be/pisp_be_config.h | 533 ++ + .../raspberrypi/pisp_be/pisp_be_formats.h | 519 ++ + .../platform/raspberrypi/rp1_cfe/Kconfig | 14 + + .../platform/raspberrypi/rp1_cfe/Makefile | 6 + + .../media/platform/raspberrypi/rp1_cfe/cfe.c | 2423 ++++++ + .../media/platform/raspberrypi/rp1_cfe/cfe.h | 43 + + .../platform/raspberrypi/rp1_cfe/cfe_fmts.h | 316 + + .../media/platform/raspberrypi/rp1_cfe/csi2.c | 624 ++ + .../media/platform/raspberrypi/rp1_cfe/csi2.h | 90 + + .../media/platform/raspberrypi/rp1_cfe/dphy.c | 177 + + .../media/platform/raspberrypi/rp1_cfe/dphy.h | 27 + + .../raspberrypi/rp1_cfe/pisp_common.h | 69 + + .../platform/raspberrypi/rp1_cfe/pisp_fe.c | 565 ++ + .../platform/raspberrypi/rp1_cfe/pisp_fe.h | 53 + + .../raspberrypi/rp1_cfe/pisp_fe_config.h | 272 + + .../raspberrypi/rp1_cfe/pisp_statistics.h | 62 + + .../platform/raspberrypi/rp1_cfe/pisp_types.h | 144 + + drivers/media/platform/video-mux.c | 73 +- + drivers/media/rc/Kconfig | 1 + + drivers/media/rc/pwm-ir-tx.c | 87 +- drivers/media/spi/Kconfig | 1 + drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 4 + - drivers/media/v4l2-core/v4l2-ctrls.c | 12 + - drivers/media/v4l2-core/v4l2-ioctl.c | 6 + + drivers/media/v4l2-core/v4l2-ctrls-defs.c | 1 + + drivers/media/v4l2-core/v4l2-ioctl.c | 22 + drivers/media/v4l2-core/v4l2-mem2mem.c | 9 +- - drivers/media/v4l2-core/v4l2-subdev.c | 48 +- - drivers/mfd/Kconfig | 8 + - drivers/mfd/Makefile | 1 + - drivers/mfd/bcm2835-pm.c | 11 + - drivers/mfd/rpisense-core.c | 165 + + drivers/mfd/Kconfig | 29 + + drivers/mfd/Makefile | 3 + + drivers/mfd/bcm2835-pm.c | 28 +- + drivers/mfd/rp1.c | 376 + + drivers/mfd/rpisense-core.c | 163 + + drivers/mfd/simple-mfd-i2c.c | 10 + drivers/misc/Kconfig | 8 + drivers/misc/Makefile | 1 + - drivers/misc/bcm2835_smi.c | 955 +++ - drivers/mmc/core/block.c | 28 +- - drivers/mmc/core/core.c | 3 +- - drivers/mmc/core/quirks.h | 8 + - drivers/mmc/host/Kconfig | 39 + + drivers/misc/bcm2835_smi.c | 953 +++ + drivers/mmc/core/block.c | 58 +- + drivers/mmc/core/bus.c | 2 + + drivers/mmc/core/card.h | 1 + + drivers/mmc/core/core.c | 10 +- + drivers/mmc/core/mmc.c | 4 +- + drivers/mmc/core/quirks.h | 38 +- + drivers/mmc/core/sd.c | 203 +- + drivers/mmc/core/sd_ops.c | 134 + + drivers/mmc/core/sd_ops.h | 6 + + drivers/mmc/host/Kconfig | 41 + drivers/mmc/host/Makefile | 2 + - drivers/mmc/host/bcm2835-mmc.c | 1576 ++++ - drivers/mmc/host/bcm2835-sdhost.c | 2208 +++++ + drivers/mmc/host/bcm2835-mmc.c | 1562 ++++ + drivers/mmc/host/bcm2835-sdhost.c | 2220 +++++ + drivers/mmc/host/bcm2835.c | 17 +- + drivers/mmc/host/cqhci-core.c | 13 +- + drivers/mmc/host/sdhci-brcmstb.c | 282 +- drivers/mmc/host/sdhci-iproc.c | 1 + - drivers/mmc/host/sdhci.c | 6 +- - .../net/ethernet/broadcom/genet/bcmgenet.c | 31 +- + drivers/mmc/host/sdhci-of-dwcmshc.c | 59 +- + drivers/mmc/host/sdhci-pltfm.c | 8 + + drivers/mmc/host/sdhci-pltfm.h | 3 + + drivers/mmc/host/sdhci.c | 36 +- + drivers/mmc/host/sdhci.h | 9 + + .../net/ethernet/broadcom/genet/bcmgenet.c | 45 +- .../net/ethernet/broadcom/genet/bcmgenet.h | 2 +- - drivers/net/ethernet/broadcom/genet/bcmmii.c | 2 + - drivers/net/phy/broadcom.c | 37 +- + drivers/net/ethernet/broadcom/genet/bcmmii.c | 6 +- + drivers/net/ethernet/cadence/macb.h | 25 + + drivers/net/ethernet/cadence/macb_main.c | 152 +- + drivers/net/ethernet/realtek/Makefile | 3 + + drivers/net/ethernet/realtek/r8169.h | 7 + + drivers/net/ethernet/realtek/r8169_leds.c | 157 + + drivers/net/ethernet/realtek/r8169_main.c | 65 + + drivers/net/phy/bcm-phy-ptp.c | 12 + + drivers/net/phy/broadcom.c | 48 +- drivers/net/phy/microchip.c | 27 + - drivers/net/phy/smsc.c | 12 +- - drivers/net/usb/Makefile | 2 +- - drivers/net/usb/lan78xx.c | 65 +- - drivers/net/usb/r8152.c | 3929 +++++++-- - drivers/net/usb/r8153_ecm.c | 162 + - drivers/net/usb/smsc95xx.c | 80 +- - .../broadcom/brcm80211/brcmfmac/bus.h | 11 +- - .../broadcom/brcm80211/brcmfmac/cfg80211.c | 62 +- - .../broadcom/brcm80211/brcmfmac/common.c | 14 +- - .../broadcom/brcm80211/brcmfmac/debug.h | 7 +- - .../broadcom/brcm80211/brcmfmac/firmware.c | 23 +- - .../wireless/broadcom/brcm80211/brcmfmac/of.c | 36 + - .../wireless/broadcom/brcm80211/brcmfmac/of.h | 7 + - .../broadcom/brcm80211/brcmfmac/pcie.c | 7 +- - .../broadcom/brcm80211/brcmfmac/sdio.c | 64 +- - .../broadcom/brcm80211/brcmfmac/usb.c | 7 +- - drivers/nvmem/Kconfig | 8 + + drivers/net/usb/ax88179_178a.c | 2 + + drivers/net/usb/lan78xx.c | 64 +- + drivers/net/usb/smsc95xx.c | 51 +- + .../broadcom/brcm80211/brcmfmac/bus.h | 2 +- + .../broadcom/brcm80211/brcmfmac/cfg80211.c | 367 +- + .../broadcom/brcm80211/brcmfmac/cfg80211.h | 18 + + .../broadcom/brcm80211/brcmfmac/common.c | 39 + + .../broadcom/brcm80211/brcmfmac/core.c | 13 +- + .../broadcom/brcm80211/brcmfmac/debug.h | 8 +- + .../broadcom/brcm80211/brcmfmac/feature.c | 1 + + .../broadcom/brcm80211/brcmfmac/feature.h | 2 + + .../broadcom/brcm80211/brcmfmac/firmware.c | 21 +- + .../broadcom/brcm80211/brcmfmac/fweh.c | 28 +- + .../broadcom/brcm80211/brcmfmac/fweh.h | 31 +- + .../broadcom/brcm80211/brcmfmac/fwil_types.h | 45 + + .../broadcom/brcm80211/brcmfmac/p2p.c | 5 + + .../broadcom/brcm80211/brcmfmac/pcie.c | 2 +- + .../broadcom/brcm80211/brcmfmac/sdio.c | 262 +- + .../broadcom/brcm80211/brcmfmac/sdio.h | 110 + + .../broadcom/brcm80211/brcmfmac/usb.c | 4 +- + .../broadcom/brcm80211/include/chipcommon.h | 2 + + drivers/nvmem/Kconfig | 12 + drivers/nvmem/Makefile | 2 + - drivers/nvmem/rmem.c | 97 + - drivers/of/Kconfig | 7 + + drivers/nvmem/raspberrypi-otp.c | 133 + + drivers/of/Kconfig | 11 + drivers/of/Makefile | 1 + drivers/of/configfs.c | 277 + drivers/of/overlay.c | 2 + - drivers/of/platform.c | 1 + - drivers/pci/controller/pcie-brcmstb.c | 35 +- + drivers/pci/controller/pcie-brcmstb.c | 533 +- drivers/perf/Kconfig | 8 + drivers/perf/Makefile | 1 + - drivers/perf/raspberrypi_axi_monitor.c | 637 ++ - drivers/pinctrl/bcm/pinctrl-bcm2835.c | 14 +- - drivers/power/reset/gpio-poweroff.c | 20 +- - drivers/power/supply/Kconfig | 6 + + drivers/perf/raspberrypi_axi_monitor.c | 830 ++ + drivers/phy/broadcom/Kconfig | 2 +- + .../phy/broadcom/phy-brcm-usb-init-synopsys.c | 59 + + drivers/phy/broadcom/phy-brcm-usb-init.h | 2 + + drivers/phy/broadcom/phy-brcm-usb.c | 18 +- + drivers/pinctrl/Kconfig | 7 + + drivers/pinctrl/Makefile | 1 + + drivers/pinctrl/bcm/Kconfig | 9 + + drivers/pinctrl/bcm/Makefile | 1 + + drivers/pinctrl/bcm/pinctrl-bcm2712.c | 1247 +++ + drivers/pinctrl/bcm/pinctrl-bcm2835.c | 37 +- + drivers/pinctrl/pinctrl-rp1.c | 1600 ++++ + drivers/platform/x86/lenovo-yogabook.c | 2 +- + drivers/pmdomain/bcm/bcm2835-power.c | 29 +- + drivers/power/reset/gpio-poweroff.c | 21 +- + drivers/power/supply/Kconfig | 7 + drivers/power/supply/Makefile | 1 + - drivers/power/supply/rpi_poe_power.c | 227 + - drivers/pps/clients/pps-gpio.c | 2 + - .../regulator/rpi-panel-attiny-regulator.c | 285 +- + drivers/power/supply/rpi_poe_power.c | 243 + + drivers/pps/clients/pps-gpio.c | 3 + + drivers/pps/pps.c | 6 +- + drivers/pwm/Kconfig | 9 + + drivers/pwm/Makefile | 1 + + drivers/pwm/core.c | 74 +- + drivers/pwm/pwm-bcm2835.c | 59 +- + drivers/pwm/pwm-raspberrypi-poe.c | 81 +- + drivers/pwm/pwm-renesas-tpu.c | 1 - + drivers/pwm/pwm-rp1.c | 203 + + drivers/pwm/pwm-twl-led.c | 2 +- + drivers/pwm/pwm-vt8500.c | 2 +- + drivers/pwm/sysfs.c | 10 +- + drivers/regulator/Kconfig | 10 + + drivers/regulator/Makefile | 1 + + drivers/regulator/pwm-regulator.c | 4 +- + .../regulator/rpi-panel-attiny-regulator.c | 18 +- + drivers/regulator/rpi-panel-v2-regulator.c | 189 + + drivers/reset/Kconfig | 2 +- + drivers/reset/reset-brcmstb-rescal.c | 10 + + drivers/rtc/Kconfig | 11 + + drivers/rtc/Makefile | 1 + + drivers/rtc/rtc-ds3232.c | 7 + drivers/rtc/rtc-pcf2123.c | 1 + - drivers/rtc/rtc-pcf85063.c | 2 + - drivers/rtc/rtc-pcf8523.c | 25 +- - drivers/rtc/rtc-rv3028.c | 17 + + drivers/rtc/rtc-pcf8523.c | 28 + + drivers/rtc/rtc-rpi.c | 277 + + drivers/rtc/rtc-rv3028.c | 24 +- drivers/soc/bcm/Kconfig | 1 + - drivers/soc/bcm/bcm2835-power.c | 22 + - drivers/spi/spi-bcm2835.c | 23 +- + drivers/spi/spi-bcm2835.c | 37 +- + drivers/spi/spi-dw-core.c | 12 +- + drivers/spi/spi-dw-dma.c | 6 +- + drivers/spi/spi-dw-mmio.c | 8 +- + drivers/spi/spi-gpio.c | 105 +- drivers/spi/spi.c | 9 + - drivers/spi/spidev.c | 7 +- + drivers/spi/spidev.c | 8 +- drivers/staging/fbtft/fb_st7735r.c | 38 +- - drivers/staging/fbtft/fb_st7789v.c | 45 +- + drivers/staging/fbtft/fb_st7789v.c | 44 +- drivers/staging/fbtft/fbtft-core.c | 16 +- - drivers/staging/fbtft/fbtft.h | 28 +- + drivers/staging/fbtft/fbtft.h | 112 +- drivers/staging/media/Kconfig | 2 + drivers/staging/media/Makefile | 1 + drivers/staging/media/rpivid/Kconfig | 16 + drivers/staging/media/rpivid/Makefile | 5 + - drivers/staging/media/rpivid/rpivid.c | 447 ++ - drivers/staging/media/rpivid/rpivid.h | 202 + - drivers/staging/media/rpivid/rpivid_dec.c | 81 + + drivers/staging/media/rpivid/rpivid.c | 466 ++ + drivers/staging/media/rpivid/rpivid.h | 203 + + drivers/staging/media/rpivid/rpivid_dec.c | 96 + drivers/staging/media/rpivid/rpivid_dec.h | 19 + - drivers/staging/media/rpivid/rpivid_h265.c | 2688 +++++++ - drivers/staging/media/rpivid/rpivid_hw.c | 366 + + drivers/staging/media/rpivid/rpivid_h265.c | 2706 +++++++ + drivers/staging/media/rpivid/rpivid_hw.c | 383 + drivers/staging/media/rpivid/rpivid_hw.h | 303 + - drivers/staging/media/rpivid/rpivid_video.c | 707 ++ + drivers/staging/media/rpivid/rpivid_video.c | 696 ++ drivers/staging/media/rpivid/rpivid_video.h | 33 + drivers/staging/vc04_services/Kconfig | 4 + drivers/staging/vc04_services/Makefile | 3 + - .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 10 +- - .../vc04_services/bcm2835-audio/bcm2835.c | 130 +- - .../vc04_services/bcm2835-audio/bcm2835.h | 4 +- + .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 3 +- + .../vc04_services/bcm2835-audio/bcm2835.c | 110 +- + .../vc04_services/bcm2835-audio/bcm2835.h | 6 +- .../bcm2835-camera/bcm2835-camera.c | 11 +- .../bcm2835-camera/bcm2835-camera.h | 2 +- .../vc04_services/bcm2835-camera/controls.c | 60 +- .../vc04_services/bcm2835-codec/Kconfig | 11 + .../vc04_services/bcm2835-codec/Makefile | 8 + .../staging/vc04_services/bcm2835-codec/TODO | 1 + - .../bcm2835-codec/bcm2835-v4l2-codec.c | 3684 +++++++++ + .../bcm2835-codec/bcm2835-v4l2-codec.c | 3964 +++++++++ .../staging/vc04_services/bcm2835-isp/Kconfig | 14 + .../vc04_services/bcm2835-isp/Makefile | 8 + .../bcm2835-isp/bcm2835-isp-ctrls.h | 72 + - .../bcm2835-isp/bcm2835-isp-fmts.h | 553 ++ - .../bcm2835-isp/bcm2835-v4l2-isp.c | 1810 +++++ + .../bcm2835-isp/bcm2835-isp-fmts.h | 558 ++ + .../bcm2835-isp/bcm2835-v4l2-isp.c | 1816 +++++ .../include/linux/broadcom/vc_sm_cma_ioctl.h | 114 + - .../interface/vchiq_arm/vchiq_2835_arm.c | 142 +- - .../interface/vchiq_arm/vchiq_arm.c | 36 + - .../interface/vchiq_arm/vchiq_arm.h | 1 + + .../interface/vchiq_arm/vchiq_arm.c | 179 +- .../staging/vc04_services/vc-sm-cma/Kconfig | 10 + .../staging/vc04_services/vc-sm-cma/Makefile | 12 + drivers/staging/vc04_services/vc-sm-cma/TODO | 1 + .../staging/vc04_services/vc-sm-cma/vc_sm.c | 1707 ++++ .../staging/vc04_services/vc-sm-cma/vc_sm.h | 84 + - .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 503 ++ + .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 511 ++ .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.h | 63 + .../vc04_services/vc-sm-cma/vc_sm_defs.h | 297 + .../vc04_services/vc-sm-cma/vc_sm_knl.h | 28 + .../staging/vc04_services/vchiq-mmal/Kconfig | 3 +- .../vc04_services/vchiq-mmal/mmal-common.h | 5 + .../vc04_services/vchiq-mmal/mmal-encodings.h | 66 + + .../vchiq-mmal/mmal-msg-format.h | 10 + .../vc04_services/vchiq-mmal/mmal-msg.h | 54 + - .../vchiq-mmal/mmal-parameters.h | 251 +- - .../vc04_services/vchiq-mmal/mmal-vchiq.c | 413 +- + .../vchiq-mmal/mmal-parameters.h | 253 +- + .../vc04_services/vchiq-mmal/mmal-vchiq.c | 388 +- .../vc04_services/vchiq-mmal/mmal-vchiq.h | 5 + drivers/thermal/broadcom/bcm2711_thermal.c | 2 +- - drivers/thermal/gov_step_wise.c | 33 +- - drivers/tty/serial/8250/8250_bcm2835aux.c | 7 + - drivers/tty/serial/amba-pl011.c | 73 +- - drivers/tty/serial/sc16is7xx.c | 16 +- + drivers/thermal/gov_step_wise.c | 23 +- + drivers/tty/serial/8250/8250.h | 1 + + drivers/tty/serial/8250/8250_bcm2835aux.c | 8 + + drivers/tty/serial/8250/8250_core.c | 15 + + drivers/tty/serial/8250/8250_port.c | 9 + + drivers/tty/serial/amba-pl011.c | 108 + + drivers/tty/serial/sc16is7xx.c | 5 + drivers/usb/Makefile | 1 + drivers/usb/core/generic.c | 1 + drivers/usb/core/hcd.c | 10 + drivers/usb/core/hub.c | 2 +- drivers/usb/core/message.c | 94 + drivers/usb/core/otg_productlist.h | 114 +- + drivers/usb/dwc3/core.c | 58 + + drivers/usb/dwc3/core.h | 17 +- + drivers/usb/dwc3/host.c | 9 +- drivers/usb/gadget/file_storage.c | 3676 +++++++++ drivers/usb/host/Kconfig | 10 + drivers/usb/host/Makefile | 1 + @@ -747,9 +971,9 @@ drivers/usb/host/dwc_common_port/dwc_modpow.h | 34 + .../usb/host/dwc_common_port/dwc_notifier.c | 319 + .../usb/host/dwc_common_port/dwc_notifier.h | 122 + - drivers/usb/host/dwc_common_port/dwc_os.h | 1276 +++ + drivers/usb/host/dwc_common_port/dwc_os.h | 1275 +++ drivers/usb/host/dwc_common_port/usb.h | 275 + - drivers/usb/host/dwc_otg/Makefile | 85 + + drivers/usb/host/dwc_otg/Makefile | 86 + drivers/usb/host/dwc_otg/doc/doxygen.cfg | 224 + drivers/usb/host/dwc_otg/dummy_audio.c | 1574 ++++ drivers/usb/host/dwc_otg/dwc_cfi_common.h | 142 + @@ -769,12 +993,12 @@ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 1433 ++++ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 399 + drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S | 80 + - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 4363 ++++++++++ + drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 4366 ++++++++++ drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 870 ++ drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c | 1135 +++ drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h | 421 + drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 2757 +++++++ - drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 1087 +++ + drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 1084 +++ drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 974 +++ drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 200 + drivers/usb/host/dwc_otg/dwc_otg_pcd.c | 2725 +++++++ @@ -787,174 +1011,201 @@ drivers/usb/host/dwc_otg/test/dwc_otg_test.pm | 337 + .../usb/host/dwc_otg/test/test_mod_param.pl | 133 + drivers/usb/host/dwc_otg/test/test_sysfs.pl | 193 + - drivers/usb/host/xhci-mem.c | 67 +- - drivers/usb/host/xhci-pci.c | 2 + - drivers/usb/host/xhci-ring.c | 34 +- - drivers/usb/host/xhci.c | 104 +- - drivers/usb/host/xhci.h | 7 +- + drivers/usb/host/xhci-mem.c | 40 +- + drivers/usb/host/xhci-pci.c | 21 +- + drivers/usb/host/xhci-ring.c | 86 +- + drivers/usb/host/xhci.c | 104 + + drivers/usb/host/xhci.h | 10 +- + drivers/usb/phy/phy-generic.c | 7 - drivers/video/backlight/Kconfig | 7 + drivers/video/backlight/Makefile | 1 + + drivers/video/backlight/lm3630a_bl.c | 2 +- + drivers/video/backlight/lp855x_bl.c | 2 +- + drivers/video/backlight/pwm_bl.c | 12 +- drivers/video/backlight/rpi_backlight.c | 119 + drivers/video/fbdev/Kconfig | 27 + drivers/video/fbdev/Makefile | 2 + drivers/video/fbdev/bcm2708_fb.c | 1274 +++ - drivers/video/fbdev/core/cfbimgblt.c | 152 +- - drivers/video/fbdev/core/fbmem.c | 35 + - drivers/video/fbdev/rpisense-fb.c | 296 + + drivers/video/fbdev/core/fb_chrdev.c | 35 + + drivers/video/fbdev/core/fb_defio.c | 3 +- + drivers/video/fbdev/core/fbmem.c | 19 +- + drivers/video/fbdev/rpisense-fb.c | 297 + + drivers/video/fbdev/ssd1307fb.c | 2 +- drivers/video/logo/logo_linux_clut224.ppm | 2483 ++---- - drivers/w1/masters/w1-gpio.c | 2 +- + drivers/w1/masters/w1-gpio.c | 15 +- + drivers/w1/w1.c | 2 + + drivers/w1/w1_io.c | 37 +- drivers/watchdog/bcm2835_wdt.c | 51 +- - include/drm/drm_atomic.h | 20 + - include/drm/drm_atomic_helper.h | 4 - - include/drm/drm_connector.h | 4 + - include/drm/drm_edid.h | 4 +- - include/drm/drm_modeset_helper_vtables.h | 56 +- - include/drm/drm_panel.h | 8 + - include/drm/drm_probe_helper.h | 1 + - include/drm/gud.h | 333 + + include/drm/drm_color_mgmt.h | 3 + + include/drm/drm_connector.h | 7 + + include/drm/drm_mipi_dsi.h | 38 +- + include/drm/drm_plane.h | 37 + + include/dt-bindings/clock/rp1.h | 56 + include/dt-bindings/gpio/gpio-fsm.h | 21 + + include/dt-bindings/mfd/rp1.h | 235 + include/linux/brcmphy.h | 1 + include/linux/broadcom/bcm2835_smi.h | 391 + include/linux/broadcom/vc_mem.h | 39 + - include/linux/clk.h | 4 + - include/linux/hdmi.h | 2 +- + include/linux/fb.h | 2 + + include/linux/gpio/driver.h | 1 + + include/linux/iommu.h | 8 +- include/linux/leds.h | 3 + - include/linux/mfd/bcm2835-pm.h | 1 + include/linux/mfd/rpisense/core.h | 47 + include/linux/mfd/rpisense/framebuffer.h | 32 + include/linux/mfd/rpisense/joystick.h | 35 + include/linux/microchipphy.h | 8 + include/linux/mmc/card.h | 2 + + include/linux/mmc/sd.h | 12 + + include/linux/module.h | 2 +- include/linux/platform_data/dma-bcm2708.h | 143 + + include/linux/pwm.h | 57 +- + include/linux/rp1_platform.h | 20 + include/linux/usb.h | 2 + include/linux/usb/hcd.h | 7 + - include/linux/usb/r8152.h | 37 + - include/media/hevc-ctrls.h | 17 + + include/linux/w1.h | 5 + include/media/media-request.h | 12 + - include/media/v4l2-mediabus.h | 8 + + include/media/raspberrypi/pisp_common.h | 65 + + include/media/raspberrypi/pisp_types.h | 144 + include/media/videobuf2-core.h | 15 + include/soc/bcm2835/raspberrypi-firmware.h | 29 +- - include/sound/hdmi-codec.h | 17 +- - include/sound/pcm_iec958.h | 8 + - include/uapi/drm/drm_fourcc.h | 11 + - include/uapi/drm/drm_mode.h | 1 + + include/uapi/drm/v3d_drm.h | 4 + include/uapi/linux/bcm2835-isp.h | 347 + include/uapi/linux/fb.h | 12 + - include/uapi/linux/media-bus-format.h | 8 +- - include/uapi/linux/v4l2-controls.h | 6 + - include/uapi/linux/videodev2.h | 13 + + include/uapi/linux/media-bus-format.h | 3 + + include/uapi/linux/v4l2-controls.h | 5 + + include/uapi/linux/videodev2.h | 40 + kernel/cgroup/cgroup.c | 38 + kernel/resource.c | 6 + - mm/page_alloc.c | 2 - - mm/zswap.c | 53 +- + mm/page_alloc.c | 28 +- + net/bluetooth/hci_sync.c | 4 +- net/bluetooth/smp.c | 16 +- - scripts/Makefile.dtbinst | 6 +- + net/wireless/certs/debian.hex | 1426 ++++ + scripts/Makefile.dtbinst | 5 +- scripts/Makefile.lib | 19 + - sound/core/pcm_iec958.c | 129 +- - sound/soc/bcm/Kconfig | 298 + - sound/soc/bcm/Makefile | 69 +- - sound/soc/bcm/allo-boss-dac.c | 456 ++ - sound/soc/bcm/allo-boss2-dac.c | 1133 +++ - sound/soc/bcm/allo-katana-codec.c | 388 + - sound/soc/bcm/allo-piano-dac-plus.c | 1063 +++ + sound/soc/bcm/Kconfig | 269 + + sound/soc/bcm/Makefile | 71 +- + sound/soc/bcm/allo-boss-dac.c | 468 ++ + sound/soc/bcm/allo-boss2-dac.c | 1130 +++ + sound/soc/bcm/allo-katana-codec.c | 386 + + sound/soc/bcm/allo-piano-dac-plus.c | 1064 +++ sound/soc/bcm/allo-piano-dac.c | 122 + .../bcm/audioinjector-isolated-soundcard.c | 183 + - sound/soc/bcm/audioinjector-octo-soundcard.c | 346 + - sound/soc/bcm/audioinjector-pi-soundcard.c | 187 + + sound/soc/bcm/audioinjector-octo-soundcard.c | 347 + + sound/soc/bcm/audioinjector-pi-soundcard.c | 189 + sound/soc/bcm/audiosense-pi.c | 248 + + sound/soc/bcm/bcm2835-i2s.c | 18 +- sound/soc/bcm/chipdip-dac.c | 275 + + sound/soc/bcm/dacberry400.c | 259 + sound/soc/bcm/digidac1-soundcard.c | 421 + sound/soc/bcm/dionaudio_loco-v2.c | 117 + sound/soc/bcm/dionaudio_loco.c | 117 + sound/soc/bcm/fe-pi-audio.c | 154 + sound/soc/bcm/googlevoicehat-codec.c | 214 + - sound/soc/bcm/hifiberry_dacplus.c | 527 ++ - sound/soc/bcm/hifiberry_dacplusadc.c | 398 + - sound/soc/bcm/hifiberry_dacplusadcpro.c | 605 ++ + sound/soc/bcm/hifiberry_dacplus.c | 560 ++ + sound/soc/bcm/hifiberry_dacplusadc.c | 396 + + sound/soc/bcm/hifiberry_dacplusadcpro.c | 603 ++ sound/soc/bcm/hifiberry_dacplusdsp.c | 90 + sound/soc/bcm/hifiberry_dacplushd.c | 238 + - sound/soc/bcm/i-sabre-q2m.c | 158 + - sound/soc/bcm/iqaudio-codec.c | 274 + - sound/soc/bcm/iqaudio-dac.c | 223 + - sound/soc/bcm/justboom-both.c | 266 + + sound/soc/bcm/i-sabre-q2m.c | 159 + + sound/soc/bcm/iqaudio-codec.c | 278 + + sound/soc/bcm/iqaudio-dac.c | 224 + + sound/soc/bcm/justboom-both.c | 267 + sound/soc/bcm/justboom-dac.c | 147 + - sound/soc/bcm/pifi-40.c | 283 + - sound/soc/bcm/pisound.c | 1238 +++ - sound/soc/bcm/rpi-cirrus.c | 1025 +++ + sound/soc/bcm/pifi-40.c | 282 + + sound/soc/bcm/pisound.c | 1255 +++ + sound/soc/bcm/rpi-cirrus.c | 1024 +++ sound/soc/bcm/rpi-proto.c | 147 + - sound/soc/bcm/rpi-simple-soundcard.c | 419 + - sound/soc/bcm/rpi-wm8804-soundcard.c | 410 + - sound/soc/codecs/Kconfig | 28 +- + sound/soc/bcm/rpi-simple-soundcard.c | 520 ++ + sound/soc/bcm/rpi-wm8804-soundcard.c | 549 ++ + sound/soc/codecs/Kconfig | 26 +- sound/soc/codecs/Makefile | 8 + + sound/soc/codecs/adau1977-i2c.c | 10 + sound/soc/codecs/cs42xx8-i2c.c | 9 +- - sound/soc/codecs/cs42xx8.c | 2 + - sound/soc/codecs/hdmi-codec.c | 219 +- - sound/soc/codecs/i-sabre-codec.c | 392 + + sound/soc/codecs/cs42xx8.c | 10 + + sound/soc/codecs/i-sabre-codec.c | 389 + sound/soc/codecs/i-sabre-codec.h | 42 + - sound/soc/codecs/ma120x0p.c | 1384 ++++ + sound/soc/codecs/ma120x0p.c | 1380 ++++ sound/soc/codecs/pcm1794a.c | 69 + - sound/soc/codecs/pcm512x.c | 2 +- - sound/soc/codecs/tas5713.c | 363 + + sound/soc/codecs/pcm512x-i2c.c | 4 + + sound/soc/codecs/pcm512x.c | 38 +- + sound/soc/codecs/tas5713.c | 360 + sound/soc/codecs/tas5713.h | 210 + + sound/soc/dwc/dwc-i2s.c | 169 +- + sound/soc/dwc/local.h | 12 + sound/soc/soc-core.c | 14 +- - sound/usb/quirks-table.h | 9 + - sound/usb/quirks.c | 6 + - 895 files changed, 175509 insertions(+), 4829 deletions(-) + sound/usb/card.c | 8 +- + sound/usb/quirks.c | 2 + + 1131 files changed, 229610 insertions(+), 4285 deletions(-) create mode 100644 Documentation/admin-guide/media/bcm2835-isp.rst - create mode 100644 Documentation/devicetree/bindings/clock/raspberrypi,firmware-clocks.yaml - create mode 100644 Documentation/devicetree/bindings/hwmon/rpi-poe-fan.txt + create mode 100644 Documentation/devicetree/bindings/display/panel/panel-dsi.yaml + create mode 100644 Documentation/devicetree/bindings/hwmon/microchip,emc2305.yaml create mode 100644 Documentation/devicetree/bindings/media/bcm2835-unicam.txt - create mode 100644 Documentation/devicetree/bindings/media/i2c/imx219.txt + create mode 100644 Documentation/devicetree/bindings/media/i2c/ad5398.txt + create mode 100644 Documentation/devicetree/bindings/media/i2c/arducam,64mp.yaml + create mode 100644 Documentation/devicetree/bindings/media/i2c/arducam-pivariety.yaml create mode 100644 Documentation/devicetree/bindings/media/i2c/imx378.yaml create mode 100644 Documentation/devicetree/bindings/media/i2c/imx477.yaml create mode 100644 Documentation/devicetree/bindings/media/i2c/imx519.yaml create mode 100644 Documentation/devicetree/bindings/media/i2c/irs1125.txt + create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml + create mode 100644 Documentation/devicetree/bindings/media/i2c/rohm,bu64754.yaml + rename Documentation/devicetree/bindings/media/i2c/{imx258.yaml => sony,imx258.yaml} (90%) + create mode 100644 Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml create mode 100644 Documentation/devicetree/bindings/media/rpivid_hevc.yaml create mode 100644 Documentation/devicetree/bindings/misc/brcm,bcm2835-smi-dev.txt create mode 100644 Documentation/devicetree/bindings/misc/brcm,bcm2835-smi.txt - create mode 100644 Documentation/devicetree/bindings/nvmem/rmem.yaml create mode 100644 Documentation/devicetree/bindings/pci/brcmstb-pcie.txt + create mode 100644 Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt + create mode 100644 Documentation/devicetree/bindings/pwm/pwm-rp1.yaml + create mode 100644 Documentation/devicetree/bindings/rtc/rtc-rpi.txt create mode 100644 Documentation/devicetree/bindings/vendor-prefixes.txt create mode 100644 Documentation/devicetree/configfs-overlays.txt - create mode 100644 Documentation/hwmon/rpi-poe-fan create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-meta-bcm2835-isp-stats.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-meta-sensor-data.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv12-col128.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y12p.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y14p.rst - create mode 100644 arch/arm/boot/dts/bcm2708-rpi-b-plus.dts - create mode 100644 arch/arm/boot/dts/bcm2708-rpi-b-rev1.dts - create mode 100644 arch/arm/boot/dts/bcm2708-rpi-b.dts - create mode 100644 arch/arm/boot/dts/bcm2708-rpi-bt.dtsi - create mode 100644 arch/arm/boot/dts/bcm2708-rpi-cm.dts - create mode 100644 arch/arm/boot/dts/bcm2708-rpi-cm.dtsi - create mode 100644 arch/arm/boot/dts/bcm2708-rpi-zero-w.dts - create mode 100644 arch/arm/boot/dts/bcm2708-rpi-zero.dts - create mode 100644 arch/arm/boot/dts/bcm2708-rpi.dtsi - create mode 100644 arch/arm/boot/dts/bcm2708.dtsi - create mode 100644 arch/arm/boot/dts/bcm2709-rpi-2-b.dts - create mode 100644 arch/arm/boot/dts/bcm2709-rpi.dtsi - create mode 100644 arch/arm/boot/dts/bcm2709.dtsi - create mode 100644 arch/arm/boot/dts/bcm270x-rpi.dtsi - create mode 100644 arch/arm/boot/dts/bcm270x.dtsi - create mode 100644 arch/arm/boot/dts/bcm2710-rpi-2-b.dts - create mode 100644 arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts - create mode 100644 arch/arm/boot/dts/bcm2710-rpi-3-b.dts - create mode 100644 arch/arm/boot/dts/bcm2710-rpi-cm3.dts - create mode 100644 arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts - create mode 100644 arch/arm/boot/dts/bcm2710-rpi-zero-2.dts - create mode 100644 arch/arm/boot/dts/bcm2710.dtsi - create mode 100644 arch/arm/boot/dts/bcm2711-rpi-400.dts - create mode 100644 arch/arm/boot/dts/bcm2711-rpi-cm4.dts - create mode 100644 arch/arm/boot/dts/bcm2711-rpi-cm4s.dts - create mode 100644 arch/arm/boot/dts/bcm2711-rpi.dtsi - create mode 100644 arch/arm/boot/dts/bcm271x-rpi-bt.dtsi - create mode 100644 arch/arm/boot/dts/bcm283x-rpi-csi0-2lane.dtsi - create mode 100644 arch/arm/boot/dts/bcm283x-rpi-csi1-2lane.dtsi - create mode 100644 arch/arm/boot/dts/bcm283x-rpi-csi1-4lane.dtsi - create mode 100644 arch/arm/boot/dts/bcm283x-rpi-i2c0mux_0_28.dtsi - create mode 100644 arch/arm/boot/dts/bcm283x-rpi-i2c0mux_0_44.dtsi - delete mode 100644 arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi + create mode 100644 README.md + create mode 100644 arch/arm/boot/dts/broadcom/bcm2708-rpi-b-plus.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2708-rpi-b-rev1.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2708-rpi-b.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm2708-rpi-cm.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2708-rpi-cm.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm2708-rpi-zero-w.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2708-rpi-zero.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2708-rpi.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm2708.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm2709-rpi-2-b.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2709-rpi-cm2.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2709-rpi.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm2709.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm270x-rpi.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm270x.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm2710-rpi-2-b.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2710-rpi-zero-2-w.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2710-rpi-zero-2.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2710.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm2712-rpi-5-b.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm2712.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts + create mode 100644 arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm283x-rpi-csi0-2lane.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm283x-rpi-csi1-2lane.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm283x-rpi-csi1-4lane.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm283x-rpi-i2c0mux_0_28.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/bcm283x-rpi-i2c0mux_0_44.dtsi + create mode 100644 arch/arm/boot/dts/broadcom/rp1.dtsi create mode 100644 arch/arm/boot/dts/overlays/Makefile create mode 100644 arch/arm/boot/dts/overlays/README create mode 100644 arch/arm/boot/dts/overlays/act-led-overlay.dts @@ -977,23 +1228,38 @@ create mode 100755 arch/arm/boot/dts/overlays/anyspi-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/apds9960-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/applepi-dac-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/arducam-64mp-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/arducam-64mp.dtsi + create mode 100644 arch/arm/boot/dts/overlays/arducam-pivariety-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/at86rf233-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/audioinjector-bare-i2s-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/audioinjector-isolated-soundcard-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/audioinjector-ultra-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/audremap-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/balena-fin-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/bcm2712d0-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/camera-mux-2port-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/camera-mux-4port-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/cap1106-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/chipdip-dac-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/cirrus-wm5102-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/cm-swap-i2c0-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/cma-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/crystalfontz-cfa050_pi_m-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/cutiepi-panel-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/dacberry400-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/dht11-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/dionaudio-kiwi-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/dionaudio-loco-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/disable-bt-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/disable-bt-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/disable-emmc2-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/disable-wifi-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/disable-wifi-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/dpi18-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/dpi18cpadhi-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/dpi24-overlay.dts @@ -1008,10 +1274,13 @@ create mode 100644 arch/arm/boot/dts/overlays/fbtft-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/fsm-demo-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/gc9a01-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/ghost-amp-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/goodix-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/googlevoicehat-soundcard-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/gpio-charger-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/gpio-fan-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/gpio-hog-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/gpio-ir-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/gpio-ir-tx-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/gpio-key-overlay.dts @@ -1020,12 +1289,18 @@ create mode 100644 arch/arm/boot/dts/overlays/gpio-no-irq-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/hat_map.dts create mode 100644 arch/arm/boot/dts/overlays/hd44780-lcd-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/hdmi-backlight-hwhack-gpio-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/hifiberry-amp100-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/hifiberry-amp3-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/hifiberry-amp4pro-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dac8x-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplus-pro-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplus-std-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplusdsp-overlay.dts @@ -1038,32 +1313,53 @@ create mode 100644 arch/arm/boot/dts/overlays/hy28b-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/i2c-bcm2708-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/i2c-fan-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/i2c-mux-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi create mode 100644 arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts + create mode 100755 arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi create mode 100755 arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/i2c0-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/i2c0-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/i2c1-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/i2c1-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/i2c2-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/i2c3-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/i2c3-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/i2c4-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/i2c5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/i2c6-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/i2s-dac-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/i2s-gpio28-31-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/ilitek251x-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/imx219-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/imx219.dtsi + create mode 100644 arch/arm/boot/dts/overlays/imx258-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/imx258.dtsi create mode 100644 arch/arm/boot/dts/overlays/imx290-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi + create mode 100644 arch/arm/boot/dts/overlays/imx290_327.dtsi + create mode 100644 arch/arm/boot/dts/overlays/imx296-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/imx327-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/imx378-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/imx462-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/imx477-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi + create mode 100644 arch/arm/boot/dts/overlays/imx477_378.dtsi create mode 100644 arch/arm/boot/dts/overlays/imx519-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/imx519.dtsi + create mode 100644 arch/arm/boot/dts/overlays/imx708-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/imx708.dtsi + create mode 100644 arch/arm/boot/dts/overlays/interludeaudio-analog-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/interludeaudio-digital-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/iqs550-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/irs1125-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/justboom-both-overlay.dts @@ -1085,24 +1381,38 @@ create mode 100644 arch/arm/boot/dts/overlays/media-center-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/merus-amp-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/midi-uart0-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/midi-uart0-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/midi-uart1-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/midi-uart1-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/midi-uart2-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/midi-uart2-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/midi-uart3-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/midi-uart3-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/midi-uart4-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/midi-uart4-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/midi-uart5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/minipitft13-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/miniuart-bt-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/mipi-dbi-spi-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/mlx90640-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/mmc-overlay.dts - create mode 100644 arch/arm/boot/dts/overlays/mpu6050-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/mz61581-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/ov2311-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/ov2311.dtsi create mode 100644 arch/arm/boot/dts/overlays/ov5647-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/ov5647.dtsi + create mode 100644 arch/arm/boot/dts/overlays/ov64a40-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/ov64a40.dtsi create mode 100644 arch/arm/boot/dts/overlays/ov7251-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/ov7251.dtsi create mode 100644 arch/arm/boot/dts/overlays/ov9281-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/ov9281.dtsi create mode 100644 arch/arm/boot/dts/overlays/overlay_map.dts create mode 100644 arch/arm/boot/dts/overlays/papirus-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pca953x-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/pcf857x-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pcie-32bit-dma-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/pcie-32bit-dma-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pibell-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pifacedigital-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pifi-40-overlay.dts @@ -1113,28 +1423,33 @@ create mode 100644 arch/arm/boot/dts/overlays/piscreen-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/piscreen2r-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pisound-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/pisound-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pitft22-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pps-gpio-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/proto-codec-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pwm-ir-tx-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pwm-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/pwm1-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/qca7000-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/qca7000-uart0-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/ramoops-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/ramoops-pi4-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/rotary-encoder-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/rpi-backlight-overlay.dts - create mode 100644 arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts - create mode 100644 arch/arm/boot/dts/overlays/rpi-dac-overlay.dts - create mode 100644 arch/arm/boot/dts/overlays/rpi-display-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/rpi-codeczero-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/rpi-dacplus-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/rpi-dacpro-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/rpi-digiampplus-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/rpi-poe-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/rpi-poe-plus-overlay.dts - create mode 100644 arch/arm/boot/dts/overlays/rpi-proto-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/rpi-sense-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/rpi-sense-v2-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/rpi-tv-overlay.dts - create mode 100644 arch/arm/boot/dts/overlays/rpivid-v4l2-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/sainsmart18-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts @@ -1143,6 +1458,7 @@ create mode 100644 arch/arm/boot/dts/overlays/sc16is752-spi1-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/sdhost-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/sdio-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/sdio-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/seeed-can-fd-hat-v1-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/seeed-can-fd-hat-v2-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts @@ -1160,14 +1476,20 @@ create mode 100644 arch/arm/boot/dts/overlays/spi1-2cs-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/spi1-3cs-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/spi2-1cs-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/spi2-1cs-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/spi2-2cs-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/spi3-1cs-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/spi3-2cs-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/spi5-1cs-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/spi5-2cs-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/ssd1306-overlay.dts @@ -1180,11 +1502,17 @@ create mode 100644 arch/arm/boot/dts/overlays/tc358743-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/tinylcd35-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/tpm-slb9670-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/tpm-slb9673-overlay.dts create mode 100755 arch/arm/boot/dts/overlays/uart0-overlay.dts + create mode 100755 arch/arm/boot/dts/overlays/uart0-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/uart1-overlay.dts + create mode 100755 arch/arm/boot/dts/overlays/uart1-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/uart2-overlay.dts + create mode 100755 arch/arm/boot/dts/overlays/uart2-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/uart3-overlay.dts + create mode 100755 arch/arm/boot/dts/overlays/uart3-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/uart4-overlay.dts + create mode 100755 arch/arm/boot/dts/overlays/uart4-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/uart5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/udrc-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/ugreen-dabboard-overlay.dts @@ -1193,20 +1521,34 @@ create mode 100644 arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/vc4-fkms-v3d-pi4-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel.dtsi + create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel2r-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel4-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel4sq-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dpi-panel-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dpi.dtsi create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dsi-generic-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dsi-ili9881-5inch-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dsi-ili9881-7inch-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dsi-lt070me05000-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dsi-lt070me05000-v2-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-kippah-7inch-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-v3d-pi4-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-v3d-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-vga666-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/vga666-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/vl805-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/w1-gpio-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/w1-gpio-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/w1-gpio-pullup-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/w5500-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/watterott-display-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/waveshare-can-fd-hat-mode-a-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/waveshare-can-fd-hat-mode-b-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/wittypi-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/wm8960-soundcard-overlay.dts create mode 100644 arch/arm/configs/bcm2709_defconfig @@ -1223,59 +1565,123 @@ create mode 100644 arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts create mode 100644 arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dts create mode 100644 arch/arm64/boot/dts/broadcom/bcm2710-rpi-cm3.dts + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2710-rpi-zero-2-w.dts create mode 100644 arch/arm64/boot/dts/broadcom/bcm2710-rpi-zero-2.dts - create mode 100644 arch/arm64/boot/dts/broadcom/bcm2711-rpi-400.dts create mode 100644 arch/arm64/boot/dts/broadcom/bcm2711-rpi-cm4.dts + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2711-rpi-cm4s.dts + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts create mode 120000 arch/arm64/boot/dts/broadcom/bcm283x-rpi-csi1-2lane.dtsi create mode 120000 arch/arm64/boot/dts/broadcom/bcm283x-rpi-lan7515.dtsi create mode 120000 arch/arm64/boot/dts/overlays create mode 100644 arch/arm64/configs/bcm2711_defconfig + create mode 100644 arch/arm64/configs/bcm2712_defconfig create mode 100644 arch/arm64/configs/bcmrpi3_defconfig create mode 100644 drivers/char/broadcom/Kconfig create mode 100644 drivers/char/broadcom/Makefile - create mode 100644 drivers/char/broadcom/bcm2835-gpiomem.c create mode 100644 drivers/char/broadcom/bcm2835_smi_dev.c - create mode 100644 drivers/char/broadcom/rpivid-mem.c create mode 100644 drivers/char/broadcom/vc_mem.c create mode 100644 drivers/char/broadcom/vcio.c - create mode 100644 drivers/clk/clk-allo-dac.c + create mode 100644 drivers/char/raspberrypi-gpiomem.c create mode 100644 drivers/clk/clk-hifiberry-dachd.c create mode 100644 drivers/clk/clk-hifiberry-dacpro.c + create mode 100644 drivers/clk/clk-rp1-sdio.c + create mode 100644 drivers/clk/clk-rp1.c create mode 100644 drivers/dma/bcm2708-dmaengine.c create mode 100644 drivers/gpio/gpio-bcm-virt.c create mode 100644 drivers/gpio/gpio-fsm.c create mode 100644 drivers/gpio/gpio-pwm.c - create mode 100644 drivers/gpu/drm/gud/Kconfig - create mode 100644 drivers/gpu/drm/gud/Makefile - create mode 100644 drivers/gpu/drm/gud/gud_connector.c - create mode 100644 drivers/gpu/drm/gud/gud_drv.c - create mode 100644 drivers/gpu/drm/gud/gud_internal.h - create mode 100644 drivers/gpu/drm/gud/gud_pipe.c + create mode 100644 drivers/gpu/drm/panel/panel-ilitek-ili9806e.c + create mode 100644 drivers/gpu/drm/panel/panel-tdo-y17p.c + create mode 100644 drivers/gpu/drm/panel/panel-waveshare-dsi.c + create mode 100644 drivers/gpu/drm/rp1/Kconfig + create mode 100644 drivers/gpu/drm/rp1/Makefile + create mode 100644 drivers/gpu/drm/rp1/rp1-dpi/Kconfig + create mode 100644 drivers/gpu/drm/rp1/rp1-dpi/Makefile + create mode 100644 drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c + create mode 100644 drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h + create mode 100644 drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_cfg.c + create mode 100644 drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c + create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/Kconfig + create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/Makefile + create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c + create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h + create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c + create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c + create mode 100644 drivers/gpu/drm/rp1/rp1-vec/Kconfig + create mode 100644 drivers/gpu/drm/rp1/rp1-vec/Makefile + create mode 100644 drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c + create mode 100644 drivers/gpu/drm/rp1/rp1-vec/rp1_vec.h + create mode 100644 drivers/gpu/drm/rp1/rp1-vec/rp1_vec_cfg.c + create mode 100644 drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c + create mode 100644 drivers/gpu/drm/rp1/rp1-vec/vec_regs.h + create mode 100644 drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c create mode 100644 drivers/gpu/drm/vc4/vc4_firmware_kms.c create mode 100644 drivers/gpu/drm/vc4/vc_image_types.h - create mode 100644 drivers/hwmon/rpi-poe-fan.c + create mode 100644 drivers/hwmon/rp1-adc.c create mode 100644 drivers/i2c/busses/i2c-bcm2708.c create mode 100644 drivers/input/joystick/rpisense-js.c + create mode 100644 drivers/iommu/bcm2712-iommu-cache.c + create mode 100644 drivers/iommu/bcm2712-iommu.c + create mode 100644 drivers/iommu/bcm2712-iommu.h + create mode 100644 drivers/irqchip/irq-bcm2712-mip.c create mode 100644 drivers/leds/trigger/ledtrig-actpwr.c create mode 100644 drivers/leds/trigger/ledtrig-input.c + create mode 100644 drivers/media/i2c/ad5398_vcm.c + create mode 100644 drivers/media/i2c/arducam-pivariety.c + create mode 100644 drivers/media/i2c/arducam-pivariety.h + create mode 100644 drivers/media/i2c/arducam_64mp.c + create mode 100644 drivers/media/i2c/bu64754.c create mode 100644 drivers/media/i2c/imx477.c create mode 100644 drivers/media/i2c/imx519.c + create mode 100644 drivers/media/i2c/imx708.c create mode 100644 drivers/media/i2c/irs1125.c create mode 100644 drivers/media/i2c/irs1125.h - create mode 100644 drivers/media/i2c/ov9281.c + create mode 100644 drivers/media/i2c/ov2311.c + create mode 100644 drivers/media/i2c/ov64a40.c create mode 100644 drivers/media/platform/bcm2835/Kconfig create mode 100644 drivers/media/platform/bcm2835/Makefile create mode 100644 drivers/media/platform/bcm2835/bcm2835-unicam.c create mode 100644 drivers/media/platform/bcm2835/vc4-regs-unicam.h + create mode 100644 drivers/media/platform/raspberrypi/Kconfig + create mode 100644 drivers/media/platform/raspberrypi/Makefile + create mode 100644 drivers/media/platform/raspberrypi/pisp_be/Kconfig + create mode 100644 drivers/media/platform/raspberrypi/pisp_be/Makefile + create mode 100644 drivers/media/platform/raspberrypi/pisp_be/pisp_be.c + create mode 100644 drivers/media/platform/raspberrypi/pisp_be/pisp_be_config.h + create mode 100644 drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/Kconfig + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/Makefile + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/cfe.c + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/cfe.h + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/cfe_fmts.h + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/csi2.c + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/csi2.h + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/dphy.c + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/dphy.h + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/pisp_common.h + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.h + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe_config.h + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/pisp_statistics.h + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/pisp_types.h + create mode 100644 drivers/mfd/rp1.c create mode 100644 drivers/mfd/rpisense-core.c create mode 100644 drivers/misc/bcm2835_smi.c create mode 100644 drivers/mmc/host/bcm2835-mmc.c create mode 100644 drivers/mmc/host/bcm2835-sdhost.c - create mode 100644 drivers/net/usb/r8153_ecm.c - create mode 100644 drivers/nvmem/rmem.c + create mode 100644 drivers/net/ethernet/realtek/r8169_leds.c + create mode 100644 drivers/nvmem/raspberrypi-otp.c create mode 100644 drivers/of/configfs.c create mode 100644 drivers/perf/raspberrypi_axi_monitor.c + create mode 100644 drivers/pinctrl/bcm/pinctrl-bcm2712.c + create mode 100644 drivers/pinctrl/pinctrl-rp1.c create mode 100644 drivers/power/supply/rpi_poe_power.c + create mode 100644 drivers/pwm/pwm-rp1.c + create mode 100644 drivers/regulator/rpi-panel-v2-regulator.c + create mode 100644 drivers/rtc/rtc-rpi.c create mode 100644 drivers/staging/media/rpivid/Kconfig create mode 100644 drivers/staging/media/rpivid/Makefile create mode 100644 drivers/staging/media/rpivid/rpivid.c @@ -1370,16 +1776,20 @@ create mode 100644 drivers/video/backlight/rpi_backlight.c create mode 100644 drivers/video/fbdev/bcm2708_fb.c create mode 100644 drivers/video/fbdev/rpisense-fb.c - create mode 100644 include/drm/gud.h + create mode 100644 include/dt-bindings/clock/rp1.h create mode 100644 include/dt-bindings/gpio/gpio-fsm.h + create mode 100644 include/dt-bindings/mfd/rp1.h create mode 100644 include/linux/broadcom/bcm2835_smi.h create mode 100644 include/linux/broadcom/vc_mem.h create mode 100644 include/linux/mfd/rpisense/core.h create mode 100644 include/linux/mfd/rpisense/framebuffer.h create mode 100644 include/linux/mfd/rpisense/joystick.h create mode 100644 include/linux/platform_data/dma-bcm2708.h - create mode 100644 include/linux/usb/r8152.h + create mode 100644 include/linux/rp1_platform.h + create mode 100644 include/media/raspberrypi/pisp_common.h + create mode 100644 include/media/raspberrypi/pisp_types.h create mode 100644 include/uapi/linux/bcm2835-isp.h + create mode 100644 net/wireless/certs/debian.hex create mode 100644 sound/soc/bcm/allo-boss-dac.c create mode 100644 sound/soc/bcm/allo-boss2-dac.c create mode 100644 sound/soc/bcm/allo-katana-codec.c @@ -1390,6 +1800,7 @@ create mode 100644 sound/soc/bcm/audioinjector-pi-soundcard.c create mode 100644 sound/soc/bcm/audiosense-pi.c create mode 100644 sound/soc/bcm/chipdip-dac.c + create mode 100644 sound/soc/bcm/dacberry400.c create mode 100644 sound/soc/bcm/digidac1-soundcard.c create mode 100644 sound/soc/bcm/dionaudio_loco-v2.c create mode 100644 sound/soc/bcm/dionaudio_loco.c @@ -1551,289 +1962,238 @@ + bcm2835_isp_black_level bcm2835_isp_geq bcm2835_isp_gamma + bcm2835_isp_denoise bcm2835_isp_sharpen + bcm2835_isp_dpc_mode bcm2835_isp_dpc -diff --git a/Documentation/devicetree/bindings/clock/raspberrypi,firmware-clocks.yaml b/Documentation/devicetree/bindings/clock/raspberrypi,firmware-clocks.yaml -new file mode 100644 -index 000000000000..2047e25700c6 ---- /dev/null -+++ b/Documentation/devicetree/bindings/clock/raspberrypi,firmware-clocks.yaml -@@ -0,0 +1,32 @@ -+# 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 --git a/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml b/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml -index 7ce06f9f9f8e..6e8ac910bdd8 100644 +index 5b35adf34c7b..6d11f5955b51 100644 --- a/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml +++ b/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml -@@ -53,6 +53,24 @@ properties: - - 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 -@@ -90,7 +108,7 @@ required: - - resets - - ddc - --additionalProperties: false -+unevaluatedProperties: false +@@ -14,6 +14,8 @@ properties: + enum: + - brcm,bcm2711-hdmi0 + - brcm,bcm2711-hdmi1 ++ - brcm,bcm2712-hdmi0 ++ - brcm,bcm2712-hdmi1 - examples: - - | + reg: + items: diff --git a/Documentation/devicetree/bindings/display/brcm,bcm2835-dsi0.yaml b/Documentation/devicetree/bindings/display/brcm,bcm2835-dsi0.yaml -index eb44e072b6e5..90ee069ada8d 100644 +index c8b2459d64f6..af638b224619 100644 --- a/Documentation/devicetree/bindings/display/brcm,bcm2835-dsi0.yaml +++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-dsi0.yaml -@@ -20,6 +20,7 @@ properties: - enum: +@@ -21,6 +21,7 @@ properties: + - brcm,bcm2711-dsi1 - brcm,bcm2835-dsi0 - brcm,bcm2835-dsi1 + - brcm,bcm2711-dsi1 reg: maxItems: 1 -diff --git a/Documentation/devicetree/bindings/display/brcm,bcm2835-hdmi.yaml b/Documentation/devicetree/bindings/display/brcm,bcm2835-hdmi.yaml -index f54b4e4808f0..899d8cfa1731 100644 ---- a/Documentation/devicetree/bindings/display/brcm,bcm2835-hdmi.yaml -+++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-hdmi.yaml -@@ -11,24 +11,58 @@ maintainers: - - properties: +diff --git a/Documentation/devicetree/bindings/display/brcm,bcm2835-hvs.yaml b/Documentation/devicetree/bindings/display/brcm,bcm2835-hvs.yaml +index 2e8566f47e63..f91c9dce2a44 100644 +--- a/Documentation/devicetree/bindings/display/brcm,bcm2835-hvs.yaml ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-hvs.yaml +@@ -13,6 +13,7 @@ properties: compatible: -- const: brcm,bcm2835-hdmi -+ enum: -+ - brcm,bcm2835-hdmi -+ - brcm,bcm2711-hdmi0 -+ - brcm,bcm2711-hdmi1 + enum: + - brcm,bcm2711-hvs ++ - brcm,bcm2712-hvs + - brcm,bcm2835-hvs 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 +@@ -36,7 +37,9 @@ if: + properties: + compatible: + contains: +- const: brcm,bcm2711-hvs ++ enum: ++ - brcm,bcm2711-hvs ++ - brcm,bcm2712-hvs - clock-names: -- items: -- - const: pixel -+ oneOf: -+ - items: -+ - const: pixel -+ - const: hdmi -+ - - const: hdmi - - ddc: -@@ -50,15 +84,54 @@ properties: - dma-names: - const: audio-rx + then: + required: +diff --git a/Documentation/devicetree/bindings/display/brcm,bcm2835-pixelvalve0.yaml b/Documentation/devicetree/bindings/display/brcm,bcm2835-pixelvalve0.yaml +index 4e1ba03f6477..6b5b1d3fbc0b 100644 +--- a/Documentation/devicetree/bindings/display/brcm,bcm2835-pixelvalve0.yaml ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-pixelvalve0.yaml +@@ -20,6 +20,9 @@ properties: + - brcm,bcm2711-pixelvalve2 + - brcm,bcm2711-pixelvalve3 + - brcm,bcm2711-pixelvalve4 ++ - brcm,bcm2712-pixelvalve0 ++ - brcm,bcm2712-pixelvalve1 ++ - brcm,bcm2712-pixelvalve2 -+ 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> -@@ -76,4 +149,31 @@ examples: - clock-names = "pixel", "hdmi"; - }; + reg: + maxItems: 1 +diff --git a/Documentation/devicetree/bindings/display/brcm,bcm2835-txp.yaml b/Documentation/devicetree/bindings/display/brcm,bcm2835-txp.yaml +index bb186197e471..16f45afd2bad 100644 +--- a/Documentation/devicetree/bindings/display/brcm,bcm2835-txp.yaml ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-txp.yaml +@@ -11,7 +11,10 @@ maintainers: -+ - | -+ 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>; -+ }; -+ - ... + properties: + compatible: +- const: brcm,bcm2835-txp ++ enum: ++ - brcm,bcm2712-mop ++ - brcm,bcm2712-moplet ++ - brcm,bcm2835-txp + + reg: + maxItems: 1 diff --git a/Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml b/Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml -index 49a5e041aa49..eac739a812f5 100644 +index 49a5e041aa49..2aa9d5d2afff 100644 --- a/Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml +++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml -@@ -21,6 +21,11 @@ properties: +@@ -18,6 +18,7 @@ properties: + compatible: + enum: + - brcm,bcm2711-vc5 ++ - brcm,bcm2712-vc6 - 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 --git a/Documentation/devicetree/bindings/display/brcm,bcm2835-vec.yaml b/Documentation/devicetree/bindings/display/brcm,bcm2835-vec.yaml -index d900cc57b4ec..4d8a6b615e5b 100644 ---- a/Documentation/devicetree/bindings/display/brcm,bcm2835-vec.yaml -+++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-vec.yaml -@@ -11,7 +11,9 @@ maintainers: +diff --git a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml +index e7ab6224b52e..9bed316f6582 100644 +--- a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml ++++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml +@@ -20,6 +20,8 @@ properties: + - feixin,k101-im2byl02 + - tdo,tl050hdv35 + - wanchanglong,w552946aba ++ - raspberrypi,dsi-5inch ++ - raspberrypi,dsi-7inch + - const: ilitek,ili9881c - properties: - compatible: -- const: brcm,bcm2835-vec + backlight: true +diff --git a/Documentation/devicetree/bindings/display/panel/panel-dsi.yaml b/Documentation/devicetree/bindings/display/panel/panel-dsi.yaml +new file mode 100644 +index 000000000000..0576541d9567 +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/panel/panel-dsi.yaml +@@ -0,0 +1,118 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/panel/panel-dsi.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Generic MIPI DSI Panel ++ ++maintainers: ++ - Timon Skerutsch <kernel@diodes-delight.com> ++ ++allOf: ++ - $ref: panel-common.yaml# ++ ++properties: ++ compatible: ++ description: ++ Shall contain a panel specific compatible and "panel-dsi" ++ in that order. ++ items: ++ - {} ++ - const: panel-dsi ++ ++ dsi-color-format: ++ description: | ++ The color format used by the panel. Only DSI supported formats are allowed. + enum: -+ - brcm,bcm2835-vec -+ - brcm,bcm2711-vec - - reg: - maxItems: 1 ++ - RGB888 ++ - RGB666 ++ - RGB666_PACKED ++ - RGB565 ++ ++ port: ++ $ref: /schemas/graph.yaml#/$defs/port-base ++ unevaluatedProperties: false ++ description: ++ Panel MIPI DSI input ++ ++ properties: ++ endpoint: ++ $ref: /schemas/media/video-interfaces.yaml# ++ unevaluatedProperties: false ++ ++ properties: ++ data-lanes: true ++ ++ required: ++ - data-lanes ++ ++ mode: ++ description: | ++ DSI mode flags. See DSI Specs for details. ++ These are driver independent features of the DSI bus. ++ items: ++ - const: MODE_VIDEO ++ - const: MODE_VIDEO_BURST ++ - const: MODE_VIDEO_SYNC_PULSE ++ - const: MODE_VIDEO_AUTO_VERT ++ - const: MODE_VIDEO_HSE ++ - const: MODE_VIDEO_NO_HFP ++ - const: MODE_VIDEO_NO_HBP ++ - const: MODE_VIDEO_NO_HSA ++ - const: MODE_VSYNC_FLUSH ++ - const: MODE_NO_EOT_PACKET ++ - const: CLOCK_NON_CONTINUOUS ++ - const: MODE_LPM ++ - const: HS_PKT_END_ALIGNED ++ ++ reg: true ++ backlight: true ++ enable-gpios: true ++ width-mm: true ++ height-mm: true ++ panel-timing: true ++ power-supply: true ++ reset-gpios: true ++ ddc-i2c-bus: true ++ ++required: ++ - panel-timing ++ - reg ++ - power-supply ++ - dsi-color-format ++ - port ++ ++additionalProperties: false ++ ++examples: ++ - | ++ panel { ++ compatible = "panel-mfgr,generic-dsi-panel","panel-dsi"; ++ power-supply = <&vcc_supply>; ++ backlight = <&backlight>; ++ dsi-color-format = "RGB888"; ++ reg = <0>; ++ mode = "MODE_VIDEO", "MODE_VIDEO_BURST", "MODE_NO_EOT_PACKET"; ++ ++ port { ++ panel_dsi_port: endpoint { ++ data-lanes = <1 2>; ++ remote-endpoint = <&dsi_out>; ++ }; ++ }; ++ ++ panel-timing { ++ clock-frequency = <9200000>; ++ hactive = <800>; ++ vactive = <480>; ++ hfront-porch = <8>; ++ hback-porch = <4>; ++ hsync-len = <41>; ++ vback-porch = <2>; ++ vfront-porch = <4>; ++ vsync-len = <10>; ++ }; ++ }; ++ ++... diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml -index edb53ab0d9eb..f474cc0feed6 100644 +index 25b4589d4a58..209e8475b0a5 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml -@@ -133,6 +133,8 @@ properties: +@@ -158,6 +158,8 @@ properties: - frida,frd350h54004 # FriendlyELEC HD702E 800x1280 LCD panel - friendlyarm,hd702e @@ -1842,7 +2202,7 @@ # GiantPlus GPG48273QS5 4.3" (480x272) WQVGA TFT LCD panel - giantplus,gpg48273qs5 # GiantPlus GPM940B0 3.0" QVGA TFT LCD panel -@@ -147,6 +149,8 @@ properties: +@@ -172,6 +174,8 @@ properties: - ivo,m133nwf4-r0 # Innolux AT043TN24 4.3" WQVGA TFT LCD panel - innolux,at043tn24 @@ -1850,68 +2210,79 @@ + - innolux,at056tn53v1 # Innolux AT070TN92 7.0" WQVGA TFT LCD panel - innolux,at070tn92 - # Innolux G070Y2-L01 7" WVGA (800x480) TFT LCD panel -diff --git a/Documentation/devicetree/bindings/hwmon/rpi-poe-fan.txt b/Documentation/devicetree/bindings/hwmon/rpi-poe-fan.txt + # Innolux G070ACE-L01 7" WVGA (800x480) TFT LCD panel +diff --git a/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml b/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml +index dae55b8a267b..97c9afe7b4f8 100644 +--- a/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml ++++ b/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml +@@ -16,6 +16,7 @@ properties: + + compatible: + enum: ++ - brcm,2712-v3d + - brcm,2711-v3d + - brcm,7268-v3d + - brcm,7278-v3d +diff --git a/Documentation/devicetree/bindings/hwmon/microchip,emc2305.yaml b/Documentation/devicetree/bindings/hwmon/microchip,emc2305.yaml new file mode 100644 -index 000000000000..c71f8569a4dc +index 000000000000..efdc3cecb03d --- /dev/null -+++ b/Documentation/devicetree/bindings/hwmon/rpi-poe-fan.txt -@@ -0,0 +1,55 @@ -+Bindings for the Raspberry Pi PoE HAT fan ++++ b/Documentation/devicetree/bindings/hwmon/microchip,emc2305.yaml +@@ -0,0 +1,54 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- + -+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 ++$id: http://devicetree.org/schemas/hwmon/emc2305.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# + -+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"; -+ }; ++title: Microchip EMC2301|2|3|5 RPM-based PWM Fan Speed Controller + -+ 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>; -+ }; -+ }; -+ }; -+ }; ++properties: ++ compatible: ++ enum: ++ - microchip,emc2305 ++ - microchip,emc2301 ++ emc2305,pwm-min: ++ description: ++ Min pwm of emc2305 ++ maxItems: 1 ++ emc2305,pwm-max: ++ description: ++ Max pwm of emc2305 ++ maxItems: 1 ++ emc2305,pwm-channel: ++ description: ++ Max number of pwm channels ++ maxItems: 1 ++ emcs205,max-state: ++ description: ++ maxItems: 1 ++ emc2305,cooling-levels: ++ description: ++ Quantity of cooling level state. ++ maxItems: 1 ++ ++required: ++ - compatible ++ ++optional: ++ - emc2305,min-pwm ++ - emc2305,max-pwm ++ - emc2305,pwm-channels ++ - emc2305,cooling-levels ++ ++additionalProperties: false ++ ++examples: ++ - | ++ fan { ++ compatible = "microchip,emc2305"; ++ emc2305,pwm-min = <0>; ++ emc2305,pwm-max = <255>; ++ emc2305,pwm-channel = <5> ++ emc2305,cooling-levels = <10>; ++ }; diff --git a/Documentation/devicetree/bindings/media/bcm2835-unicam.txt b/Documentation/devicetree/bindings/media/bcm2835-unicam.txt new file mode 100644 index 000000000000..164d0377dcd2 @@ -2003,93 +2374,311 @@ + }; + }; + }; -diff --git a/Documentation/devicetree/bindings/media/i2c/imx219.txt b/Documentation/devicetree/bindings/media/i2c/imx219.txt +diff --git a/Documentation/devicetree/bindings/media/i2c/ad5398.txt b/Documentation/devicetree/bindings/media/i2c/ad5398.txt new file mode 100644 -index 000000000000..a02f1ce1e120 +index 000000000000..446ac9717598 --- /dev/null -+++ b/Documentation/devicetree/bindings/media/i2c/imx219.txt -@@ -0,0 +1,59 @@ -+* 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. ++++ b/Documentation/devicetree/bindings/media/i2c/ad5398.txt +@@ -0,0 +1,20 @@ ++* Analog Devices AD5398 autofocus coil + +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. ++ - compatible: Must contain one of: ++ - "adi,ad5398" + -+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. ++ - reg: I2C slave address + -+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) ++ - VANA-supply: supply of voltage for VANA pin + +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>; -+ }; ++ ad5398: coil@c { ++ compatible = "adi,ad5398"; ++ reg = <0x0c>; + -+ port { -+ sensor_out: endpoint { -+ remote-endpoint = <&csiss_in>; -+ clock-lanes = <0>; -+ data-lanes = <1 2>; -+ }; -+ }; -+ }; -diff --git a/Documentation/devicetree/bindings/media/i2c/imx290.txt b/Documentation/devicetree/bindings/media/i2c/imx290.txt -index a3cc21410f7c..294e63650d9e 100644 ---- a/Documentation/devicetree/bindings/media/i2c/imx290.txt -+++ b/Documentation/devicetree/bindings/media/i2c/imx290.txt -@@ -1,13 +1,14 @@ - * 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". ++ VANA-supply = <&vaux4>; ++ }; ++ +diff --git a/Documentation/devicetree/bindings/media/i2c/arducam,64mp.yaml b/Documentation/devicetree/bindings/media/i2c/arducam,64mp.yaml +new file mode 100644 +index 000000000000..b71a19782f97 +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/i2c/arducam,64mp.yaml +@@ -0,0 +1,115 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/media/i2c/arducam,64mp.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Arducam 1/1.7-Inch 64Mpixel CMOS Digital Image Sensor ++ ++maintainers: ++ - Lee Jackson <info@arducam.com> ++ ++description: |- ++ The Arducam 1/1.7-Inch 64Mpixel CMOS active pixel digital image sensor ++ with an active array size of 9248 x 6944. 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 can be configured for operation ++ with either 2 or 4 data lanes. ++ ++properties: ++ compatible: ++ const: arducam,64mp ++ ++ 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>. ++ anyOf: ++ - items: ++ - const: 1 ++ - const: 2 ++ - items: ++ - const: 1 ++ - const: 2 ++ - const: 3 ++ - const: 4 ++ ++ clock-noncontinuous: true ++ ++ 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>; ++ ++ arducam_64mp: sensor@1a { ++ compatible = "arducam,64mp"; ++ reg = <0x1a>; ++ clocks = <&arducam_64mp_clk>; ++ VANA-supply = <&arducam_64mp_vana>; /* 2.8v */ ++ VDIG-supply = <&arducam_64mp_vdig>; /* 1.05v */ ++ VDDL-supply = <&arducam_64mp_vddl>; /* 1.8v */ ++ ++ port { ++ arducam_64mp_0: endpoint { ++ remote-endpoint = <&csi1_ep>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = /bits/ 64 <456000000>; ++ }; ++ }; ++ }; ++ }; ++ ++... +diff --git a/Documentation/devicetree/bindings/media/i2c/arducam-pivariety.yaml b/Documentation/devicetree/bindings/media/i2c/arducam-pivariety.yaml +new file mode 100644 +index 000000000000..92bf4ff32eb4 +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/i2c/arducam-pivariety.yaml +@@ -0,0 +1,112 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/media/i2c/arducam-pivariety.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Arducam Pivariety Series CMOS Digital Image Sensor ++ ++maintainers: ++ - Lee Jackson <info@arducam.com> ++ ++description: |- ++ Arducam Pivariety series cameras make compatibility layers for various CMOS ++ sensors and provide a unified command interface. It is programmable through ++ I2C interface. The I2C address is fixed to 0x0C. Image data is sent through ++ MIPI CSI-2, which is configured as either 1, 2 or 4 data lanes. ++ ++properties: ++ compatible: ++ const: arducam,arducam-pivariety ++ ++ 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>; ++ ++ arducam_pivariety: sensor@0c { ++ compatible = "arducam,arducam-pivariety"; ++ reg = <0x0c>; ++ clocks = <&arducam_pivariety_clk>; ++ VANA-supply = <&arducam_pivariety_vana>; /* 2.8v */ ++ VDIG-supply = <&arducam_pivariety_vdig>; /* 1.05v */ ++ VDDL-supply = <&arducam_pivariety_vddl>; /* 1.8v */ ++ ++ port { ++ arducam_pivariety_0: endpoint { ++ remote-endpoint = <&csi1_ep>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = /bits/ 64 <493500000>; ++ }; ++ }; ++ }; ++ }; ++ ++... +diff --git a/Documentation/devicetree/bindings/media/i2c/dongwoon,dw9807-vcm.yaml b/Documentation/devicetree/bindings/media/i2c/dongwoon,dw9807-vcm.yaml +index aae246ca3fcf..6de07543e973 100644 +--- a/Documentation/devicetree/bindings/media/i2c/dongwoon,dw9807-vcm.yaml ++++ b/Documentation/devicetree/bindings/media/i2c/dongwoon,dw9807-vcm.yaml +@@ -5,22 +5,32 @@ + $id: http://devicetree.org/schemas/media/i2c/dongwoon,dw9807-vcm.yaml# + $schema: http://devicetree.org/meta-schemas/core.yaml# + +-title: Dongwoon Anatech DW9807 voice coil lens driver ++title: Dongwoon Anatech DW9807 and DW9817 voice coil lens driver + + maintainers: + - Sakari Ailus <sakari.ailus@linux.intel.com> + + description: | + DW9807 is a 10-bit DAC with current sink capability. It is intended for +- controlling voice coil lenses. ++ controlling voice coil lenses. The output drive is 0-100mA. ++ DW9817 is very similar as a 10-bit DAC with current sink capability, ++ however the output drive is a bidirection -100 to +100mA. ++ + + properties: + compatible: +- const: dongwoon,dw9807-vcm ++ items: ++ - enum: ++ - dongwoon,dw9807-vcm ++ - dongwoon,dw9817-vcm + + reg: + maxItems: 1 + ++ VDD-supply: ++ description: ++ Definition of the regulator used as VDD power supply to the driver. ++ + required: + - compatible + - reg diff --git a/Documentation/devicetree/bindings/media/i2c/imx378.yaml b/Documentation/devicetree/bindings/media/i2c/imx378.yaml new file mode 100644 index 000000000000..f832b4bfab93 @@ -2501,6 +3090,331 @@ + }; + }; + }; +diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml +new file mode 100644 +index 000000000000..15fbe86bba10 +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml +@@ -0,0 +1,98 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/media/i2c/ovti,ov64a40.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: OmniVision OV64A40 Image Sensor ++ ++maintainers: ++ - Jacopo Mondi <jacopo.mondi@ideasonboard.com> ++ ++allOf: ++ - $ref: /schemas/media/video-interface-devices.yaml# ++ ++properties: ++ compatible: ++ const: ovti,ov64a40 ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ avdd-supply: ++ description: Analog voltage supply, 2.8 volts ++ ++ dvdd-supply: ++ description: Digital core voltage supply, 1.1 volts ++ ++ dovdd-supply: ++ description: Digital I/O voltage supply, 1.8 volts ++ ++ powerdown-gpios: ++ maxItems: 1 ++ ++ reset-gpios: ++ maxItems: 1 ++ ++ port: ++ $ref: /schemas/graph.yaml#/$defs/port-base ++ additionalProperties: false ++ ++ properties: ++ endpoint: ++ $ref: /schemas/media/video-interfaces.yaml# ++ additionalProperties: false ++ ++ properties: ++ bus-type: ++ enum: ++ - 1 # MIPI CSI-2 C-PHY ++ - 4 # MIPI CSI-2 D-PHY ++ data-lanes: true ++ link-frequencies: true ++ clock-noncontinuous: true ++ remote-endpoint: true ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - port ++ ++unevaluatedProperties: false ++ ++examples: ++ - | ++ #include <dt-bindings/gpio/gpio.h> ++ ++ i2c { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ camera@36 { ++ compatible = "ovti,ov64a40"; ++ reg = <0x36>; ++ clocks = <&camera_clk>; ++ dovdd-supply = <&vgen4_reg>; ++ avdd-supply = <&vgen3_reg>; ++ dvdd-supply = <&vgen2_reg>; ++ powerdown-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; ++ reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; ++ rotation = <180>; ++ orientation = <2>; ++ ++ port { ++ endpoint { ++ remote-endpoint = <&mipi_csi2_in>; ++ bus-type = <4>; ++ data-lanes = <1 2 3 4>; ++ link-frequencies = /bits/ 64 <456000000>; ++ }; ++ }; ++ }; ++ }; ++ ++... +diff --git a/Documentation/devicetree/bindings/media/i2c/rohm,bu64754.yaml b/Documentation/devicetree/bindings/media/i2c/rohm,bu64754.yaml +new file mode 100644 +index 000000000000..22da4a46bb0c +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/i2c/rohm,bu64754.yaml +@@ -0,0 +1,48 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++# Copyright (C) 2023 Ideas on Board Oy. ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/media/i2c/rohm,bu64754.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: ROHM BU64754 Actuator Driver for Camera Autofocus ++ ++maintainers: ++ - Kieran Bingham <kieran.bingham@ideasonboard.com> ++ ++description: | ++ The BU64754GWZ is an actuator driver IC which can control the actuator ++ position precisely using an internal Hall Sensor. ++ ++properties: ++ compatible: ++ items: ++ - enum: ++ - rohm,bu64754 ++ ++ reg: ++ maxItems: 1 ++ ++ vdd-supply: ++ description: ++ Definition of the regulator used as VDD power supply to the driver. ++ ++required: ++ - compatible ++ - reg ++ ++additionalProperties: false ++ ++examples: ++ - | ++ i2c { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ lens@76 { ++ compatible = "rohm,bu64754"; ++ reg = <0x76>; ++ vdd-supply = <&cam1_reg>; ++ }; ++ }; ++... +diff --git a/Documentation/devicetree/bindings/media/i2c/imx258.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml +similarity index 90% +rename from Documentation/devicetree/bindings/media/i2c/imx258.yaml +rename to Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml +index 80d24220baa0..3415b26b5991 100644 +--- a/Documentation/devicetree/bindings/media/i2c/imx258.yaml ++++ b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + %YAML 1.2 + --- +-$id: http://devicetree.org/schemas/media/i2c/imx258.yaml# ++$id: http://devicetree.org/schemas/media/i2c/sony,imx258.yaml# + $schema: http://devicetree.org/meta-schemas/core.yaml# + + title: Sony IMX258 13 Mpixel CMOS Digital Image Sensor +@@ -14,10 +14,15 @@ description: |- + type stacked image sensor with a square pixel array of size 4208 x 3120. It + is programmable through I2C interface. Image data is sent through MIPI + CSI-2. ++ There are a number of variants of the sensor which cannot be detected at ++ runtime, so multiple compatible strings are required to differentiate these. + + properties: + compatible: +- const: sony,imx258 ++ oneOf: ++ - enum: ++ - sony,imx258 ++ - sony,imx258-pdaf + + assigned-clocks: true + assigned-clock-parents: true +diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml +new file mode 100644 +index 000000000000..286aad2e8c69 +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml +@@ -0,0 +1,128 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/media/i2c/sony,imx708.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Sony 1/2.3-Inch 12Mpixel CMOS Digital Image Sensor ++ ++maintainers: ++ - Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com> ++ ++description: |- ++ The Sony IMX708 is a 1/2.3-inch CMOS active pixel digital image sensor ++ with an active array size of 4608H x 2592V. 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,imx708 ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ clock-names: ++ description: Input clock (6 to 27 MHz) ++ items: ++ - const: inck ++ ++ vdig-supply: ++ description: ++ Digital I/O voltage supply, 1.1 volts ++ ++ vana1-supply: ++ description: ++ Analog1 voltage supply, 2.8 volts ++ ++ vana2-supply: ++ description: ++ Analog2 voltage supply, 1.8 volts ++ ++ vddl-supply: ++ description: ++ Digital core voltage supply, 1.8 volts ++ ++ reset-gpios: ++ description: Sensor reset (XCLR) GPIO ++ maxItems: 1 ++ ++ port: ++ $ref: /schemas/graph.yaml#/$defs/port-base ++ description: | ++ Video output port ++ ++ properties: ++ endpoint: ++ $ref: /schemas/media/video-interfaces.yaml# ++ unevaluatedProperties: false ++ ++ properties: ++ data-lanes: ++ anyOf: ++ - items: ++ - const: 1 ++ - const: 2 ++ - items: ++ - const: 1 ++ - const: 2 ++ - const: 3 ++ - const: 4 ++ ++ link-frequencies: true ++ ++ required: ++ - data-lanes ++ - link-frequencies ++ ++ additionalProperties: false ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - vdig-supply ++ - vana1-supply ++ - vana2-supply ++ - vddl-supply ++ - port ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include <dt-bindings/gpio/gpio.h> ++ ++ i2c { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ imx708: camera-sensor@1a { ++ compatible = "sony,imx708"; ++ reg = <0x1a>; ++ ++ clocks = <&clk 90>; ++ clock-names = "inck"; ++ ++ vdig-supply = <&camera_vdig>; ++ vana1-supply = <&camera_vana1>; ++ vana2-supply = <&camera_vana2>; ++ vddl-supply = <&camera_vddl>; ++ ++ reset-gpios = <&gpio 35 GPIO_ACTIVE_LOW>; ++ ++ port { ++ imx708_ep: endpoint { ++ data-lanes = <1 2>; ++ link-frequencies = /bits/ 64 <450000000>; ++ remote-endpoint = <&csi_ep>; ++ }; ++ }; ++ }; ++ }; ++... diff --git a/Documentation/devicetree/bindings/media/rpivid_hevc.yaml b/Documentation/devicetree/bindings/media/rpivid_hevc.yaml new file mode 100644 index 000000000000..ce6b81a10303 @@ -2656,6 +3570,63 @@ + brcm,pull = <2 2 2 2 2 2 0 0 0 0 0 0 0 0>; +}; + +diff --git a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +index a43eb837f8da..fb0eb5bb53a5 100644 +--- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml ++++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +@@ -16,6 +16,7 @@ allOf: + properties: + compatible: + enum: ++ - raspberrypi,rp1-dwcmshc + - rockchip,rk3568-dwcmshc + - rockchip,rk3588-dwcmshc + - snps,dwcmshc-sdhci +@@ -34,6 +35,8 @@ properties: + - description: axi clock for rockchip specified + - description: block clock for rockchip specified + - description: timer clock for rockchip specified ++ - description: timeout clock for rp1 specified ++ - description: sdio clock generator for rp1 specified + + + clock-names: +@@ -44,6 +47,8 @@ properties: + - const: axi + - const: block + - const: timer ++ - const: timeout ++ - const: sdio + + resets: + maxItems: 5 +diff --git a/Documentation/devicetree/bindings/net/cdns,macb.yaml b/Documentation/devicetree/bindings/net/cdns,macb.yaml +index bf8894a0257e..a9edfe6c1254 100644 +--- a/Documentation/devicetree/bindings/net/cdns,macb.yaml ++++ b/Documentation/devicetree/bindings/net/cdns,macb.yaml +@@ -131,6 +131,22 @@ properties: + Node containing PHY children. If this node is not present, then PHYs will + be direct children. + ++ cdns,aw2w-max-pipe: ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ description: ++ Maximum number of outstanding AXI write requests ++ ++ cdns,ar2r-max-pipe: ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ description: ++ Maximum number of outstanding AXI read requests ++ ++ cdns,use-aw2b-fill: ++ type: boolean ++ description: ++ If set, the maximum number of outstanding write transactions operates ++ between the AW to B AXI channel, instead of the AW to W AXI channel. ++ + patternProperties: + "^ethernet-phy@0-9a-f$": + type: object diff --git a/Documentation/devicetree/bindings/net/microchip,lan78xx.txt b/Documentation/devicetree/bindings/net/microchip,lan78xx.txt index 11a679530ae6..104768b85bbc 100644 --- a/Documentation/devicetree/bindings/net/microchip,lan78xx.txt @@ -2670,61 +3641,25 @@ Example: -diff --git a/Documentation/devicetree/bindings/nvmem/rmem.yaml b/Documentation/devicetree/bindings/nvmem/rmem.yaml -new file mode 100644 -index 000000000000..29b53871aa02 ---- /dev/null -+++ b/Documentation/devicetree/bindings/nvmem/rmem.yaml -@@ -0,0 +1,49 @@ -+# 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 +diff --git a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml +index 7e15aae7d69e..ad313d76eb7c 100644 +--- a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml ++++ b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml +@@ -77,6 +77,14 @@ properties: + minItems: 1 + maxItems: 3 + ++ brcm,tperst-clk-ms: ++ category: optional ++ type: int ++ description: u32 giving the number of milliseconds to extend ++ the time between internal release of fundamental reset and ++ the deassertion of the external PERST# pin. This has the ++ effect of increasing the Tperst_clk phase of link init. + -+ 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; -+ }; -+ }; -+ -+... + required: + - compatible + - reg diff --git a/Documentation/devicetree/bindings/pci/brcmstb-pcie.txt b/Documentation/devicetree/bindings/pci/brcmstb-pcie.txt new file mode 100644 index 000000000000..a1a9ad5e70ca @@ -2791,24 +3726,132 @@ + linux,pci-domain = <0>; + }; diff --git a/Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt b/Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt -index 3e56c1b34a4c..76dd7b06e26a 100644 ---- a/Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt +new file mode 100644 +index 000000000000..76dd7b06e26a +--- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt -@@ -31,6 +31,7 @@ Optional properties: - - 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. +@@ -0,0 +1,42 @@ ++Driver a GPIO line that can be used to turn the power off. ++ ++The driver supports both level triggered and edge triggered power off. ++At driver load time, the driver will request the given gpio line and ++install a handler to power off the system. If the optional properties ++'input' is not found, the GPIO line will be driven in the inactive ++state. Otherwise its configured as an input. ++ ++When the power-off handler is called, the gpio is configured as an ++output, and drive active, so triggering a level triggered power off ++condition. This will also cause an inactive->active edge condition, so ++triggering positive edge triggered power off. After a delay of 100ms, ++the GPIO is set to inactive, thus causing an active->inactive edge, ++triggering negative edge triggered power off. After another 100ms ++delay the GPIO is driver active again. If the power is still on and ++the CPU still running after a 3000ms delay, a WARN_ON(1) is emitted. ++ ++Required properties: ++- compatible : should be "gpio-poweroff". ++- gpios : The GPIO to set high/low, see "gpios property" in ++ Documentation/devicetree/bindings/gpio/gpio.txt. If the pin should be ++ low to power down the board set it to "Active Low", otherwise set ++ gpio to "Active High". ++ ++Optional properties: ++- input : Initially configure the GPIO line as an input. Only reconfigure ++ it to an output when the power-off handler is called. If this optional ++ property is not specified, the GPIO is initialized as an output in its ++ inactive state. ++- active-delay-ms: Delay (default 100) to wait after driving gpio active ++- 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: - ++ ++Examples: ++ ++gpio-poweroff { ++ compatible = "gpio-poweroff"; ++ gpios = <&gpio 4 0>; ++ timeout-ms = <3000>; ++}; +diff --git a/Documentation/devicetree/bindings/pwm/pwm-rp1.yaml b/Documentation/devicetree/bindings/pwm/pwm-rp1.yaml +new file mode 100644 +index 000000000000..db9d7085f1c3 +--- /dev/null ++++ b/Documentation/devicetree/bindings/pwm/pwm-rp1.yaml +@@ -0,0 +1,38 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/pwm/pwm-rp1.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Raspberry Pi RP1 PWM controller ++ ++maintainers: ++ - Naushir Patuck <naush@raspberrypi.com> ++ ++properties: ++ compatible: ++ enum: ++ - raspberrypi,rp1-pwm ++ ++ reg: ++ maxItems: 1 ++ ++ "#pwm-cells": ++ const: 3 ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - "#pwm-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ pwm0: pwm@98000 { ++ compatible = "raspberrypi,rp1-pwm"; ++ reg = <0x0 0x98000 0x0 0x100>; ++ clocks = <&rp1_sys>; ++ #pwm-cells = <3>; ++ }; +diff --git a/Documentation/devicetree/bindings/rtc/rtc-rpi.txt b/Documentation/devicetree/bindings/rtc/rtc-rpi.txt +new file mode 100644 +index 000000000000..ed0d0d0a8464 +--- /dev/null ++++ b/Documentation/devicetree/bindings/rtc/rtc-rpi.txt +@@ -0,0 +1,22 @@ ++* Raspberry Pi RTC ++ ++This is a Linux interface to an RTC managed by firmware, hence it's ++virtual from a Linux perspective. ++ ++The interface uses the firmware mailbox api to access the RTC registers. ++ ++Required properties: ++compatible: should be "raspberrypi,rpi-rtc" ++firmware: Reference to the RPi firmware device node. ++ ++Optional property: ++trickle-charge-microvolt: specify a trickle charge voltage for the backup ++ battery in microvolts. ++ ++Example: ++ ++ rpi_rtc: rpi_rtc { ++ compatible = "raspberrypi,rpi-rtc"; ++ firmware = <&firmware>; ++ trickle-charge-microvolt = <3000000>; ++ }; diff --git a/Documentation/devicetree/bindings/serial/pl011.yaml b/Documentation/devicetree/bindings/serial/pl011.yaml -index c23c93b400f0..5e1d6483b2a9 100644 +index 9571041030b7..f34e2f66d1a3 100644 --- a/Documentation/devicetree/bindings/serial/pl011.yaml +++ b/Documentation/devicetree/bindings/serial/pl011.yaml -@@ -98,6 +98,12 @@ properties: - $ref: /schemas/types.yaml#/definitions/uint32 - default: 3000 +@@ -101,6 +101,12 @@ properties: + on the device. + enum: 1, 4 + cts-event-workaround: + description: @@ -2819,6 +3862,74 @@ required: - compatible - reg +diff --git a/Documentation/devicetree/bindings/sound/pcm512x.txt b/Documentation/devicetree/bindings/sound/pcm512x.txt +index 3aae3b41bd8e..77006a4aec4a 100644 +--- a/Documentation/devicetree/bindings/sound/pcm512x.txt ++++ b/Documentation/devicetree/bindings/sound/pcm512x.txt +@@ -1,12 +1,12 @@ +-PCM512x audio CODECs ++PCM512x and TAS575x audio CODECs/amplifiers + + These devices support both I2C and SPI (configured with pin strapping +-on the board). ++on the board). The TAS575x devices only support I2C. + + Required properties: + +- - compatible : One of "ti,pcm5121", "ti,pcm5122", "ti,pcm5141" or +- "ti,pcm5142" ++ - compatible : One of "ti,pcm5121", "ti,pcm5122", "ti,pcm5141", ++ "ti,pcm5142", "ti,tas5754" or "ti,tas5756" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. +@@ -25,6 +25,7 @@ Optional properties: + through <6>. The device will be configured for clock input on the + given pll-in pin and PLL output on the given pll-out pin. An + external connection from the pll-out pin to the SCLK pin is assumed. ++ Caution: the TAS-desvices only support gpios 1,2 and 3 + + Examples: + +diff --git a/Documentation/devicetree/bindings/spi/spi-gpio.yaml b/Documentation/devicetree/bindings/spi/spi-gpio.yaml +index 9ce1df93d4c3..d911c203fa45 100644 +--- a/Documentation/devicetree/bindings/spi/spi-gpio.yaml ++++ b/Documentation/devicetree/bindings/spi/spi-gpio.yaml +@@ -43,6 +43,10 @@ properties: + with no chip select is connected. + $ref: /schemas/types.yaml#/definitions/uint32 + ++ sck-idle-input: ++ description: Make SCK an input when inactive. ++ type: boolean ++ + # Deprecated properties + gpio-sck: false + gpio-miso: false +diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml +index a696f23730d3..d516979b0681 100644 +--- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml ++++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml +@@ -233,12 +233,17 @@ properties: + + snps,parkmode-disable-ss-quirk: + description: +- When set, all SuperSpeed bus instances in park mode are disabled. ++ When set, disable park mode for all Superspeed bus instances. + type: boolean + + snps,parkmode-disable-hs-quirk: + description: +- When set, all HighSpeed bus instances in park mode are disabled. ++ When set, disable park mode for all Highspeed bus instances. ++ type: boolean ++ ++ snps,parkmode-disable-fsls-quirk: ++ description: ++ When set, disable park mode for all Full/Lowspeed bus instances. + type: boolean + + snps,dis_metastability_quirk: diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt new file mode 100644 index 000000000000..f8d32547195b @@ -3289,19 +4400,28 @@ +zte ZTE Corp. +zyxel ZyXEL Communications Corp. diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml -index 2735be1a8470..e8a98ec7632d 100644 +index 133cfb2bb05c..d5805b33bd0e 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml -@@ -159,6 +159,8 @@ patternProperties: +@@ -133,6 +133,8 @@ patternProperties: + description: arcx Inc. / Archronix Inc. + "^aries,.*": + description: Aries Embedded GmbH ++ "^arducam,.*": ++ description: Arducam Technology co., Ltd. + "^arm,.*": + description: ARM Ltd. + "^armadeus,.*": +@@ -196,6 +198,8 @@ patternProperties: description: Beckhoff Automation GmbH & Co. KG "^bitmain,.*": description: Bitmain Technologies + "^blokaslabs,.*": + description: Vilniaus Blokas UAB + "^blutek,.*": + description: BluTek Power "^boe,.*": - description: BOE Technology Group Co., Ltd. - "^bosch,.*": -@@ -399,6 +401,8 @@ patternProperties: +@@ -504,6 +508,8 @@ patternProperties: description: General Electric Company "^geekbuying,.*": description: GeekBuying @@ -3347,166 +4467,77 @@ +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 --git a/Documentation/hwmon/rpi-poe-fan b/Documentation/hwmon/rpi-poe-fan -new file mode 100644 -index 000000000000..9182ab633993 ---- /dev/null -+++ b/Documentation/hwmon/rpi-poe-fan -@@ -0,0 +1,15 @@ -+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 --git a/Documentation/driver-api/pwm.rst b/Documentation/driver-api/pwm.rst +index 3fdc95f7a1d1..c68ed828fba9 100644 +--- a/Documentation/driver-api/pwm.rst ++++ b/Documentation/driver-api/pwm.rst +@@ -41,11 +41,20 @@ the getter, devm_pwm_get() and devm_fwnode_pwm_get(), also exist. + + After being requested, a PWM has to be configured using:: + +- int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state); ++ int pwm_apply_might_sleep(struct pwm_device *pwm, struct pwm_state *state); + + This API controls both the PWM period/duty_cycle config and the + enable/disable state. + ++PWM devices can be used from atomic context, if the PWM does not sleep. You ++can check if this the case with:: ++ ++ bool pwm_might_sleep(struct pwm_device *pwm); ++ ++If false, the PWM can also be configured from atomic context with:: ++ ++ int pwm_apply_atomic(struct pwm_device *pwm, struct pwm_state *state); ++ + As a consumer, don't rely on the output's state for a disabled PWM. If it's + easily possible, drivers are supposed to emit the inactive state, but some + drivers cannot. If you rely on getting the inactive state, use .duty_cycle=0, +@@ -57,13 +66,13 @@ If supported by the driver, the signal can be optimized, for example to improve + EMI by phase shifting the individual channels of a chip. + + The pwm_config(), pwm_enable() and pwm_disable() functions are just wrappers +-around pwm_apply_state() and should not be used if the user wants to change ++around pwm_apply_might_sleep() and should not be used if the user wants to change + several parameter at once. For example, if you see pwm_config() and + pwm_{enable,disable}() calls in the same function, this probably means you +-should switch to pwm_apply_state(). ++should switch to pwm_apply_might_sleep(). + + The PWM user API also allows one to query the PWM state that was passed to the +-last invocation of pwm_apply_state() using pwm_get_state(). Note this is ++last invocation of pwm_apply_might_sleep() using pwm_get_state(). Note this is + different to what the driver has actually implemented if the request cannot be + satisfied exactly with the hardware in use. There is currently no way for + consumers to get the actually implemented settings. diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst -index 05a82f8c0c99..df39e6ad40e3 100644 +index 6708d649afd7..65de8ab99c58 100644 --- a/Documentation/userspace-api/media/drivers/index.rst +++ b/Documentation/userspace-api/media/drivers/index.rst -@@ -33,6 +33,7 @@ For more details see the file COPYING in the source distribution of Linux. - +@@ -36,6 +36,7 @@ For more details see the file COPYING in the source distribution of Linux. cx2341x-uapi + dw100 imx-uapi + bcm2835-isp max2175 - meye-uapi omap3isp-uapi -diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst -index b864869b42bc..3163f501afb4 100644 ---- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst -+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst -@@ -4111,6 +4111,9 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - - * - __u32 - - ``data_bit_offset`` - - Offset (in bits) to the video data in the current slice data. -+ * - __u32 -+ - ``slice_segment_addr`` -+ - - * - __u8 - - ``nal_unit_type`` - - -@@ -4188,7 +4191,7 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - - - ``num_rps_poc_lt_curr`` - - The number of reference pictures in the long-term set. - * - __u8 -- - ``padding7`` -+ - ``padding5`` - - Applications and drivers must set this to zero. - * - struct :c:type:`v4l2_hevc_dpb_entry` - - ``dpbV4L2_HEVC_DPB_ENTRIES_NUM_MAX`` -@@ -4319,6 +4322,47 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - - - ``padding6`` - - 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_4x4616`` -+ - -+ * - __u8 -+ - ``scaling_list_8x8664`` -+ - -+ * - __u8 -+ - ``scaling_list_16x16664`` -+ - -+ * - __u8 -+ - ``scaling_list_32x32264`` -+ - -+ * - __u8 -+ - ``scaling_list_dc_coef_16x166`` -+ - -+ * - __u8 -+ - ``scaling_list_dc_coef_32x322`` -+ - -+ - ``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 --git a/Documentation/userspace-api/media/v4l/ext-ctrls-image-source.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-image-source.rst -index 9457dc340c31..af8fa25026c0 100644 ---- a/Documentation/userspace-api/media/v4l/ext-ctrls-image-source.rst -+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-image-source.rst -@@ -58,3 +58,23 @@ Image Source Control IDs - The unit cell consists of the whole area of the pixel, sensitive and - non-sensitive. - This control is required for automatic calibration of sensors/cameras. -+ -+``V4L2_CID_NOTIFY_GAINS (integer array)`` -+ The sensor is notified what gains will be applied to the different -+ colour channels by subsequent processing (such as by an ISP). The -+ sensor is merely informed of these values in case it performs -+ processing that requires them, but it does not apply them itself to -+ the output pixels. -+ -+ Currently it is defined only for Bayer sensors, and is an array -+ control taking 4 gain values, being the gains for each of the -+ Bayer channels. The gains are always in the order B, Gb, Gr and R, -+ irrespective of the exact Bayer order of the sensor itself. -+ -+ The use of an array allows this control to be extended to sensors -+ with, for example, non-Bayer CFAs (colour filter arrays). -+ -+ The units for the gain values are linear, with the default value -+ representing a gain of exactly 1.0. For example, if this default value -+ is reported as being (say) 128, then a value of 192 would represent -+ a gain of exactly 1.5. + st-vgxy61 diff --git a/Documentation/userspace-api/media/v4l/meta-formats.rst b/Documentation/userspace-api/media/v4l/meta-formats.rst -index fff25357fe86..c1dd92a2d617 100644 +index 0bb61fc5bc00..d421ccdfccfc 100644 --- a/Documentation/userspace-api/media/v4l/meta-formats.rst +++ b/Documentation/userspace-api/media/v4l/meta-formats.rst @@ -12,9 +12,11 @@ These formats are used for the :ref:`metadata` interface only. .. 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 --git a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst -index d585909bc4e2..f817c643761b 100644 ---- a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst -+++ b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst -@@ -200,6 +200,7 @@ Compressed Formats - * ``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. ++ metafmt-bcm2835-isp-stats + metafmt-d4xx + metafmt-intel-ipu3 + metafmt-rkisp1 ++ metafmt-sensor-data + metafmt-uvc + metafmt-vsp1-hgo + metafmt-vsp1-hgt diff --git a/Documentation/userspace-api/media/v4l/pixfmt-meta-bcm2835-isp-stats.rst b/Documentation/userspace-api/media/v4l/pixfmt-meta-bcm2835-isp-stats.rst new file mode 100644 index 000000000000..f974774c8252 @@ -3813,38 +4844,6 @@ + + + -diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv12.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv12.rst -index dd2f38129fe6..359f7ce67114 100644 ---- a/Documentation/userspace-api/media/v4l/pixfmt-nv12.rst -+++ b/Documentation/userspace-api/media/v4l/pixfmt-nv12.rst -@@ -3,9 +3,9 @@ - .. _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 -@@ -31,6 +31,14 @@ with a Cr byte. - 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 --git a/Documentation/userspace-api/media/v4l/pixfmt-y12p.rst b/Documentation/userspace-api/media/v4l/pixfmt-y12p.rst new file mode 100644 index 000000000000..3704f9180fd7 @@ -3956,18 +4955,41 @@ + - Y'\ :sub:`03low bits 5--0`\ (bits 7--2) + + Y'\ :sub:`02low bits 5--4`\ (bits 1--0) +diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst +index 1840224faa41..56ef9ee9c0e1 100644 +--- a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst ++++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst +@@ -697,6 +697,18 @@ Data in the 12 high bits, zeros in the 4 low bits, arranged in little endian ord + - Cr\ :sub:`11` + + ++V4L2_PIX_FMT_NV12_COL128 ++------------------------ ++ ++``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. ++ ++ + Fully Planar YUV Formats + ======================== + diff --git a/Documentation/userspace-api/media/v4l/subdev-formats.rst b/Documentation/userspace-api/media/v4l/subdev-formats.rst -index eff6727c69d3..a62c416f1408 100644 +index a3a35eeed708..d7250b6a1695 100644 --- a/Documentation/userspace-api/media/v4l/subdev-formats.rst +++ b/Documentation/userspace-api/media/v4l/subdev-formats.rst -@@ -620,6 +620,43 @@ The following tables list existing packed RGB formats. +@@ -624,6 +624,43 @@ The following tables list existing packed RGB formats. - b\ :sub:`2` - b\ :sub:`1` - b\ :sub:`0` + * .. _MEDIA_BUS_FMT_RGB565_1X24_CPADHI: + + - MEDIA_BUS_FMT_RGB565_1X24_CPADHI -+ - 0x1020 ++ - 0x1022 + - + - + - @@ -4004,14 +5026,14 @@ * .. _MEDIA-BUS-FMT-BGR565-2X8-BE: - MEDIA_BUS_FMT_BGR565_2X8_BE -@@ -908,6 +945,43 @@ The following tables list existing packed RGB formats. +@@ -912,6 +949,43 @@ The following tables list existing packed RGB formats. - g\ :sub:`5` - g\ :sub:`4` - g\ :sub:`3` + * .. _MEDIA-BUS-FMT-BGR666-1X18: + -+ - MEDIA_BUS_FMT_RGB666_1X18 -+ - 0x101f ++ - MEDIA_BUS_FMT-BGR666_1X18 ++ - 0x1023 + - + - + - @@ -4048,14 +5070,14 @@ * .. _MEDIA-BUS-FMT-RGB666-1X18: - MEDIA_BUS_FMT_RGB666_1X18 -@@ -982,6 +1056,43 @@ The following tables list existing packed RGB formats. +@@ -1023,6 +1097,43 @@ The following tables list existing packed RGB formats. - g\ :sub:`2` - g\ :sub:`1` - g\ :sub:`0` + * .. _MEDIA-BUS-FMT-BGR666-1X24_CPADHI: + + - MEDIA_BUS_FMT_BGR666_1X24_CPADHI -+ - 0x101e ++ - 0x1024 + - + - + - @@ -4092,11 +5114,10 @@ * .. _MEDIA-BUS-FMT-RGB666-1X24_CPADHI: - MEDIA_BUS_FMT_RGB666_1X24_CPADHI -@@ -7899,3 +8010,36 @@ formats. - - 0x5001 - - Interleaved raw UYVY and JPEG image format with embedded meta-data - used by Samsung S3C73MX camera sensors. -+ +@@ -8234,3 +8345,35 @@ The following table lists the existing metadata formats. + both sides of the link and the bus format is a fixed + metadata format that is not configurable from userspace. + Width and height will be set to 0 for this format. + + +.. _v4l2-mbus-sensor-data: @@ -4130,32 +5151,66 @@ + <https://mipi.org/specifications/csi-2>`_ + diff --git a/Documentation/userspace-api/media/v4l/yuv-formats.rst b/Documentation/userspace-api/media/v4l/yuv-formats.rst -index 4a05a105a9e6..ba3a5b599362 100644 +index 24b34cdfa6fe..44589ac3e909 100644 --- a/Documentation/userspace-api/media/v4l/yuv-formats.rst +++ b/Documentation/userspace-api/media/v4l/yuv-formats.rst -@@ -28,7 +28,9 @@ to brightness information. - pixfmt-grey - pixfmt-y10 - pixfmt-y12 +@@ -267,7 +267,28 @@ image. + pixfmt-packed-yuv + pixfmt-yuv-planar + pixfmt-yuv-luma + pixfmt-y12p - pixfmt-y14 + pixfmt-y14p - pixfmt-y10b - pixfmt-y10p - pixfmt-y16 -@@ -51,6 +53,7 @@ to brightness information. - pixfmt-nv12 - pixfmt-nv12m - pixfmt-nv12mt + pixfmt-y8i + pixfmt-y12i + pixfmt-uv8 ++ pixfmt-yuyv ++ pixfmt-uyvy ++ pixfmt-yvyu ++ pixfmt-vyuy ++ pixfmt-y41p ++ pixfmt-yuv420 ++ pixfmt-yuv420m ++ pixfmt-yuv422m ++ pixfmt-yuv444m ++ pixfmt-yuv410 ++ pixfmt-yuv422p ++ pixfmt-yuv411p ++ pixfmt-nv12 ++ pixfmt-nv12m ++ pixfmt-nv12mt + pixfmt-nv12-col128 - pixfmt-nv16 - pixfmt-nv16m - pixfmt-nv24 ++ pixfmt-nv16 ++ pixfmt-nv16m ++ pixfmt-nv24 + pixfmt-m420 diff --git a/MAINTAINERS b/MAINTAINERS -index 23a23bd94c00..87dd5d4ac875 100644 +index cd4f9e589245..9c9668adac5d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -3417,6 +3417,29 @@ N: bcm113* +@@ -1563,6 +1563,22 @@ S: Maintained + F: drivers/net/arcnet/ + F: include/uapi/linux/if_arcnet.h + ++ARDUCAM 64MP SENSOR DRIVER ++M: Arducam Kernel Maintenance <info@arducam.com> ++L: linux-media@vger.kernel.org ++S: Maintained ++T: git git://linuxtv.org/media_tree.git ++F: Documentation/devicetree/bindings/media/i2c/arducam,64mp.yaml ++F: drivers/media/i2c/arducam_64mp.c ++ ++ARDUCAM PIVARIETY SENSOR DRIVER ++M: Arducam Kernel Maintenance <info@arducam.com> ++L: linux-media@vger.kernel.org ++S: Maintained ++T: git git://linuxtv.org/media_tree.git ++F: Documentation/devicetree/bindings/media/i2c/arducam-pivariety.yaml ++F: drivers/media/i2c/arducam-pivariety.c ++ + ARM AND ARM64 SoC SUB-ARCHITECTURES (COMMON PARTS) + M: Arnd Bergmann <arnd@arndb.de> + M: Olof Johansson <olof@lixom.net> +@@ -3916,6 +3932,29 @@ N: bcm113* N: bcm216* N: kona @@ -4185,24 +5240,56 @@ BROADCOM BCM47XX MIPS ARCHITECTURE M: Hauke Mehrtens <hauke@hauke-m.de> M: Rafał Miłecki <zajec5@gmail.com> -@@ -5513,6 +5536,14 @@ S: Maintained - F: Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.yaml - F: drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c +@@ -15852,6 +15891,14 @@ S: Maintained + T: git git://linuxtv.org/media_tree.git + F: drivers/media/i2c/ov5695.c -+DRM DRIVER FOR GENERIC USB DISPLAY -+M: Noralf Trønnes <noralf@tronnes.org> ++OMNIVISION OV64A40 SENSOR DRIVER ++M: Jacopo Mondi <jacopo.mondi@ideasonboard.com> ++L: linux-media@vger.kernel.org ++S: Maintained ++T: git git://linuxtv.org/media_tree.git ++F: Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml ++F: drivers/media/i2c/ov64a40.c ++ + OMNIVISION OV7670 SENSOR DRIVER + L: linux-media@vger.kernel.org + S: Orphan +@@ -17410,7 +17457,7 @@ F: drivers/video/backlight/pwm_bl.c + F: include/dt-bindings/pwm/ + F: include/linux/pwm.h + F: include/linux/pwm_backlight.h +-K: pwm_(config|apply_state|ops) ++K: pwm_(config|apply_might_sleep|apply_atomic|ops) + + PXA GPIO DRIVER + M: Robert Jarzmik <robert.jarzmik@free.fr> +@@ -18602,6 +18649,13 @@ S: Supported + F: drivers/iio/light/rohm-bu27008.c + F: drivers/iio/light/rohm-bu27034.c + ++ROHM BU64754 MOTOR DRIVER FOR CAMERA AUTOFOCUS ++M: Kieran Bingham <kieran.bingham@ideasonboard.com> ++L: linux-media@vger.kernel.org +S: Maintained -+W: https://github.com/notro/gud/wiki -+T: git git://anongit.freedesktop.org/drm/drm-misc -+F: drivers/gpu/drm/gud/ -+F: include/drm/gud.h ++T: git git://linuxtv.org/media_tree.git ++F: Documentation/devicetree/bindings/media/i2c/rohm,bu64754.yaml + - DRM DRIVER FOR GRAIN MEDIA GM12U320 PROJECTORS - M: Hans de Goede <hdegoede@redhat.com> + ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS + M: Marek Vasut <marek.vasut+renesas@gmail.com> + L: linux-kernel@vger.kernel.org +@@ -19995,7 +20049,7 @@ M: Sakari Ailus <sakari.ailus@linux.intel.com> + L: linux-media@vger.kernel.org S: Maintained -@@ -16402,6 +16433,23 @@ S: Maintained T: git git://linuxtv.org/media_tree.git - F: drivers/media/i2c/imx355.c +-F: Documentation/devicetree/bindings/media/i2c/imx258.yaml ++F: Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml + F: drivers/media/i2c/imx258.c + + SONY IMX274 SENSOR DRIVER +@@ -20072,6 +20126,31 @@ T: git git://linuxtv.org/media_tree.git + F: Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml + F: drivers/media/i2c/imx415.c +SONY IMX477 SENSOR DRIVER +M: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com> @@ -4221,80 +5308,118 @@ +F: Documentation/devicetree/bindings/media/i2c/imx519.yaml +F: drivers/media/i2c/imx519.c + ++SONY IMX708 SENSOR DRIVER ++M: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com> ++L: linux-media@vger.kernel.org ++S: Maintained ++T: git git://linuxtv.org/media_tree.git ++F: Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml ++F: drivers/media/i2c/imx708.c ++ SONY MEMORYSTICK SUBSYSTEM M: Maxim Levitsky <maximlevitsky@gmail.com> M: Alex Dubov <oakad@yahoo.com> -diff --git a/Makefile b/Makefile -index 3ebf74787e93..e16eb72067f4 100644 ---- a/Makefile -+++ b/Makefile -@@ -1354,6 +1354,9 @@ ifneq ($(dtstree),) - %.dtb: include/config/kernel.release scripts_dtc - $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@ - -+%.dtbo: include/config/kernel.release scripts_dtc -+ $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@ -+ - PHONY += dtbs dtbs_install dtbs_check - dtbs: include/config/kernel.release scripts_dtc - $(Q)$(MAKE) $(build)=$(dtstree) +diff --git a/README.md b/README.md +new file mode 100644 +index 000000000000..e33ba1b6c950 +--- /dev/null ++++ b/README.md +@@ -0,0 +1,30 @@ ++Linux kernel ++============ ++ ++There are several guides for kernel developers and users. These guides can ++be rendered in a number of formats, like HTML and PDF. Please read ++Documentation/admin-guide/README.rst first. ++ ++In order to build the documentation, use ``make htmldocs`` or ++``make pdfdocs``. The formatted documentation can also be read online at: ++ ++ https://www.kernel.org/doc/html/latest/ ++ ++There are various text files in the Documentation/ subdirectory, ++several of them using the Restructured Text markup notation. ++ ++Please read the Documentation/process/changes.rst file, as it contains the ++requirements for building and running the kernel, and information about ++the problems which may result by upgrading your kernel. ++ ++Build status for rpi-5.15.y: ++!Pi kernel build tests(https://github.com/raspberrypi/linux/actions/workflows/kernel-build.yml/badge.svg?branch=rpi-5.15.y)(https://github.com/raspberrypi/linux/actions/workflows/kernel-build.yml) ++!dtoverlaycheck(https://github.com/raspberrypi/linux/actions/workflows/dtoverlaycheck.yml/badge.svg?branch=rpi-5.15.y)(https://github.com/raspberrypi/linux/actions/workflows/dtoverlaycheck.yml) ++ ++Build status for rpi-6.1.y: ++!Pi kernel build tests(https://github.com/raspberrypi/linux/actions/workflows/kernel-build.yml/badge.svg?branch=rpi-6.1.y)(https://github.com/raspberrypi/linux/actions/workflows/kernel-build.yml) ++!dtoverlaycheck(https://github.com/raspberrypi/linux/actions/workflows/dtoverlaycheck.yml/badge.svg?branch=rpi-6.1.y)(https://github.com/raspberrypi/linux/actions/workflows/dtoverlaycheck.yml) ++ ++Build status for rpi-6.6.y: ++!Pi kernel build tests(https://github.com/raspberrypi/linux/actions/workflows/kernel-build.yml/badge.svg?branch=rpi-6.6.y)(https://github.com/raspberrypi/linux/actions/workflows/kernel-build.yml) ++!dtoverlaycheck(https://github.com/raspberrypi/linux/actions/workflows/dtoverlaycheck.yml/badge.svg?branch=rpi-6.6.y)(https://github.com/raspberrypi/linux/actions/workflows/dtoverlaycheck.yml) diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile -index 7e8151681597..6bcb35ad76ac 100644 +index efe38eb25301..a2a407fb5b28 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile -@@ -1,4 +1,24 @@ - # 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 \ -+ bcm2710-rpi-zero-2.dtb \ -+ bcm2710-rpi-zero-2-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 \ -+ bcm2711-rpi-cm4s.dtb -+ - dtb-$(CONFIG_ARCH_ALPINE) += \ - alpine-db.dtb - dtb-$(CONFIG_MACH_ARTPEC6) += \ -@@ -92,7 +112,6 @@ dtb-$(CONFIG_ARCH_BCM2835) += \ - 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) += \ -@@ -1409,3 +1428,13 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ - aspeed-bmc-opp-zaius.dtb \ - aspeed-bmc-portwell-neptune.dtb \ - aspeed-bmc-quanta-q71l.dtb +@@ -39,3 +39,8 @@ subdir-y += unisoc + subdir-y += vt8500 + subdir-y += xen + subdir-y += xilinx + +targets += dtbs dtbs_install +targets += $(dtb-y) + -+subdir-y := overlays ++subdir-y += overlays +diff --git a/arch/arm/boot/dts/broadcom/Makefile b/arch/arm/boot/dts/broadcom/Makefile +index 7099d9560033..4af351c7f7b2 100644 +--- a/arch/arm/boot/dts/broadcom/Makefile ++++ b/arch/arm/boot/dts/broadcom/Makefile +@@ -35,6 +35,41 @@ dtb-$(CONFIG_ARCH_BCM2835) += \ + bcm2711-rpi-cm4-io.dtb \ + bcm2835-rpi-zero.dtb \ + bcm2835-rpi-zero-w.dtb + -+# Enable fixups to support overlays on BCM2835 platforms -+ifeq ($(CONFIG_ARCH_BCM2835),y) -+ DTC_FLAGS += -@ -+endif -diff --git a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts ++DTC_FLAGS_bcm2708-rpi-b := -@ ++DTC_FLAGS_bcm2708-rpi-b-rev1 := -@ ++DTC_FLAGS_bcm2708-rpi-b-plus := -@ ++DTC_FLAGS_bcm2708-rpi-cm := -@ ++DTC_FLAGS_bcm2708-rpi-zero := -@ ++DTC_FLAGS_bcm2708-rpi-zero-w := -@ ++DTC_FLAGS_bcm2710-rpi-zero-2 := -@ ++DTC_FLAGS_bcm2710-rpi-zero-2-w := -@ ++DTC_FLAGS_bcm2709-rpi-2-b := -@ ++DTC_FLAGS_bcm2710-rpi-2-b := -@ ++DTC_FLAGS_bcm2710-rpi-3-b := -@ ++DTC_FLAGS_bcm2710-rpi-3-b-plus := -@ ++DTC_FLAGS_bcm2709-rpi-cm2 := -@ ++DTC_FLAGS_bcm2710-rpi-cm3 := -@ ++DTC_FLAGS_bcm2711-rpi-cm4 := -@ ++DTC_FLAGS_bcm2711-rpi-cm4s := -@ ++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 \ ++ bcm2710-rpi-zero-2.dtb \ ++ bcm2710-rpi-zero-2-w.dtb \ ++ bcm2709-rpi-2-b.dtb \ ++ bcm2710-rpi-2-b.dtb \ ++ bcm2710-rpi-3-b.dtb \ ++ bcm2710-rpi-3-b-plus.dtb \ ++ bcm2709-rpi-cm2.dtb \ ++ bcm2710-rpi-cm3.dtb \ ++ bcm2711-rpi-cm4.dtb \ ++ bcm2711-rpi-cm4s.dtb ++ + dtb-$(CONFIG_ARCH_BCMBCA) += \ + bcm947622.dtb \ + bcm963138.dtb \ +diff --git a/arch/arm/boot/dts/broadcom/bcm2708-rpi-b-plus.dts b/arch/arm/boot/dts/broadcom/bcm2708-rpi-b-plus.dts new file mode 100644 -index 000000000000..a7d6427671b4 +index 000000000000..ee72fdac6663 --- /dev/null -+++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts -@@ -0,0 +1,131 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-b-plus.dts +@@ -0,0 +1,210 @@ +/dts-v1/; + +#include "bcm2708.dtsi" @@ -4302,6 +5427,7 @@ +#include "bcm283x-rpi-smsc9514.dtsi" +#include "bcm283x-rpi-csi1-2lane.dtsi" +#include "bcm283x-rpi-i2c0mux_0_28.dtsi" ++#include "bcm283x-rpi-led-deprecated.dtsi" + +/ { + compatible = "raspberrypi,model-b-plus", "brcm,bcm2835"; @@ -4309,6 +5435,71 @@ +}; + +&gpio { ++ /* ++ * Taken from Raspberry-Pi-B-Plus-V1.2-Schematics.pdf ++ * RPI-BPLUS sheet 1 ++ * ++ * Legend: ++ * "NC" = not connected (no rail from the SoC) ++ * "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", ++ "GPIO2", ++ "GPIO3", ++ "GPIO4", ++ "GPIO5", ++ "GPIO6", ++ "GPIO7", ++ "GPIO8", ++ "GPIO9", ++ "GPIO10", ++ "GPIO11", ++ "GPIO12", ++ "GPIO13", ++ "GPIO14", ++ "GPIO15", ++ "GPIO16", ++ "GPIO17", ++ "GPIO18", ++ "GPIO19", ++ "GPIO20", ++ "GPIO21", ++ "GPIO22", ++ "GPIO23", ++ "GPIO24", ++ "GPIO25", ++ "GPIO26", ++ "GPIO27", ++ "SDA0", ++ "SCL0", ++ "NC", /* GPIO30 */ ++ "LAN_RUN", /* GPIO31 */ ++ "CAM_GPIO1", /* GPIO32 */ ++ "NC", /* GPIO33 */ ++ "NC", /* GPIO34 */ ++ "PWR_LOW_N", /* GPIO35 */ ++ "NC", /* GPIO36 */ ++ "NC", /* GPIO37 */ ++ "USB_LIMIT", /* GPIO38 */ ++ "NC", /* GPIO39 */ ++ "PWM0_OUT", /* GPIO40 */ ++ "CAM_GPIO0", /* GPIO41 */ ++ "NC", /* GPIO42 */ ++ "NC", /* GPIO43 */ ++ "ETH_CLK", /* GPIO44 */ ++ "PWM1_OUT", /* GPIO45 */ ++ "HDMI_HPD_N", ++ "STATUS_LED", ++ /* Used by SD Card */ ++ "SD_CLK_R", ++ "SD_CMD_R", ++ "SD_DATA0_R", ++ "SD_DATA1_R", ++ "SD_DATA2_R", ++ "SD_DATA3_R"; ++ + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = <4>; /* alt0 */ @@ -4337,6 +5528,7 @@ + audio_pins: audio_pins { + brcm,pins = <40 45>; + brcm,function = <4>; ++ brcm,pull = <0>; + }; +}; + @@ -4385,17 +5577,18 @@ + pinctrl-0 = <&i2s_pins>; +}; + -+&leds { -+ act_led: led-act { -+ label = "led0"; -+ linux,default-trigger = "mmc0"; -+ gpios = <&gpio 47 0>; -+ }; ++&led_act { ++ gpios = <&gpio 47 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; ++}; + -+ pwr_led: led-pwr { -+ label = "led1"; ++&leds { ++ led_pwr: led-pwr { ++ label = "PWR"; ++ gpios = <&gpio 35 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; + linux,default-trigger = "input"; -+ gpios = <&gpio 35 0>; + }; +}; + @@ -4403,7 +5596,7 @@ + hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>; +}; + -+&audio { ++&vchiq { + pinctrl-names = "default"; + pinctrl-0 = <&audio_pins>; +}; @@ -4415,29 +5608,41 @@ +cam0_reg: &cam_dummy_reg { +}; + ++i2c_arm: &i2c1 { ++}; ++ ++i2c_vc: &i2c0 { ++}; ++ ++i2c_csi_dsi0: &i2c0 { ++}; ++ +/ { + __overrides__ { -+ act_led_gpio = <&act_led>,"gpios:4"; -+ act_led_activelow = <&act_led>,"gpios:8"; -+ act_led_trigger = <&act_led>,"linux,default-trigger"; ++ audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_headphones=1 snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_headphones=0 snd_bcm2835.enable_hdmi=0'}"; ++ ++ act_led_gpio = <&led_act>,"gpios:4"; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>,"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"; ++ pwr_led_gpio = <&led_pwr>,"gpios:4"; ++ pwr_led_activelow = <&led_pwr>,"gpios:8"; ++ pwr_led_trigger = <&led_pwr>,"linux,default-trigger"; + }; +}; -diff --git a/arch/arm/boot/dts/bcm2708-rpi-b-rev1.dts b/arch/arm/boot/dts/bcm2708-rpi-b-rev1.dts +diff --git a/arch/arm/boot/dts/broadcom/bcm2708-rpi-b-rev1.dts b/arch/arm/boot/dts/broadcom/bcm2708-rpi-b-rev1.dts new file mode 100644 -index 000000000000..af1b477f7927 +index 000000000000..9301e345aea2 --- /dev/null -+++ b/arch/arm/boot/dts/bcm2708-rpi-b-rev1.dts -@@ -0,0 +1,134 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-b-rev1.dts +@@ -0,0 +1,223 @@ +/dts-v1/; + +#include "bcm2708.dtsi" +#include "bcm2708-rpi.dtsi" +#include "bcm283x-rpi-smsc9512.dtsi" +#include "bcm283x-rpi-csi1-2lane.dtsi" ++#include "bcm283x-rpi-led-deprecated.dtsi" + +/ { + compatible = "raspberrypi,model-b", "brcm,bcm2835"; @@ -4445,6 +5650,73 @@ +}; + +&gpio { ++ /* ++ * Taken from Raspberry-Pi-Rev-1.0-Model-AB-Schematics.pdf ++ * RPI00021 sheet 02 ++ * ++ * Legend: ++ * "NC" = not connected (no rail from the SoC) ++ * "FOO" = GPIO line named "FOO" on the schematic ++ * "FOO_N" = GPIO line named "FOO" on schematic, active low ++ */ ++ gpio-line-names = "SDA0", ++ "SCL0", ++ "SDA1", ++ "SCL1", ++ "GPIO_GCLK", ++ "CAM_GPIO1", ++ "LAN_RUN", ++ "SPI_CE1_N", ++ "SPI_CE0_N", ++ "SPI_MISO", ++ "SPI_MOSI", ++ "SPI_SCLK", ++ "NC", /* GPIO12 */ ++ "NC", /* GPIO13 */ ++ /* Serial port */ ++ "TXD0", ++ "RXD0", ++ "STATUS_LED_N", ++ "GPIO17", ++ "GPIO18", ++ "NC", /* GPIO19 */ ++ "NC", /* GPIO20 */ ++ "GPIO21", ++ "GPIO22", ++ "GPIO23", ++ "GPIO24", ++ "GPIO25", ++ "NC", /* GPIO26 */ ++ "CAM_GPIO0", ++ /* Binary number representing build/revision */ ++ "CONFIG0", ++ "CONFIG1", ++ "CONFIG2", ++ "CONFIG3", ++ "NC", /* GPIO32 */ ++ "NC", /* GPIO33 */ ++ "NC", /* GPIO34 */ ++ "NC", /* GPIO35 */ ++ "NC", /* GPIO36 */ ++ "NC", /* GPIO37 */ ++ "NC", /* GPIO38 */ ++ "NC", /* GPIO39 */ ++ "PWM0_OUT", ++ "NC", /* GPIO41 */ ++ "NC", /* GPIO42 */ ++ "NC", /* GPIO43 */ ++ "NC", /* GPIO44 */ ++ "PWM1_OUT", ++ "HDMI_HPD_P", ++ "SD_CARD_DET", ++ /* Used by SD Card */ ++ "SD_CLK_R", ++ "SD_CMD_R", ++ "SD_DATA0_R", ++ "SD_DATA1_R", ++ "SD_DATA2_R", ++ "SD_DATA3_R"; ++ + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = <4>; /* alt0 */ @@ -4473,6 +5745,7 @@ + audio_pins: audio_pins { + brcm,pins = <40 45>; + brcm,function = <4>; ++ brcm,pull = <0>; + }; +}; + @@ -4521,6 +5794,10 @@ + i2c0 = &i2c0; + }; + ++ /* Provide an i2c0mux label to avoid undefined symbols in overlays */ ++ i2c0mux: i2c0mux { ++ }; ++ + __overrides__ { + i2c0 = <&i2c0>, "status"; + }; @@ -4535,19 +5812,17 @@ + pinctrl-0 = <&i2s_pins>; +}; + -+&leds { -+ act_led: led-act { -+ label = "led0"; -+ linux,default-trigger = "mmc0"; -+ gpios = <&gpio 16 1>; -+ }; ++&led_act { ++ gpios = <&gpio 16 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; +}; + +&hdmi { + hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>; +}; + -+&audio { ++&vchiq { + pinctrl-names = "default"; + pinctrl-0 = <&audio_pins>; +}; @@ -4559,19 +5834,37 @@ +cam0_reg: &cam_dummy_reg { +}; + ++i2c_arm: &i2c0 { ++}; ++ ++i2c_vc: &i2c1 { ++}; ++ ++i2c_csi_dsi0: &i2c0 { ++}; ++ +/ { + __overrides__ { -+ act_led_gpio = <&act_led>,"gpios:4"; -+ act_led_activelow = <&act_led>,"gpios:8"; -+ act_led_trigger = <&act_led>,"linux,default-trigger"; ++ audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_headphones=1 snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_headphones=0 snd_bcm2835.enable_hdmi=0'}"; ++ ++ act_led_gpio = <&led_act>,"gpios:4"; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>,"linux,default-trigger"; ++ ++ i2c = <&i2c0>,"status"; ++ i2c_arm = <&i2c0>,"status"; ++ i2c_vc = <&i2c1>,"status"; ++ i2c_baudrate = <&i2c0>,"clock-frequency:0"; ++ i2c_arm_baudrate = <&i2c0>,"clock-frequency:0"; ++ i2c_vc_baudrate = <&i2c1>,"clock-frequency:0"; + }; +}; -diff --git a/arch/arm/boot/dts/bcm2708-rpi-b.dts b/arch/arm/boot/dts/bcm2708-rpi-b.dts +diff --git a/arch/arm/boot/dts/broadcom/bcm2708-rpi-b.dts b/arch/arm/boot/dts/broadcom/bcm2708-rpi-b.dts new file mode 100644 -index 000000000000..a5316257a18b +index 000000000000..b8459fd0f497 --- /dev/null -+++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts -@@ -0,0 +1,121 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-b.dts +@@ -0,0 +1,198 @@ +/dts-v1/; + +#include "bcm2708.dtsi" @@ -4579,6 +5872,7 @@ +#include "bcm283x-rpi-smsc9512.dtsi" +#include "bcm283x-rpi-csi1-2lane.dtsi" +#include "bcm283x-rpi-i2c0mux_0_28.dtsi" ++#include "bcm283x-rpi-led-deprecated.dtsi" + +/ { + compatible = "raspberrypi,model-b", "brcm,bcm2835"; @@ -4586,6 +5880,72 @@ +}; + +&gpio { ++ /* ++ * Taken from Raspberry-Pi-Rev-2.0-Model-AB-Schematics.pdf ++ * RPI00022 sheet 02 ++ * ++ * Legend: ++ * "NC" = not connected (no rail from the SoC) ++ * "FOO" = GPIO line named "FOO" on the schematic ++ * "FOO_N" = GPIO line named "FOO" on schematic, active low ++ */ ++ gpio-line-names = "SDA0", ++ "SCL0", ++ "SDA1", ++ "SCL1", ++ "GPIO_GCLK", ++ "CAM_GPIO1", ++ "LAN_RUN", ++ "SPI_CE1_N", ++ "SPI_CE0_N", ++ "SPI_MISO", ++ "SPI_MOSI", ++ "SPI_SCLK", ++ "NC", /* GPIO12 */ ++ "NC", /* GPIO13 */ ++ /* Serial port */ ++ "TXD0", ++ "RXD0", ++ "STATUS_LED_N", ++ "GPIO17", ++ "GPIO18", ++ "NC", /* GPIO19 */ ++ "NC", /* GPIO20 */ ++ "CAM_GPIO0", ++ "GPIO22", ++ "GPIO23", ++ "GPIO24", ++ "GPIO25", ++ "NC", /* GPIO26 */ ++ "GPIO27", ++ "GPIO28", ++ "GPIO29", ++ "GPIO30", ++ "GPIO31", ++ "NC", /* GPIO32 */ ++ "NC", /* GPIO33 */ ++ "NC", /* GPIO34 */ ++ "NC", /* GPIO35 */ ++ "NC", /* GPIO36 */ ++ "NC", /* GPIO37 */ ++ "NC", /* GPIO38 */ ++ "NC", /* GPIO39 */ ++ "PWM0_OUT", ++ "NC", /* GPIO41 */ ++ "NC", /* GPIO42 */ ++ "NC", /* GPIO43 */ ++ "NC", /* GPIO44 */ ++ "PWM1_OUT", ++ "HDMI_HPD_P", ++ "SD_CARD_DET", ++ /* Used by SD Card */ ++ "SD_CLK_R", ++ "SD_CMD_R", ++ "SD_DATA0_R", ++ "SD_DATA1_R", ++ "SD_DATA2_R", ++ "SD_DATA3_R"; ++ + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = <4>; /* alt0 */ @@ -4614,6 +5974,7 @@ + audio_pins: audio_pins { + brcm,pins = <40 45>; + brcm,function = <4>; ++ brcm,pull = <0>; + }; +}; + @@ -4662,19 +6023,17 @@ + pinctrl-0 = <&i2s_pins>; +}; + -+&leds { -+ act_led: led-act { -+ label = "led0"; -+ linux,default-trigger = "mmc0"; -+ gpios = <&gpio 16 1>; -+ }; ++&led_act { ++ gpios = <&gpio 16 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; +}; + +&hdmi { + hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>; +}; + -+&audio { ++&vchiq { + pinctrl-names = "default"; + pinctrl-0 = <&audio_pins>; +}; @@ -4686,19 +6045,30 @@ +cam0_reg: &cam_dummy_reg { +}; + ++i2c_arm: &i2c1 { ++}; ++ ++i2c_vc: &i2c0 { ++}; ++ ++i2c_csi_dsi0: &i2c0 { ++}; ++ +/ { + __overrides__ { -+ act_led_gpio = <&act_led>,"gpios:4"; -+ act_led_activelow = <&act_led>,"gpios:8"; -+ act_led_trigger = <&act_led>,"linux,default-trigger"; ++ audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_headphones=1 snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_headphones=0 snd_bcm2835.enable_hdmi=0'}"; ++ ++ act_led_gpio = <&led_act>,"gpios:4"; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>,"linux,default-trigger"; + }; +}; -diff --git a/arch/arm/boot/dts/bcm2708-rpi-bt.dtsi b/arch/arm/boot/dts/bcm2708-rpi-bt.dtsi +diff --git a/arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi b/arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi new file mode 100644 -index 000000000000..a18f80af97d3 +index 000000000000..98555528adae --- /dev/null -+++ b/arch/arm/boot/dts/bcm2708-rpi-bt.dtsi -@@ -0,0 +1,26 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi +@@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0 + +&uart0 { @@ -4706,31 +6076,43 @@ + compatible = "brcm,bcm43438-bt"; + max-speed = <3000000>; + shutdown-gpios = <&gpio 45 GPIO_ACTIVE_HIGH>; -+ status = "disabled"; ++ local-bd-address = 00 00 00 00 00 00 ; ++ fallback-bd-address; // Don't override a valid address ++ status = "okay"; + }; +}; + +&uart1 { + minibt: bluetooth { + compatible = "brcm,bcm43438-bt"; -+ max-speed = <460800>; ++ max-speed = <230400>; + shutdown-gpios = <&gpio 45 GPIO_ACTIVE_HIGH>; ++ local-bd-address = 00 00 00 00 00 00 ; ++ fallback-bd-address; // Don't override a valid address + status = "disabled"; + }; +}; + +/ { ++ aliases { ++ bluetooth = &bt; ++ }; ++ + __overrides__ { ++ bdaddr = <&bt>,"local-bd-address", ++ <&bt>,"fallback-bd-address?=0", ++ <&minibt>,"local-bd-address", ++ <&minibt>,"fallback-bd-address?=0"; + krnbt = <&bt>,"status"; -+ krnbt_baudrate = <&bt>,"max-speed:0"; ++ krnbt_baudrate = <&bt>,"max-speed:0", <&minibt>,"max-speed:0"; + }; +}; -diff --git a/arch/arm/boot/dts/bcm2708-rpi-cm.dts b/arch/arm/boot/dts/bcm2708-rpi-cm.dts +diff --git a/arch/arm/boot/dts/broadcom/bcm2708-rpi-cm.dts b/arch/arm/boot/dts/broadcom/bcm2708-rpi-cm.dts new file mode 100644 -index 000000000000..863bd207e323 +index 000000000000..fde85c8c7dca --- /dev/null -+++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts -@@ -0,0 +1,106 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-cm.dts +@@ -0,0 +1,174 @@ +/dts-v1/; + +#include "bcm2708-rpi-cm.dtsi" @@ -4744,12 +6126,15 @@ +}; + +&cam1_reg { -+ gpio = <&gpio 2 GPIO_ACTIVE_HIGH>; ++ gpio = <&gpio 3 GPIO_ACTIVE_HIGH>; + status = "disabled"; +}; + +cam0_reg: &cam0_regulator { -+ gpio = <&gpio 30 GPIO_ACTIVE_HIGH>; ++ gpio = <&gpio 31 GPIO_ACTIVE_HIGH>; ++}; ++ ++i2c_csi_dsi0: &i2c0 { +}; + +&uart0 { @@ -4757,6 +6142,71 @@ +}; + +&gpio { ++ /* ++ * This is based on the official GPU firmware DT blob. ++ * ++ * Legend: ++ * "NC" = not connected (no rail from the SoC) ++ * "FOO" = GPIO line named "FOO" on the schematic ++ * "FOO_N" = GPIO line named "FOO" on schematic, active low ++ */ ++ gpio-line-names = "GPIO0", ++ "GPIO1", ++ "GPIO2", ++ "GPIO3", ++ "GPIO4", ++ "GPIO5", ++ "GPIO6", ++ "GPIO7", ++ "GPIO8", ++ "GPIO9", ++ "GPIO10", ++ "GPIO11", ++ "GPIO12", ++ "GPIO13", ++ "GPIO14", ++ "GPIO15", ++ "GPIO16", ++ "GPIO17", ++ "GPIO18", ++ "GPIO19", ++ "GPIO20", ++ "GPIO21", ++ "GPIO22", ++ "GPIO23", ++ "GPIO24", ++ "GPIO25", ++ "GPIO26", ++ "GPIO27", ++ "GPIO28", ++ "GPIO29", ++ "GPIO30", ++ "GPIO31", ++ "GPIO32", ++ "GPIO33", ++ "GPIO34", ++ "GPIO35", ++ "GPIO36", ++ "GPIO37", ++ "GPIO38", ++ "GPIO39", ++ "GPIO40", ++ "GPIO41", ++ "GPIO42", ++ "GPIO43", ++ "GPIO44", ++ "GPIO45", ++ "HDMI_HPD_N", ++ /* Also used as ACT LED */ ++ "EMMC_EN_N", ++ /* Used by eMMC */ ++ "SD_CLK_R", ++ "SD_CMD_R", ++ "SD_DATA0_R", ++ "SD_DATA1_R", ++ "SD_DATA2_R", ++ "SD_DATA3_R"; ++ + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = <4>; /* alt0 */ @@ -4829,7 +6279,7 @@ + pinctrl-0 = <&i2s_pins>; +}; + -+&audio { ++&vchiq { + pinctrl-names = "default"; + pinctrl-0 = <&audio_pins>; +}; @@ -4837,40 +6287,45 @@ +&hdmi { + hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>; +}; -diff --git a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi +diff --git a/arch/arm/boot/dts/broadcom/bcm2708-rpi-cm.dtsi b/arch/arm/boot/dts/broadcom/bcm2708-rpi-cm.dtsi new file mode 100644 -index 000000000000..dd59f884d796 +index 000000000000..10fd4475dd5e --- /dev/null -+++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi -@@ -0,0 +1,22 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-cm.dtsi +@@ -0,0 +1,27 @@ +#include "bcm2708.dtsi" +#include "bcm2708-rpi.dtsi" ++#include "bcm283x-rpi-led-deprecated.dtsi" + -+&leds { -+ act_led: led-act { -+ label = "led0"; -+ linux,default-trigger = "mmc0"; -+ gpios = <&gpio 47 0>; -+ }; ++&led_act { ++ gpios = <&gpio 47 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; ++}; ++ ++i2c_arm: &i2c1 { ++}; ++ ++i2c_vc: &i2c0 { +}; + +/ { + __overrides__ { -+ act_led_gpio = <&act_led>,"gpios:4"; -+ act_led_activelow = <&act_led>,"gpios:8"; -+ act_led_trigger = <&act_led>,"linux,default-trigger"; ++ act_led_gpio = <&led_act>,"gpios:4"; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>,"linux,default-trigger"; + cam0_reg = <&cam0_reg>,"status"; -+ cam0_reg_gpio = <&cam0_reg>,"gpios:4"; ++ cam0_reg_gpio = <&cam0_reg>,"gpio:4"; + cam1_reg = <&cam1_reg>,"status"; -+ cam1_reg_gpio = <&cam1_reg>,"gpios:4"; ++ cam1_reg_gpio = <&cam1_reg>,"gpio:4"; + }; +}; -diff --git a/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts b/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts +diff --git a/arch/arm/boot/dts/broadcom/bcm2708-rpi-zero-w.dts b/arch/arm/boot/dts/broadcom/bcm2708-rpi-zero-w.dts new file mode 100644 -index 000000000000..e4c6c352f3aa +index 000000000000..011d0fa4c9c0 --- /dev/null -+++ b/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts -@@ -0,0 +1,178 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-zero-w.dts +@@ -0,0 +1,254 @@ +/dts-v1/; + +#include "bcm2708.dtsi" @@ -4878,13 +6333,14 @@ +#include "bcm283x-rpi-csi1-2lane.dtsi" +#include "bcm283x-rpi-i2c0mux_0_28.dtsi" +#include "bcm2708-rpi-bt.dtsi" ++#include "bcm283x-rpi-led-deprecated.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"; ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; + }; + + aliases { @@ -4895,6 +6351,72 @@ +}; + +&gpio { ++ /* ++ * This is based on the official GPU firmware DT blob. ++ * ++ * Legend: ++ * "NC" = not connected (no rail from the SoC) ++ * "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", ++ "GPIO2", ++ "GPIO3", ++ "GPIO4", ++ "GPIO5", ++ "GPIO6", ++ "GPIO7", ++ "GPIO8", ++ "GPIO9", ++ "GPIO10", ++ "GPIO11", ++ "GPIO12", ++ "GPIO13", ++ "GPIO14", ++ "GPIO15", ++ "GPIO16", ++ "GPIO17", ++ "GPIO18", ++ "GPIO19", ++ "GPIO20", ++ "GPIO21", ++ "GPIO22", ++ "GPIO23", ++ "GPIO24", ++ "GPIO25", ++ "GPIO26", ++ "GPIO27", ++ "SDA0", ++ "SCL0", ++ /* Used by BT module */ ++ "CTS0", ++ "RTS0", ++ "TXD0", ++ "RXD0", ++ /* Used by Wifi */ ++ "SD1_CLK", ++ "SD1_CMD", ++ "SD1_DATA0", ++ "SD1_DATA1", ++ "SD1_DATA2", ++ "SD1_DATA3", ++ "CAM_GPIO1", /* GPIO40 */ ++ "WL_ON", /* GPIO41 */ ++ "NC", /* GPIO42 */ ++ "WIFI_CLK", /* GPIO43 */ ++ "CAM_GPIO0", /* GPIO44 */ ++ "BT_ON", /* GPIO45 */ ++ "HDMI_HPD_N", ++ "STATUS_LED_N", ++ /* Used by SD Card */ ++ "SD_CLK_R", ++ "SD_CMD_R", ++ "SD_DATA0_R", ++ "SD_DATA1_R", ++ "SD_DATA2_R", ++ "SD_DATA3_R"; ++ + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = <4>; /* alt0 */ @@ -4944,6 +6466,12 @@ + brcm,pull; + }; + ++ uart1_bt_pins: uart1_bt_pins { ++ brcm,pins = <32 33 30 31>; ++ brcm,function = <BCM2835_FSEL_ALT5>; /* alt5=UART1 */ ++ brcm,pull = <0 2 2 0>; ++ }; ++ + audio_pins: audio_pins { + brcm,pins = <>; + brcm,function = <>; @@ -5017,22 +6545,19 @@ + pinctrl-0 = <&i2s_pins>; +}; + -+&leds { -+ act_led: led-act { -+ label = "led0"; -+ linux,default-trigger = "actpwr"; -+ gpios = <&gpio 47 GPIO_ACTIVE_LOW>; -+ }; ++&led_act { ++ gpios = <&gpio 47 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ linux,default-trigger = "actpwr"; +}; + +&hdmi { + hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>; +}; + -+&audio { ++&vchiq { + pinctrl-names = "default"; + pinctrl-0 = <&audio_pins>; -+ brcm,disable-headphones = <1>; +}; + +&cam1_reg { @@ -5042,36 +6567,103 @@ +cam0_reg: &cam_dummy_reg { +}; + ++i2c_arm: &i2c1 {}; ++i2c_vc: &i2c0 {}; ++i2c_csi_dsi0: &i2c0 {}; ++ +/ { + __overrides__ { -+ act_led_gpio = <&act_led>,"gpios:4"; -+ act_led_activelow = <&act_led>,"gpios:8"; -+ act_led_trigger = <&act_led>,"linux,default-trigger"; ++ audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_hdmi=0'}"; ++ ++ act_led_gpio = <&led_act>,"gpios:4"; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>,"linux,default-trigger"; + }; +}; -diff --git a/arch/arm/boot/dts/bcm2708-rpi-zero.dts b/arch/arm/boot/dts/bcm2708-rpi-zero.dts +diff --git a/arch/arm/boot/dts/broadcom/bcm2708-rpi-zero.dts b/arch/arm/boot/dts/broadcom/bcm2708-rpi-zero.dts new file mode 100644 -index 000000000000..19dae0d682ed +index 000000000000..1721be8dbe20 --- /dev/null -+++ b/arch/arm/boot/dts/bcm2708-rpi-zero.dts -@@ -0,0 +1,125 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-zero.dts +@@ -0,0 +1,189 @@ +/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-led-deprecated.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 { ++ /* ++ * This is based on the official GPU firmware DT blob. ++ * ++ * Legend: ++ * "NC" = not connected (no rail from the SoC) ++ * "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", ++ "GPIO2", ++ "GPIO3", ++ "GPIO4", ++ "GPIO5", ++ "GPIO6", ++ "GPIO7", ++ "GPIO8", ++ "GPIO9", ++ "GPIO10", ++ "GPIO11", ++ "GPIO12", ++ "GPIO13", ++ "GPIO14", ++ "GPIO15", ++ "GPIO16", ++ "GPIO17", ++ "GPIO18", ++ "GPIO19", ++ "GPIO20", ++ "GPIO21", ++ "GPIO22", ++ "GPIO23", ++ "GPIO24", ++ "GPIO25", ++ "GPIO26", ++ "GPIO27", ++ "SDA0", ++ "SCL0", ++ "NC", /* GPIO30 */ ++ "NC", /* GPIO31 */ ++ "CAM_GPIO1", /* GPIO32 */ ++ "NC", /* GPIO33 */ ++ "NC", /* GPIO34 */ ++ "NC", /* GPIO35 */ ++ "NC", /* GPIO36 */ ++ "NC", /* GPIO37 */ ++ "NC", /* GPIO38 */ ++ "NC", /* GPIO39 */ ++ "NC", /* GPIO40 */ ++ "CAM_GPIO0", /* GPIO41 */ ++ "NC", /* GPIO42 */ ++ "NC", /* GPIO43 */ ++ "NC", /* GPIO44 */ ++ "NC", /* GPIO45 */ ++ "HDMI_HPD_N", ++ "STATUS_LED_N", ++ /* Used by SD Card */ ++ "SD_CLK_R", ++ "SD_CMD_R", ++ "SD_DATA0_R", ++ "SD_DATA1_R", ++ "SD_DATA2_R", ++ "SD_DATA3_R"; ++ + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = <4>; /* alt0 */ @@ -5148,22 +6740,19 @@ + pinctrl-0 = <&i2s_pins>; +}; + -+&leds { -+ act_led: led-act { -+ label = "led0"; -+ linux,default-trigger = "actpwr"; -+ gpios = <&gpio 47 GPIO_ACTIVE_LOW>; -+ }; ++&led_act { ++ gpios = <&gpio 47 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ linux,default-trigger = "actpwr"; +}; + +&hdmi { + hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>; +}; + -+&audio { ++&vchiq { + pinctrl-names = "default"; + pinctrl-0 = <&audio_pins>; -+ brcm,disable-headphones = <1>; +}; + +&cam1_reg { @@ -5173,22 +6762,30 @@ +cam0_reg: &cam_dummy_reg { +}; + ++i2c_arm: &i2c1 {}; ++i2c_vc: &i2c0 {}; ++i2c_csi_dsi0: &i2c0 {}; ++ +/ { + __overrides__ { -+ act_led_gpio = <&act_led>,"gpios:4"; -+ act_led_activelow = <&act_led>,"gpios:8"; -+ act_led_trigger = <&act_led>,"linux,default-trigger"; ++ audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_hdmi=0'}"; ++ ++ act_led_gpio = <&led_act>,"gpios:4"; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>,"linux,default-trigger"; + }; +}; -diff --git a/arch/arm/boot/dts/bcm2708-rpi.dtsi b/arch/arm/boot/dts/bcm2708-rpi.dtsi +diff --git a/arch/arm/boot/dts/broadcom/bcm2708-rpi.dtsi b/arch/arm/boot/dts/broadcom/bcm2708-rpi.dtsi new file mode 100644 -index 000000000000..e2458b15d64a +index 000000000000..f4949a07272b --- /dev/null -+++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi -@@ -0,0 +1,36 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi.dtsi +@@ -0,0 +1,57 @@ +/* Downstream modifications common to bcm2835, bcm2836, bcm2837 */ + ++#define i2c0 i2c0mux +#include "bcm2835-rpi.dtsi" ++#undef i2c0 +#include "bcm270x-rpi.dtsi" + +/ { @@ -5202,12 +6799,31 @@ + }; + + __overrides__ { ++ hdmi = <&hdmi>,"status"; + i2c2_iknowwhatimdoing = <&i2c2>,"status"; + i2c2_baudrate = <&i2c2>,"clock-frequency:0"; ++ nvmem_cust_rw = <&nvmem_cust>,"rw?"; ++ sd = <&sdhost>,"status"; + sd_poll_once = <&sdhost>,"non-removable?"; + }; +}; + ++&soc { ++ nvmem_otp: nvmem_otp { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <0 192>; ++ status = "okay"; ++ }; ++ ++ nvmem_cust: nvmem_cust { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <1 8>; ++ status = "okay"; ++ }; ++}; ++ +&sdhost { + pinctrl-names = "default"; + pinctrl-0 = <&sdhost_gpio48>; @@ -5222,13 +6838,15 @@ +&i2c2 { + status = "disabled"; +}; -diff --git a/arch/arm/boot/dts/bcm2708.dtsi b/arch/arm/boot/dts/bcm2708.dtsi +diff --git a/arch/arm/boot/dts/broadcom/bcm2708.dtsi b/arch/arm/boot/dts/broadcom/bcm2708.dtsi new file mode 100644 -index 000000000000..36ec4989403f +index 000000000000..fdc7f2423bbe --- /dev/null -+++ b/arch/arm/boot/dts/bcm2708.dtsi -@@ -0,0 +1,12 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2708.dtsi +@@ -0,0 +1,19 @@ ++#define i2c0 i2c0if +#include "bcm2835.dtsi" ++#undef i2c0 +#include "bcm270x.dtsi" + +/ { @@ -5237,15 +6855,20 @@ + }; +}; + ++&soc { ++ dma-ranges = <0x80000000 0x00000000 0x20000000>, ++ <0x7e000000 0x20000000 0x02000000>; ++}; ++ +&vc4 { + status = "disabled"; +}; -diff --git a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +diff --git a/arch/arm/boot/dts/broadcom/bcm2709-rpi-2-b.dts b/arch/arm/boot/dts/broadcom/bcm2709-rpi-2-b.dts new file mode 100644 -index 000000000000..4c80d15981fe +index 000000000000..7796e545da43 --- /dev/null -+++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts -@@ -0,0 +1,131 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2709-rpi-2-b.dts +@@ -0,0 +1,204 @@ +/dts-v1/; + +#include "bcm2709.dtsi" @@ -5253,6 +6876,7 @@ +#include "bcm283x-rpi-smsc9514.dtsi" +#include "bcm283x-rpi-csi1-2lane.dtsi" +#include "bcm283x-rpi-i2c0mux_0_28.dtsi" ++#include "bcm283x-rpi-led-deprecated.dtsi" + +/ { + compatible = "raspberrypi,2-model-b", "brcm,bcm2836"; @@ -5260,6 +6884,71 @@ +}; + +&gpio { ++ /* ++ * Taken from rpi_SCH_2b_1p2_reduced.pdf and ++ * the official GPU firmware DT blob. ++ * ++ * Legend: ++ * "NC" = not connected (no rail from the SoC) ++ * "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", ++ "GPIO2", ++ "GPIO3", ++ "GPIO4", ++ "GPIO5", ++ "GPIO6", ++ "GPIO7", ++ "GPIO8", ++ "GPIO9", ++ "GPIO10", ++ "GPIO11", ++ "GPIO12", ++ "GPIO13", ++ "GPIO14", ++ "GPIO15", ++ "GPIO16", ++ "GPIO17", ++ "GPIO18", ++ "GPIO19", ++ "GPIO20", ++ "GPIO21", ++ "GPIO22", ++ "GPIO23", ++ "GPIO24", ++ "GPIO25", ++ "GPIO26", ++ "GPIO27", ++ "SDA0", ++ "SCL0", ++ "NC", /* GPIO30 */ ++ "LAN_RUN", ++ "CAM_GPIO1", ++ "NC", /* GPIO33 */ ++ "NC", /* GPIO34 */ ++ "PWR_LOW_N", ++ "NC", /* GPIO36 */ ++ "NC", /* GPIO37 */ ++ "USB_LIMIT", ++ "NC", /* GPIO39 */ ++ "PWM0_OUT", ++ "CAM_GPIO0", ++ "SMPS_SCL", ++ "SMPS_SDA", ++ "ETH_CLK", ++ "PWM1_OUT", ++ "HDMI_HPD_N", ++ "STATUS_LED", ++ /* Used by SD Card */ ++ "SD_CLK_R", ++ "SD_CMD_R", ++ "SD_DATA0_R", ++ "SD_DATA1_R", ++ "SD_DATA2_R", ++ "SD_DATA3_R"; ++ + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = <4>; /* alt0 */ @@ -5288,6 +6977,7 @@ + audio_pins: audio_pins { + brcm,pins = <40 45>; + brcm,function = <4>; ++ brcm,pull = <0>; + }; +}; + @@ -5336,17 +7026,18 @@ + pinctrl-0 = <&i2s_pins>; +}; + -+&leds { -+ act_led: led-act { -+ label = "led0"; -+ linux,default-trigger = "mmc0"; -+ gpios = <&gpio 47 0>; -+ }; ++&led_act { ++ gpios = <&gpio 47 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; ++}; + -+ pwr_led: led-pwr { -+ label = "led1"; ++&leds { ++ led_pwr: led-pwr { ++ label = "PWR"; ++ gpios = <&gpio 35 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; + linux,default-trigger = "input"; -+ gpios = <&gpio 35 0>; + }; +}; + @@ -5354,7 +7045,7 @@ + hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>; +}; + -+&audio { ++&vchiq { + pinctrl-names = "default"; + pinctrl-0 = <&audio_pins>; +}; @@ -5366,35 +7057,274 @@ +cam0_reg: &cam_dummy_reg { +}; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ +/ { + __overrides__ { -+ act_led_gpio = <&act_led>,"gpios:4"; -+ act_led_activelow = <&act_led>,"gpios:8"; -+ act_led_trigger = <&act_led>,"linux,default-trigger"; ++ audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_headphones=1 snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_headphones=0 snd_bcm2835.enable_hdmi=0'}"; + -+ pwr_led_gpio = <&pwr_led>,"gpios:4"; -+ pwr_led_activelow = <&pwr_led>,"gpios:8"; -+ pwr_led_trigger = <&pwr_led>,"linux,default-trigger"; ++ act_led_gpio = <&led_act>,"gpios:4"; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>,"linux,default-trigger"; ++ ++ pwr_led_gpio = <&led_pwr>,"gpios:4"; ++ pwr_led_activelow = <&led_pwr>,"gpios:8"; ++ pwr_led_trigger = <&led_pwr>,"linux,default-trigger"; + }; +}; -diff --git a/arch/arm/boot/dts/bcm2709-rpi.dtsi b/arch/arm/boot/dts/bcm2709-rpi.dtsi +diff --git a/arch/arm/boot/dts/broadcom/bcm2709-rpi-cm2.dts b/arch/arm/boot/dts/broadcom/bcm2709-rpi-cm2.dts new file mode 100644 -index 000000000000..babfa41cd9f7 +index 000000000000..396771880798 --- /dev/null -+++ b/arch/arm/boot/dts/bcm2709-rpi.dtsi -@@ -0,0 +1,5 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2709-rpi-cm2.dts +@@ -0,0 +1,223 @@ ++/dts-v1/; ++ ++#include "bcm2709.dtsi" ++#include "bcm2709-rpi.dtsi" ++#include "bcm283x-rpi-csi0-2lane.dtsi" ++#include "bcm283x-rpi-csi1-4lane.dtsi" ++#include "bcm283x-rpi-i2c0mux_0_28.dtsi" ++#include "bcm283x-rpi-led-deprecated.dtsi" ++ ++/ { ++ compatible = "raspberrypi,2-compute-module", "brcm,bcm2836"; ++ model = "Raspberry Pi Compute Module 2"; ++}; ++ ++&cam1_reg { ++ gpio = <&gpio 2 GPIO_ACTIVE_HIGH>; ++ status = "disabled"; ++}; ++ ++cam0_reg: &cam0_regulator { ++ gpio = <&gpio 30 GPIO_ACTIVE_HIGH>; ++}; ++ ++i2c_csi_dsi0: &i2c0 { ++}; ++ ++&uart0 { ++ status = "okay"; ++}; ++ ++&gpio { ++ /* ++ * This is based on the official GPU firmware DT blob. ++ * ++ * Legend: ++ * "NC" = not connected (no rail from the SoC) ++ * "FOO" = GPIO line named "FOO" on the schematic ++ * "FOO_N" = GPIO line named "FOO" on schematic, active low ++ */ ++ gpio-line-names = "GPIO0", ++ "GPIO1", ++ "GPIO2", ++ "GPIO3", ++ "GPIO4", ++ "GPIO5", ++ "GPIO6", ++ "GPIO7", ++ "GPIO8", ++ "GPIO9", ++ "GPIO10", ++ "GPIO11", ++ "GPIO12", ++ "GPIO13", ++ "GPIO14", ++ "GPIO15", ++ "GPIO16", ++ "GPIO17", ++ "GPIO18", ++ "GPIO19", ++ "GPIO20", ++ "GPIO21", ++ "GPIO22", ++ "GPIO23", ++ "GPIO24", ++ "GPIO25", ++ "GPIO26", ++ "GPIO27", ++ "GPIO28", ++ "GPIO29", ++ "GPIO30", ++ "GPIO31", ++ "GPIO32", ++ "GPIO33", ++ "GPIO34", ++ "GPIO35", ++ "GPIO36", ++ "GPIO37", ++ "GPIO38", ++ "GPIO39", ++ "GPIO40", ++ "GPIO41", ++ "GPIO42", ++ "GPIO43", ++ "GPIO44", ++ "GPIO45", ++ "SMPS_SCL", ++ "SMPS_SDA", ++ /* Used by eMMC */ ++ "SD_CLK_R", ++ "SD_CMD_R", ++ "SD_DATA0_R", ++ "SD_DATA1_R", ++ "SD_DATA2_R", ++ "SD_DATA3_R"; ++ ++ 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>; ++ gpio-line-names = "HDMI_HPD_N", ++ "EMMC_EN_N", ++ "NC", ++ "NC", ++ "NC", ++ "NC", ++ "NC", ++ "NC"; ++ 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>; ++}; ++ ++&led_act { ++ gpios = <&virtgpio 0 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; ++}; ++ ++&hdmi { ++ hpd-gpios = <&expgpio 0 GPIO_ACTIVE_LOW>; ++}; ++ ++&vchiq { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&audio_pins>; ++}; ++ ++/ { ++ __overrides__ { ++ audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_hdmi=0'}"; ++ ++ act_led_gpio = <&led_act>,"gpios:4"; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>,"linux,default-trigger"; ++ cam0_reg = <&cam0_reg>,"status"; ++ cam0_reg_gpio = <&cam0_reg>,"gpio:4"; ++ cam1_reg = <&cam1_reg>,"status"; ++ cam1_reg_gpio = <&cam1_reg>,"gpio:4"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/broadcom/bcm2709-rpi.dtsi b/arch/arm/boot/dts/broadcom/bcm2709-rpi.dtsi +new file mode 100644 +index 000000000000..7335e7fbcb71 +--- /dev/null ++++ b/arch/arm/boot/dts/broadcom/bcm2709-rpi.dtsi +@@ -0,0 +1,8 @@ +#include "bcm2708-rpi.dtsi" + +&vchiq { + compatible = "brcm,bcm2836-vchiq", "brcm,bcm2835-vchiq"; +}; -diff --git a/arch/arm/boot/dts/bcm2709.dtsi b/arch/arm/boot/dts/bcm2709.dtsi ++ ++i2c_arm: &i2c1 {}; ++i2c_vc: &i2c0 {}; +diff --git a/arch/arm/boot/dts/broadcom/bcm2709.dtsi b/arch/arm/boot/dts/broadcom/bcm2709.dtsi new file mode 100644 -index 000000000000..68eafc1b281a +index 000000000000..868f65f922ff --- /dev/null -+++ b/arch/arm/boot/dts/bcm2709.dtsi -@@ -0,0 +1,22 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2709.dtsi +@@ -0,0 +1,29 @@ ++#define i2c0 i2c0if +#include "bcm2836.dtsi" ++#undef i2c0 +#include "bcm270x.dtsi" + +/ { @@ -5402,7 +7332,8 @@ + ranges = <0x7e000000 0x3f000000 0x01000000>, + <0x40000000 0x40000000 0x00040000>; + -+ /delete-node/ timer@7e003000; ++ dma-ranges = <0xc0000000 0x00000000 0x3f000000>, ++ <0x7e000000 0x3f000000 0x01000000>; + }; + + __overrides__ { @@ -5413,20 +7344,23 @@ + }; +}; + ++&system_timer { ++ status = "disabled"; ++}; ++ +&vc4 { + status = "disabled"; +}; -diff --git a/arch/arm/boot/dts/bcm270x-rpi.dtsi b/arch/arm/boot/dts/bcm270x-rpi.dtsi +diff --git a/arch/arm/boot/dts/broadcom/bcm270x-rpi.dtsi b/arch/arm/boot/dts/broadcom/bcm270x-rpi.dtsi new file mode 100644 -index 000000000000..57e7d5f60d3e +index 000000000000..360fb05fe80e --- /dev/null -+++ b/arch/arm/boot/dts/bcm270x-rpi.dtsi -@@ -0,0 +1,155 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm270x-rpi.dtsi +@@ -0,0 +1,186 @@ +/* Downstream modifications to bcm2835-rpi.dtsi */ + +/ { -+ aliases { -+ audio = &audio; ++ aliases: aliases { + aux = &aux; + sound = &sound; + soc = &soc; @@ -5446,6 +7380,7 @@ + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c10 = &i2c_csi_dsi; ++ i2c = &i2c_arm; + spi0 = &spi0; + spi1 = &spi1; + spi2 = &spi2; @@ -5473,10 +7408,6 @@ + regulator-name = "5v0"; + }; + -+ leds: leds { -+ compatible = "gpio-leds"; -+ }; -+ + soc { + gpiomem { + compatible = "brcm,bcm2835-gpiomem"; @@ -5504,10 +7435,15 @@ + spi = <&spi0>,"status"; + i2c0 = <&i2c0if>,"status",<&i2c0mux>,"status"; + i2c1 = <&i2c1>,"status"; ++ i2c = <&i2c1>,"status"; ++ i2c_arm = <&i2c1>,"status"; ++ i2c_vc = <&i2c0if>,"status",<&i2c0mux>,"status"; + i2c0_baudrate = <&i2c0if>,"clock-frequency:0"; + i2c1_baudrate = <&i2c1>,"clock-frequency:0"; ++ i2c_baudrate = <&i2c1>,"clock-frequency:0"; ++ i2c_arm_baudrate = <&i2c1>,"clock-frequency:0"; ++ i2c_vc_baudrate = <&i2c0if>,"clock-frequency:0"; + -+ audio = <&audio>,"status"; + watchdog = <&watchdog>,"status"; + random = <&random>,"status"; + sd_overclock = <&sdhost>,"brcm,overclock-50:0"; @@ -5517,6 +7453,9 @@ + sdio_overclock = <&mmc>,"brcm,overclock-50:0", + <&mmcnr>,"brcm,overclock-50:0"; + axiperf = <&axiperf>,"status"; ++ drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4; ++ drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4; ++ drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4; + }; +}; + @@ -5537,6 +7476,8 @@ +}; + +&i2c0mux { ++ pinctrl-names = "i2c0", "i2c_csi_dsi"; ++ /delete-property/ clock-frequency; + status = "disabled"; +}; + @@ -5544,6 +7485,9 @@ + status = "disabled"; +}; + ++i2s_clk_producer: &i2s {}; ++i2s_clk_consumer: &i2s {}; ++ +&clocks { + firmware = <&firmware>; +}; @@ -5555,45 +7499,67 @@ +}; + +&cpu_thermal { -+ /delete-node/ trips; ++ // Add some labels ++ thermal_trips: trips { ++ cpu-crit { ++ // Raise upstream limit of 90C ++ temperature = <110000>; ++ }; ++ }; ++ cooling_maps: cooling-maps { ++ }; +}; + +&vec { ++ clocks = <&firmware_clocks 15>; + status = "disabled"; +}; + -+&vchiq { -+ /* Onboard audio */ -+ audio: bcm2835_audio { -+ compatible = "brcm,bcm2835-audio"; -+ brcm,firmware = <&firmware>; -+ brcm,pwm-channels = <8>; -+ status = "disabled"; ++&firmware { ++#ifndef BCM2711 ++ firmware_clocks: clocks { ++ compatible = "raspberrypi,firmware-clocks"; ++ #clock-cells = <1>; + }; -+}; ++#endif + -+&firmware { + vcio: vcio { + compatible = "raspberrypi,vcio"; + }; +}; -diff --git a/arch/arm/boot/dts/bcm270x.dtsi b/arch/arm/boot/dts/bcm270x.dtsi ++ ++&vc4 { ++ raspberrypi,firmware = <&firmware>; ++}; ++ ++#ifndef BCM2711 ++ ++&hdmi { ++ reg-names = "hdmi", ++ "hd"; ++ clocks = <&firmware_clocks 9>, ++ <&firmware_clocks 13>; ++ dmas = <&dma (17|(1<<27)|(1<<24))>; ++}; ++ ++#endif +diff --git a/arch/arm/boot/dts/broadcom/bcm270x.dtsi b/arch/arm/boot/dts/broadcom/bcm270x.dtsi new file mode 100644 -index 000000000000..a5cabb5bc4a1 +index 000000000000..c318080eb883 --- /dev/null -+++ b/arch/arm/boot/dts/bcm270x.dtsi -@@ -0,0 +1,272 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm270x.dtsi +@@ -0,0 +1,294 @@ +/* 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; ++ chosen: chosen { ++ // Disable audio by default ++ bootargs = "coherent_pool=1M snd_bcm2835.enable_headphones=0"; ++ stdout-path = "serial0:115200n8"; + }; + + soc: soc { -+ + watchdog: watchdog@7e100000 { + /* Add label */ + }; @@ -5736,6 +7702,28 @@ + firmware = <&firmware>; + status = "disabled"; + }; ++ ++ i2c0mux: i2c0mux { ++ compatible = "i2c-mux-pinctrl"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ i2c-parent = <&i2c0if>; ++ ++ 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>; ++ }; ++ }; + }; + + cam1_reg: cam1_regulator { @@ -5855,12 +7843,12 @@ + dmas = <&dma 6>, <&dma 7>; + dma-names = "tx", "rx"; +}; -diff --git a/arch/arm/boot/dts/bcm2710-rpi-2-b.dts b/arch/arm/boot/dts/bcm2710-rpi-2-b.dts +diff --git a/arch/arm/boot/dts/broadcom/bcm2710-rpi-2-b.dts b/arch/arm/boot/dts/broadcom/bcm2710-rpi-2-b.dts new file mode 100644 -index 000000000000..a8a18ef4d1bf +index 000000000000..ce48eb6073f0 --- /dev/null -+++ b/arch/arm/boot/dts/bcm2710-rpi-2-b.dts -@@ -0,0 +1,131 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-2-b.dts +@@ -0,0 +1,204 @@ +/dts-v1/; + +#include "bcm2710.dtsi" @@ -5868,6 +7856,7 @@ +#include "bcm283x-rpi-smsc9514.dtsi" +#include "bcm283x-rpi-csi1-2lane.dtsi" +#include "bcm283x-rpi-i2c0mux_0_28.dtsi" ++#include "bcm283x-rpi-led-deprecated.dtsi" + +/ { + compatible = "raspberrypi,2-model-b-rev2", "brcm,bcm2837"; @@ -5875,6 +7864,71 @@ +}; + +&gpio { ++ /* ++ * Taken from rpi_SCH_2b_1p2_reduced.pdf and ++ * the official GPU firmware DT blob. ++ * ++ * Legend: ++ * "NC" = not connected (no rail from the SoC) ++ * "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", ++ "GPIO2", ++ "GPIO3", ++ "GPIO4", ++ "GPIO5", ++ "GPIO6", ++ "GPIO7", ++ "GPIO8", ++ "GPIO9", ++ "GPIO10", ++ "GPIO11", ++ "GPIO12", ++ "GPIO13", ++ "GPIO14", ++ "GPIO15", ++ "GPIO16", ++ "GPIO17", ++ "GPIO18", ++ "GPIO19", ++ "GPIO20", ++ "GPIO21", ++ "GPIO22", ++ "GPIO23", ++ "GPIO24", ++ "GPIO25", ++ "GPIO26", ++ "GPIO27", ++ "SDA0", ++ "SCL0", ++ "NC", /* GPIO30 */ ++ "LAN_RUN", ++ "CAM_GPIO1", ++ "NC", /* GPIO33 */ ++ "NC", /* GPIO34 */ ++ "PWR_LOW_N", ++ "NC", /* GPIO36 */ ++ "NC", /* GPIO37 */ ++ "USB_LIMIT", ++ "NC", /* GPIO39 */ ++ "PWM0_OUT", ++ "CAM_GPIO0", ++ "SMPS_SCL", ++ "SMPS_SDA", ++ "ETH_CLK", ++ "PWM1_OUT", ++ "HDMI_HPD_N", ++ "STATUS_LED", ++ /* Used by SD Card */ ++ "SD_CLK_R", ++ "SD_CMD_R", ++ "SD_DATA0_R", ++ "SD_DATA1_R", ++ "SD_DATA2_R", ++ "SD_DATA3_R"; ++ + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = <4>; /* alt0 */ @@ -5903,6 +7957,7 @@ + audio_pins: audio_pins { + brcm,pins = <40 45>; + brcm,function = <4>; ++ brcm,pull = <0>; + }; +}; + @@ -5951,17 +8006,18 @@ + pinctrl-0 = <&i2s_pins>; +}; + -+&leds { -+ act_led: led-act { -+ label = "led0"; -+ linux,default-trigger = "mmc0"; -+ gpios = <&gpio 47 0>; -+ }; ++&led_act { ++ gpios = <&gpio 47 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; ++}; + -+ pwr_led: led-pwr { -+ label = "led1"; ++&leds { ++ led_pwr: led-pwr { ++ label = "PWR"; ++ gpios = <&gpio 35 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; + linux,default-trigger = "input"; -+ gpios = <&gpio 35 0>; + }; +}; + @@ -5969,7 +8025,7 @@ + hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>; +}; + -+&audio { ++&vchiq { + pinctrl-names = "default"; + pinctrl-0 = <&audio_pins>; +}; @@ -5981,23 +8037,28 @@ +cam0_reg: &cam_dummy_reg { +}; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ +/ { + __overrides__ { -+ act_led_gpio = <&act_led>,"gpios:4"; -+ act_led_activelow = <&act_led>,"gpios:8"; -+ act_led_trigger = <&act_led>,"linux,default-trigger"; ++ audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_headphones=1 snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_headphones=0 snd_bcm2835.enable_hdmi=0'}"; + -+ pwr_led_gpio = <&pwr_led>,"gpios:4"; -+ pwr_led_activelow = <&pwr_led>,"gpios:8"; -+ pwr_led_trigger = <&pwr_led>,"linux,default-trigger"; ++ act_led_gpio = <&led_act>,"gpios:4"; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>,"linux,default-trigger"; ++ ++ pwr_led_gpio = <&led_pwr>,"gpios:4"; ++ pwr_led_activelow = <&led_pwr>,"gpios:8"; ++ pwr_led_trigger = <&led_pwr>,"linux,default-trigger"; + }; +}; -diff --git a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts +diff --git a/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts b/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts new file mode 100644 -index 000000000000..93f9c8dddbca +index 000000000000..1afbb9011702 --- /dev/null -+++ b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts -@@ -0,0 +1,210 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts +@@ -0,0 +1,299 @@ +/dts-v1/; + +#include "bcm2710.dtsi" @@ -6006,13 +8067,14 @@ +#include "bcm283x-rpi-csi1-2lane.dtsi" +#include "bcm283x-rpi-i2c0mux_0_44.dtsi" +#include "bcm271x-rpi-bt.dtsi" ++#include "bcm283x-rpi-led-deprecated.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"; ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; + }; + + aliases { @@ -6023,6 +8085,73 @@ +}; + +&gpio { ++ /* ++ * Taken from rpi_SCH_3bplus_1p0_reduced.pdf and ++ * the official GPU firmware DT blob. ++ * ++ * Legend: ++ * "NC" = not connected (no rail from the SoC) ++ * "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", ++ "GPIO2", ++ "GPIO3", ++ "GPIO4", ++ "GPIO5", ++ "GPIO6", ++ "GPIO7", ++ "GPIO8", ++ "GPIO9", ++ "GPIO10", ++ "GPIO11", ++ "GPIO12", ++ "GPIO13", ++ "GPIO14", ++ "GPIO15", ++ "GPIO16", ++ "GPIO17", ++ "GPIO18", ++ "GPIO19", ++ "GPIO20", ++ "GPIO21", ++ "GPIO22", ++ "GPIO23", ++ "GPIO24", ++ "GPIO25", ++ "GPIO26", ++ "GPIO27", ++ "HDMI_HPD_N", ++ "STATUS_LED_G", ++ /* Used by BT module */ ++ "CTS0", ++ "RTS0", ++ "TXD0", ++ "RXD0", ++ /* Used by Wifi */ ++ "SD1_CLK", ++ "SD1_CMD", ++ "SD1_DATA0", ++ "SD1_DATA1", ++ "SD1_DATA2", ++ "SD1_DATA3", ++ "PWM0_OUT", ++ "PWM1_OUT", ++ "ETH_CLK", ++ "WIFI_CLK", ++ "SDA0", ++ "SCL0", ++ "SMPS_SCL", ++ "SMPS_SDA", ++ /* Used by SD Card */ ++ "SD_CLK_R", ++ "SD_CMD_R", ++ "SD_DATA0_R", ++ "SD_DATA1_R", ++ "SD_DATA2_R", ++ "SD_DATA3_R"; ++ + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = <4>; /* alt0 */ @@ -6072,9 +8201,16 @@ + brcm,pull; + }; + ++ uart1_bt_pins: uart1_bt_pins { ++ brcm,pins = <32 33 30 31>; ++ brcm,function = <BCM2835_FSEL_ALT5>; /* alt5=UART1 */ ++ brcm,pull = <0 2 2 0>; ++ }; ++ + audio_pins: audio_pins { + brcm,pins = <40 41>; + brcm,function = <4>; ++ brcm,pull = <0>; + }; +}; + @@ -6097,6 +8233,14 @@ + compatible = "raspberrypi,firmware-gpio"; + gpio-controller; + #gpio-cells = <2>; ++ gpio-line-names = "BT_ON", ++ "WL_ON", ++ "PWR_LED_R", ++ "LAN_RUN", ++ "NC", ++ "CAM_GPIO0", ++ "CAM_GPIO1", ++ "NC"; + status = "okay"; + }; +}; @@ -6154,17 +8298,18 @@ + pinctrl-0 = <&i2s_pins>; +}; + -+&leds { -+ act_led: led-act { -+ label = "led0"; -+ linux,default-trigger = "mmc0"; -+ gpios = <&gpio 29 0>; -+ }; ++&led_act { ++ gpios = <&gpio 29 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; ++}; + -+ pwr_led: led-pwr { -+ label = "led1"; -+ linux,default-trigger = "default-on"; ++&leds { ++ led_pwr: led-pwr { ++ label = "PWR"; + gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ linux,default-trigger = "default-on"; + }; +}; + @@ -6172,7 +8317,7 @@ + hpd-gpios = <&gpio 28 GPIO_ACTIVE_LOW>; +}; + -+&audio { ++&vchiq { + pinctrl-names = "default"; + pinctrl-0 = <&audio_pins>; +}; @@ -6190,15 +8335,20 @@ +cam0_reg: &cam_dummy_reg { +}; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ +/ { + __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"; ++ audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_headphones=1 snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_headphones=0 snd_bcm2835.enable_hdmi=0'}"; ++ ++ act_led_gpio = <&led_act>,"gpios:4"; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>,"linux,default-trigger"; ++ ++ pwr_led_gpio = <&led_pwr>,"gpios:4"; ++ pwr_led_activelow = <&led_pwr>,"gpios:8"; ++ pwr_led_trigger = <&led_pwr>,"linux,default-trigger"; + + eee = <ð_phy>,"microchip,eee-enabled?"; + tx_lpi_timer = <ð_phy>,"microchip,tx-lpi-timer:0"; @@ -6208,12 +8358,12 @@ + eth_max_speed = <ð_phy>,"max-speed:0"; + }; +}; -diff --git a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts +diff --git a/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b.dts b/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b.dts new file mode 100644 -index 000000000000..bc5d086beb93 +index 000000000000..b893affe6997 --- /dev/null -+++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts -@@ -0,0 +1,212 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b.dts +@@ -0,0 +1,297 @@ +/dts-v1/; + +#include "bcm2710.dtsi" @@ -6222,13 +8372,14 @@ +#include "bcm283x-rpi-csi1-2lane.dtsi" +#include "bcm283x-rpi-i2c0mux_0_44.dtsi" +#include "bcm271x-rpi-bt.dtsi" ++#include "bcm283x-rpi-led-deprecated.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"; ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; + }; + + aliases { @@ -6239,6 +8390,73 @@ +}; + +&gpio { ++ /* ++ * Taken from rpi_SCH_3b_1p2_reduced.pdf and ++ * the official GPU firmware DT blob. ++ * ++ * Legend: ++ * "NC" = not connected (no rail from the SoC) ++ * "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", ++ "GPIO2", ++ "GPIO3", ++ "GPIO4", ++ "GPIO5", ++ "GPIO6", ++ "GPIO7", ++ "GPIO8", ++ "GPIO9", ++ "GPIO10", ++ "GPIO11", ++ "GPIO12", ++ "GPIO13", ++ "GPIO14", ++ "GPIO15", ++ "GPIO16", ++ "GPIO17", ++ "GPIO18", ++ "GPIO19", ++ "GPIO20", ++ "GPIO21", ++ "GPIO22", ++ "GPIO23", ++ "GPIO24", ++ "GPIO25", ++ "GPIO26", ++ "GPIO27", ++ "NC", /* GPIO 28 */ ++ "LAN_RUN_BOOT", ++ /* Used by BT module */ ++ "CTS0", ++ "RTS0", ++ "TXD0", ++ "RXD0", ++ /* Used by Wifi */ ++ "SD1_CLK", ++ "SD1_CMD", ++ "SD1_DATA0", ++ "SD1_DATA1", ++ "SD1_DATA2", ++ "SD1_DATA3", ++ "PWM0_OUT", ++ "PWM1_OUT", ++ "ETH_CLK", ++ "WIFI_CLK", ++ "SDA0", ++ "SCL0", ++ "SMPS_SCL", ++ "SMPS_SDA", ++ /* Used by SD Card */ ++ "SD_CLK_R", ++ "SD_CMD_R", ++ "SD_DATA0_R", ++ "SD_DATA1_R", ++ "SD_DATA2_R", ++ "SD_DATA3_R"; ++ + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = <4>; /* alt0 */ @@ -6288,9 +8506,16 @@ + brcm,pull; + }; + ++ uart1_bt_pins: uart1_bt_pins { ++ brcm,pins = <32 33>; ++ brcm,function = <BCM2835_FSEL_ALT5>; /* alt5=UART1 */ ++ brcm,pull = <0 2>; ++ }; ++ + audio_pins: audio_pins { + brcm,pins = <40 41>; + brcm,function = <4>; ++ brcm,pull = <0>; + }; +}; + @@ -6308,20 +8533,24 @@ + }; +}; + -+&soc { -+ virtgpio: virtgpio { -+ compatible = "brcm,bcm2835-virtgpio"; ++&firmware { ++ expgpio: expgpio { ++ compatible = "raspberrypi,firmware-gpio"; + gpio-controller; + #gpio-cells = <2>; -+ firmware = <&firmware>; ++ gpio-line-names = "BT_ON", ++ "WL_ON", ++ "STATUS_LED", ++ "LAN_RUN", ++ "HDMI_HPD_N", ++ "CAM_GPIO0", ++ "CAM_GPIO1", ++ "PWR_LOW_N"; + status = "okay"; + }; + -+}; -+ -+&firmware { -+ expgpio: expgpio { -+ compatible = "raspberrypi,firmware-gpio"; ++ virtgpio: virtgpio { ++ compatible = "brcm,bcm2835-virtgpio"; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; @@ -6385,17 +8614,18 @@ + pinctrl-0 = <&i2s_pins>; +}; + -+&leds { -+ act_led: led-act { -+ label = "led0"; -+ linux,default-trigger = "mmc0"; -+ gpios = <&virtgpio 0 0>; -+ }; ++&led_act { ++ gpios = <&virtgpio 0 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; ++}; + -+ pwr_led: led-pwr { -+ label = "led1"; ++&leds { ++ led_pwr: led-pwr { ++ label = "PWR"; ++ gpios = <&expgpio 7 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; + linux,default-trigger = "input"; -+ gpios = <&expgpio 7 0>; + }; +}; + @@ -6403,7 +8633,7 @@ + hpd-gpios = <&expgpio 4 GPIO_ACTIVE_LOW>; +}; + -+&audio { ++&vchiq { + pinctrl-names = "default"; + pinctrl-0 = <&audio_pins>; +}; @@ -6415,23 +8645,28 @@ +cam0_reg: &cam_dummy_reg { +}; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ +/ { + __overrides__ { -+ act_led_gpio = <&act_led>,"gpios:4"; -+ act_led_activelow = <&act_led>,"gpios:8"; -+ act_led_trigger = <&act_led>,"linux,default-trigger"; ++ audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_headphones=1 snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_headphones=0 snd_bcm2835.enable_hdmi=0'}"; ++ ++ act_led_gpio = <&led_act>,"gpios:4"; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>,"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"; ++ pwr_led_gpio = <&led_pwr>,"gpios:4"; ++ pwr_led_activelow = <&led_pwr>,"gpios:8"; ++ pwr_led_trigger = <&led_pwr>,"linux,default-trigger"; + }; +}; -diff --git a/arch/arm/boot/dts/bcm2710-rpi-cm3.dts b/arch/arm/boot/dts/bcm2710-rpi-cm3.dts +diff --git a/arch/arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts b/arch/arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts new file mode 100644 -index 000000000000..517ed47c257d +index 000000000000..08a33038e3f5 --- /dev/null -+++ b/arch/arm/boot/dts/bcm2710-rpi-cm3.dts -@@ -0,0 +1,146 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts +@@ -0,0 +1,223 @@ +/dts-v1/; + +#include "bcm2710.dtsi" @@ -6439,18 +8674,23 @@ +#include "bcm283x-rpi-csi0-2lane.dtsi" +#include "bcm283x-rpi-csi1-4lane.dtsi" +#include "bcm283x-rpi-i2c0mux_0_28.dtsi" ++#include "bcm283x-rpi-led-deprecated.dtsi" ++ +/ { + compatible = "raspberrypi,3-compute-module", "brcm,bcm2837"; + model = "Raspberry Pi Compute Module 3"; +}; + +&cam1_reg { -+ gpio = <&gpio 2 GPIO_ACTIVE_HIGH>; ++ gpio = <&gpio 3 GPIO_ACTIVE_HIGH>; + status = "disabled"; +}; + +cam0_reg: &cam0_regulator { -+ gpio = <&gpio 30 GPIO_ACTIVE_HIGH>; ++ gpio = <&gpio 31 GPIO_ACTIVE_HIGH>; ++}; ++ ++i2c_csi_dsi0: &i2c0 { +}; + +&uart0 { @@ -6458,6 +8698,70 @@ +}; + +&gpio { ++ /* ++ * This is based on the official GPU firmware DT blob. ++ * ++ * Legend: ++ * "NC" = not connected (no rail from the SoC) ++ * "FOO" = GPIO line named "FOO" on the schematic ++ * "FOO_N" = GPIO line named "FOO" on schematic, active low ++ */ ++ gpio-line-names = "GPIO0", ++ "GPIO1", ++ "GPIO2", ++ "GPIO3", ++ "GPIO4", ++ "GPIO5", ++ "GPIO6", ++ "GPIO7", ++ "GPIO8", ++ "GPIO9", ++ "GPIO10", ++ "GPIO11", ++ "GPIO12", ++ "GPIO13", ++ "GPIO14", ++ "GPIO15", ++ "GPIO16", ++ "GPIO17", ++ "GPIO18", ++ "GPIO19", ++ "GPIO20", ++ "GPIO21", ++ "GPIO22", ++ "GPIO23", ++ "GPIO24", ++ "GPIO25", ++ "GPIO26", ++ "GPIO27", ++ "GPIO28", ++ "GPIO29", ++ "GPIO30", ++ "GPIO31", ++ "GPIO32", ++ "GPIO33", ++ "GPIO34", ++ "GPIO35", ++ "GPIO36", ++ "GPIO37", ++ "GPIO38", ++ "GPIO39", ++ "GPIO40", ++ "GPIO41", ++ "GPIO42", ++ "GPIO43", ++ "GPIO44", ++ "GPIO45", ++ "SMPS_SCL", ++ "SMPS_SDA", ++ /* Used by eMMC */ ++ "SD_CLK_R", ++ "SD_CMD_R", ++ "SD_DATA0_R", ++ "SD_DATA1_R", ++ "SD_DATA2_R", ++ "SD_DATA3_R"; ++ + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = <4>; /* alt0 */ @@ -6505,6 +8809,14 @@ + compatible = "raspberrypi,firmware-gpio"; + gpio-controller; + #gpio-cells = <2>; ++ gpio-line-names = "HDMI_HPD_N", ++ "EMMC_EN_N", ++ "NC", ++ "NC", ++ "NC", ++ "NC", ++ "NC", ++ "NC"; + status = "okay"; + }; +}; @@ -6550,40 +8862,40 @@ + pinctrl-0 = <&i2s_pins>; +}; + -+&leds { -+ act_led: led-act { -+ label = "led0"; -+ linux,default-trigger = "mmc0"; -+ gpios = <&virtgpio 0 0>; -+ }; ++&led_act { ++ gpios = <&virtgpio 0 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; +}; + +&hdmi { + hpd-gpios = <&expgpio 0 GPIO_ACTIVE_LOW>; +}; + -+&audio { ++&vchiq { + 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"; ++ audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_hdmi=0'}"; ++ ++ act_led_gpio = <&led_act>,"gpios:4"; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>,"linux,default-trigger"; + cam0_reg = <&cam0_reg>,"status"; -+ cam0_reg_gpio = <&cam0_reg>,"gpios:4"; ++ cam0_reg_gpio = <&cam0_reg>,"gpio:4"; + cam1_reg = <&cam1_reg>,"status"; -+ cam1_reg_gpio = <&cam1_reg>,"gpios:4"; ++ cam1_reg_gpio = <&cam1_reg>,"gpio:4"; + }; +}; -diff --git a/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts b/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts +diff --git a/arch/arm/boot/dts/broadcom/bcm2710-rpi-zero-2-w.dts b/arch/arm/boot/dts/broadcom/bcm2710-rpi-zero-2-w.dts new file mode 100644 -index 000000000000..38629ebfa47f +index 000000000000..25182d73f244 --- /dev/null -+++ b/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts -@@ -0,0 +1,199 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-zero-2-w.dts +@@ -0,0 +1,261 @@ +/dts-v1/; + +#include "bcm2710.dtsi" @@ -6591,13 +8903,14 @@ +#include "bcm283x-rpi-csi1-2lane.dtsi" +#include "bcm283x-rpi-i2c0mux_0_44.dtsi" +#include "bcm2708-rpi-bt.dtsi" ++#include "bcm283x-rpi-led-deprecated.dtsi" + +/ { + compatible = "raspberrypi,model-zero-2-w", "brcm,bcm2837"; + model = "Raspberry Pi Zero 2 W"; + + chosen { -+ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1"; ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; + }; + + aliases { @@ -6608,6 +8921,72 @@ +}; + +&gpio { ++ /* ++ * This is based on the official GPU firmware DT blob. ++ * ++ * Legend: ++ * "NC" = not connected (no rail from the SoC) ++ * "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", ++ "GPIO2", ++ "GPIO3", ++ "GPIO4", ++ "GPIO5", ++ "GPIO6", ++ "GPIO7", ++ "GPIO8", ++ "GPIO9", ++ "GPIO10", ++ "GPIO11", ++ "GPIO12", ++ "GPIO13", ++ "GPIO14", ++ "GPIO15", ++ "GPIO16", ++ "GPIO17", ++ "GPIO18", ++ "GPIO19", ++ "GPIO20", ++ "GPIO21", ++ "GPIO22", ++ "GPIO23", ++ "GPIO24", ++ "GPIO25", ++ "GPIO26", ++ "GPIO27", ++ "HDMI_HPD_N", ++ "STATUS_LED_N", ++ /* Used by BT module */ ++ "CTS0", ++ "RTS0", ++ "TXD0", ++ "RXD0", ++ /* Used by Wifi */ ++ "SD1_CLK", ++ "SD1_CMD", ++ "SD1_DATA0", ++ "SD1_DATA1", ++ "SD1_DATA2", ++ "SD1_DATA3", ++ "CAM_GPIO1", /* GPIO40 */ ++ "WL_ON", /* GPIO41 */ ++ "BT_ON", /* GPIO42 */ ++ "WIFI_CLK", /* GPIO43 */ ++ "SDA0", /* GPIO44 */ ++ "SCL0", /* GPIO45 */ ++ "SMPS_SCL", /* GPIO46 */ ++ "SMPS_SDA", /* GPIO47 */ ++ /* Used by SD Card */ ++ "SD_CLK_R", ++ "SD_CMD_R", ++ "SD_DATA0_R", ++ "SD_DATA1_R", ++ "SD_DATA2_R", ++ "SD_DATA3_R"; ++ + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = <4>; /* alt0 */ @@ -6657,6 +9036,12 @@ + brcm,pull; + }; + ++ uart1_bt_pins: uart1_bt_pins { ++ brcm,pins = <32 33 30 31>; ++ brcm,function = <BCM2835_FSEL_ALT5>; /* alt5=UART1 */ ++ brcm,pull = <0 2 2 0>; ++ }; ++ + audio_pins: audio_pins { + brcm,pins = <>; + brcm,function = <>; @@ -6674,19 +9059,6 @@ + brcmf: wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; -+ -+ firmwares { -+ fw_43436p { -+ chipid = <43430>; -+ revmask = <4>; -+ fw_base = "brcm/brcmfmac43436-sdio"; -+ }; -+ fw_43436s { -+ chipid = <43430>; -+ revmask = <2>; -+ fw_base = "brcm/brcmfmac43436s-sdio"; -+ }; -+ }; + }; +}; + @@ -6743,22 +9115,19 @@ + pinctrl-0 = <&i2s_pins>; +}; + -+&leds { -+ act_led: led-act { -+ label = "led0"; -+ linux,default-trigger = "actpwr"; -+ gpios = <&gpio 29 GPIO_ACTIVE_LOW>; -+ }; ++&led_act { ++ gpios = <&gpio 29 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ linux,default-trigger = "actpwr"; +}; + +&hdmi { + hpd-gpios = <&gpio 28 GPIO_ACTIVE_LOW>; +}; + -+&audio { ++&vchiq { + pinctrl-names = "default"; + pinctrl-0 = <&audio_pins>; -+ brcm,disable-headphones = <1>; +}; + +&bt { @@ -6776,27 +9145,34 @@ +cam0_reg: &cam_dummy_reg { +}; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ +/ { + __overrides__ { -+ act_led_gpio = <&act_led>,"gpios:4"; -+ act_led_activelow = <&act_led>,"gpios:8"; -+ act_led_trigger = <&act_led>,"linux,default-trigger"; ++ audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_hdmi=0'}"; ++ ++ act_led_gpio = <&led_act>,"gpios:4"; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>,"linux,default-trigger"; + }; +}; -diff --git a/arch/arm/boot/dts/bcm2710-rpi-zero-2.dts b/arch/arm/boot/dts/bcm2710-rpi-zero-2.dts +diff --git a/arch/arm/boot/dts/broadcom/bcm2710-rpi-zero-2.dts b/arch/arm/boot/dts/broadcom/bcm2710-rpi-zero-2.dts new file mode 100644 index 000000000000..daa12bd30d6b --- /dev/null -+++ b/arch/arm/boot/dts/bcm2710-rpi-zero-2.dts ++++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-zero-2.dts @@ -0,0 +1 @@ +#include "bcm2710-rpi-zero-2-w.dts" -diff --git a/arch/arm/boot/dts/bcm2710.dtsi b/arch/arm/boot/dts/bcm2710.dtsi +diff --git a/arch/arm/boot/dts/broadcom/bcm2710.dtsi b/arch/arm/boot/dts/broadcom/bcm2710.dtsi new file mode 100644 -index 000000000000..e7e5c913f1d1 +index 000000000000..bdcdbb51fab8 --- /dev/null -+++ b/arch/arm/boot/dts/bcm2710.dtsi -@@ -0,0 +1,25 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2710.dtsi +@@ -0,0 +1,32 @@ ++#define i2c0 i2c0if +#include "bcm2837.dtsi" ++#undef i2c0 +#include "bcm270x.dtsi" + +/ { @@ -6807,7 +9183,8 @@ + }; + + soc { -+ /delete-node/ timer@7e003000; ++ dma-ranges = <0xc0000000 0x00000000 0x3f000000>, ++ <0x7e000000 0x3f000000 0x01000000>; + }; + + __overrides__ { @@ -6818,87 +9195,85 @@ + }; +}; + ++&system_timer { ++ status = "disabled"; ++}; ++ +&vc4 { + status = "disabled"; +}; -diff --git a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -index 167538518a1e..fb44c89f3b0c 100644 ---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -@@ -2,7 +2,6 @@ +diff --git a/arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts b/arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts +index d5f8823230db..d3a3a1e4d4c6 100644 +--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts +@@ -1,10 +1,16 @@ + // SPDX-License-Identifier: GPL-2.0 /dts-v1/; ++#define BCM2711 ++#define i2c0 i2c0if #include "bcm2711.dtsi" - #include "bcm2835-rpi.dtsi" ++#include "bcm283x-rpi-wifi-bt.dtsi" ++#undef i2c0 ++#include "bcm270x.dtsi" ++#define i2c0 i2c0mux + #include "bcm2711-rpi.dtsi" ++#undef i2c0 + #include "bcm283x-rpi-led-deprecated.dtsi" -#include "bcm283x-rpi-usb-peripheral.dtsi" +-#include "bcm283x-rpi-wifi-bt.dtsi" ++//#include "bcm283x-rpi-usb-peripheral.dtsi" - #include <dt-bindings/reset/raspberrypi,firmware-reset.h> - -@@ -25,6 +24,7 @@ aliases { - emmc2bus = &emmc2bus; - ethernet0 = &genet; - pcie0 = &pcie0; -+ blconfig = &blconfig; - }; - - leds { -@@ -95,7 +95,7 @@ expgpio: gpio { - "VDD_SD_IO_SEL", - "CAM_GPIO", - "SD_PWR_ON", -- ""; -+ "SD_OC_N"; - status = "okay"; - }; - -@@ -181,12 +181,14 @@ &gpio { - &hdmi0 { - clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>; - clock-names = "hdmi", "bvb", "audio", "cec"; -+ wifi-2.4ghz-coexistence; - status = "okay"; - }; - - &hdmi1 { - clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>; - clock-names = "hdmi", "bvb", "audio", "cec"; -+ wifi-2.4ghz-coexistence; - status = "okay"; - }; - -@@ -216,6 +218,22 @@ &pwm1 { - status = "okay"; + / { + compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; +@@ -60,7 +66,7 @@ &expgpio { + "VDD_SD_IO_SEL", + "CAM_GPIO", /* 5 */ + "SD_PWR_ON", +- ""; ++ "SD_OC_N"; }; -+&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>; -@@ -302,3 +320,311 @@ &vc4 { - &vec { - status = "disabled"; + &gpio { +@@ -74,21 +80,21 @@ &gpio { + */ + gpio-line-names = "ID_SDA", /* 0 */ + "ID_SCL", +- "SDA1", +- "SCL1", +- "GPIO_GCLK", ++ "GPIO2", ++ "GPIO3", ++ "GPIO4", + "GPIO5", /* 5 */ + "GPIO6", +- "SPI_CE1_N", +- "SPI_CE0_N", +- "SPI_MISO", +- "SPI_MOSI", /* 10 */ +- "SPI_SCLK", ++ "GPIO7", ++ "GPIO8", ++ "GPIO9", ++ "GPIO10", /* 10 */ ++ "GPIO11", + "GPIO12", + "GPIO13", + /* Serial port */ +- "TXD1", +- "RXD1", /* 15 */ ++ "GPIO14", ++ "GPIO15", /* 15 */ + "GPIO16", + "GPIO17", + "GPIO18", +@@ -241,3 +247,233 @@ &vec { + &wifi_pwrseq { + reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>; }; + +// ============================================= +// Downstream rpi- changes + -+#define BCM2711 -+ -+#include "bcm270x.dtsi" +#include "bcm271x-rpi-bt.dtsi" + +/ { @@ -6908,32 +9283,13 @@ + }; +}; + -+#include "bcm2711-rpi.dtsi" ++#include "bcm2711-rpi-ds.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; ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; + }; + + /delete-node/ wifi-pwrseq; @@ -6978,102 +9334,67 @@ +}; + +&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>; -+ }; ++ gpio-line-names = "ID_SDA", ++ "ID_SCL", ++ "GPIO2", ++ "GPIO3", ++ "GPIO4", ++ "GPIO5", ++ "GPIO6", ++ "GPIO7", ++ "GPIO8", ++ "GPIO9", ++ "GPIO10", ++ "GPIO11", ++ "GPIO12", ++ "GPIO13", ++ "GPIO14", ++ "GPIO15", ++ "GPIO16", ++ "GPIO17", ++ "GPIO18", ++ "GPIO19", ++ "GPIO20", ++ "GPIO21", ++ "GPIO22", ++ "GPIO23", ++ "GPIO24", ++ "GPIO25", ++ "GPIO26", ++ "GPIO27", ++ "RGMII_MDIO", ++ "RGMIO_MDC", ++ /* Used by BT module */ ++ "CTS0", /* 30 */ ++ "RTS0", ++ "TXD0", ++ "RXD0", ++ /* Used by Wifi */ ++ "SD1_CLK", ++ "SD1_CMD", /* 35 */ ++ "SD1_DATA0", ++ "SD1_DATA1", ++ "SD1_DATA2", ++ "SD1_DATA3", ++ /* Shared with SPI flash */ ++ "PWM0_MISO", /* 40 */ ++ "PWM1_MOSI", ++ "STATUS_LED_G_CLK", ++ "SPIFLASH_CE_N", ++ "SDA0", ++ "SCL0", /* 45 */ ++ "RGMII_RXCLK", ++ "RGMII_RXCTL", ++ "RGMII_RXD0", ++ "RGMII_RXD1", ++ "RGMII_RXD2", /* 50 */ ++ "RGMII_RXD3", ++ "RGMII_TXCLK", ++ "RGMII_TXCTL", ++ "RGMII_TXD0", ++ "RGMII_TXD1", /* 55 */ ++ "RGMII_TXD2", ++ "RGMII_TXD3"; + + bt_pins: bt_pins { + brcm,pins = "-"; // non-empty to keep btuart happy, //4 = 0 @@ -7094,28 +9415,10 @@ + 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>; ++ uart1_bt_pins: uart1_bt_pins { ++ brcm,pins = <32 33 30 31>; ++ brcm,function = <BCM2835_FSEL_ALT5>; /* alt5=UART1 */ ++ brcm,pull = <0 2 2 0>; + }; +}; + @@ -7149,28 +9452,24 @@ + audio_pins: audio_pins { + brcm,pins = <40 41>; + brcm,function = <4>; ++ brcm,pull = <0>; + }; +}; + -+&leds { -+ act_led: led-act { -+ label = "led0"; -+ linux,default-trigger = "mmc0"; -+ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; -+ }; ++&led_act { ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; ++}; + -+ pwr_led: led-pwr { -+ label = "led1"; -+ linux,default-trigger = "default-on"; -+ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; -+ }; ++&led_pwr { ++ default-state = "off"; +}; + +&pwm1 { + status = "disabled"; +}; + -+&audio { ++&vchiq { + pinctrl-names = "default"; + pinctrl-0 = <&audio_pins>; +}; @@ -7182,77 +9481,114 @@ +cam0_reg: &cam_dummy_reg { +}; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ +/ { + __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"; ++ audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_headphones=1 snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_headphones=0 snd_bcm2835.enable_hdmi=0'}"; ++ ++ act_led_gpio = <&led_act>,"gpios:4"; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>,"linux,default-trigger"; ++ ++ pwr_led_gpio = <&led_pwr>,"gpios:4"; ++ pwr_led_activelow = <&led_pwr>,"gpios:8"; ++ pwr_led_trigger = <&led_pwr>,"linux,default-trigger"; + + eth_led0 = <&phy1>,"led-modes:0"; + eth_led1 = <&phy1>,"led-modes:4"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/broadcom/bcm2711-rpi-400.dts b/arch/arm/boot/dts/broadcom/bcm2711-rpi-400.dts +index 5a2869a18bd5..d5b81b889018 100644 +--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-400.dts ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-400.dts +@@ -36,8 +36,53 @@ &led_pwr { + gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; + }; + +-/delete-node/ &led_act; +- + &pm { + /delete-property/ system-power-controller; + }; + -+ sd_poll_once = <&emmc2>, "non-removable?"; -+ spi_dma4 = <&spi0>, "dmas:0=", <&dma40>, -+ <&spi0>, "dmas:8=", <&dma40>; ++// ============================================= ++// Downstream rpi- changes ++ ++/ { ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++}; ++ ++&audio_pins { ++ brcm,pins = <>; ++ brcm,function = <>; ++}; ++ ++// Declare the LED but leave it disabled, in case a user wants to map it ++// to a GPIO on the header ++&led_act { ++ default-state = "off"; ++ gpios = <&gpio 0 GPIO_ACTIVE_HIGH>; ++ status = "disabled"; ++}; ++ ++&led_pwr { ++ default-state = "off"; ++}; ++ ++&cam1_reg { ++ /delete-property/ gpio; ++}; ++ ++cam0_reg: &cam_dummy_reg { ++}; ++ ++/ { ++ __overrides__ { ++ audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_hdmi=0'}"; ++ ++ act_led_gpio = <&led_act>,"gpios:4", ++ <&led_act>,"status=okay"; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>,"linux,default-trigger"; ++ pwr_led_gpio = <&led_pwr>,"gpios:4"; ++ pwr_led_activelow = <&led_pwr>,"gpios:8"; ++ pwr_led_trigger = <&led_pwr>,"linux,default-trigger"; + }; +}; -diff --git a/arch/arm/boot/dts/bcm2711-rpi-400.dts b/arch/arm/boot/dts/bcm2711-rpi-400.dts +diff --git a/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts new file mode 100644 -index 000000000000..ec0c75810754 +index 000000000000..9fdb9278c5a2 --- /dev/null -+++ b/arch/arm/boot/dts/bcm2711-rpi-400.dts -@@ -0,0 +1,637 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts +@@ -0,0 +1,510 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; ++#define BCM2711 ++#define i2c0 i2c0if +#include "bcm2711.dtsi" -+#include "bcm2835-rpi.dtsi" -+ -+#include <dt-bindings/reset/raspberrypi,firmware-reset.h> ++#include "bcm283x-rpi-wifi-bt.dtsi" ++#undef i2c0 ++#include "bcm270x.dtsi" ++#define i2c0 i2c0mux ++#include "bcm2711-rpi.dtsi" ++#undef i2c0 ++#include "bcm283x-rpi-led-deprecated.dtsi" ++//#include "bcm283x-rpi-usb-peripheral.dtsi" + +/ { -+ compatible = "raspberrypi,400", "brcm,bcm2711"; -+ model = "Raspberry Pi 400"; ++ 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 { -+ led-act { -+ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; -+ }; -+ -+ led-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"; @@ -7262,8 +9598,8 @@ + regulator-always-on; + regulator-settling-time-us = <5000>; + gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>; -+ states = <1800000 0x1 -+ 3300000 0x0>; ++ states = <1800000 0x1>, ++ <3300000 0x0>; + status = "okay"; + }; + @@ -7278,6 +9614,10 @@ + }; +}; + ++&bt { ++ shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>; ++}; ++ +&ddc0 { + status = "okay"; +}; @@ -7286,30 +9626,26 @@ + 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", -+ "GLOBAL_SHUTDOWN", -+ "SD_PWR_ON", -+ "SHUTDOWN_REQUEST"; -+ status = "okay"; -+ }; -+ -+ reset: reset { -+ compatible = "raspberrypi,firmware-reset"; -+ #reset-cells = <1>; ++&expgpio { ++ gpio-line-names = "BT_ON", ++ "WL_ON", ++ "PWR_LED_OFF", ++ "ANT1", ++ "VDD_SD_IO_SEL", ++ "CAM_GPIO", ++ "SD_PWR_ON", ++ "ANT2"; ++ ++ ant1: ant1 { ++ gpio-hog; ++ gpios = <3 GPIO_ACTIVE_HIGH>; ++ output-high; ++ }; ++ ++ ant2: ant2 { ++ gpio-hog; ++ gpios = <7 GPIO_ACTIVE_HIGH>; ++ output-low; + }; +}; + @@ -7387,21 +9723,24 @@ +}; + +&hdmi0 { -+ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>; -+ clock-names = "hdmi", "bvb", "audio", "cec"; -+ wifi-2.4ghz-coexistence; + status = "okay"; +}; + +&hdmi1 { -+ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>; -+ clock-names = "hdmi", "bvb", "audio", "cec"; -+ wifi-2.4ghz-coexistence; + status = "okay"; +}; + -+&hvs { -+ clocks = <&firmware_clocks 4>; ++&led_act { ++ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; ++}; ++ ++&leds { ++ led_pwr: led-pwr { ++ label = "PWR"; ++ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; ++ default-state = "keep"; ++ linux,default-trigger = "default-on"; ++ }; +}; + +&pixelvalve0 { @@ -7426,41 +9765,9 @@ + 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 is used to drive the EMMC card */ +&emmc2 { ++ bus-width = <8>; + vqmmc-supply = <&sd_io_1v8_reg>; + vmmc-supply = <&sd_vcc_reg>; + broken-cd; @@ -7474,9 +9781,9 @@ +}; + +&genet_mdio { -+ phy1: ethernet-phy@1 { ++ phy1: ethernet-phy@0 { + /* No PHY interrupt */ -+ reg = <0x1>; ++ reg = <0x0>; + }; +}; + @@ -7488,11 +9795,6 @@ + ranges; + + reg = <0 0 0 0 0>; -+ -+ usb@0,0 { -+ reg = <0 0 0 0 0>; -+ resets = <&reset RASPBERRYPI_FIRMWARE_RESET_ID_USB>; -+ }; + }; +}; + @@ -7501,13 +9803,6 @@ + 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 */ @@ -7517,10 +9812,6 @@ + status = "okay"; +}; + -+&vchiq { -+ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>; -+}; -+ +&vc4 { + status = "okay"; +}; @@ -7529,12 +9820,13 @@ + status = "disabled"; +}; + ++&wifi_pwrseq { ++ reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>; ++}; ++ +// ============================================= +// Downstream rpi- changes + -+#define BCM2711 -+ -+#include "bcm270x.dtsi" +#include "bcm271x-rpi-bt.dtsi" + +/ { @@ -7544,32 +9836,14 @@ + }; +}; + -+#include "bcm2711-rpi.dtsi" -+#include "bcm283x-rpi-csi1-2lane.dtsi" ++#include "bcm2711-rpi-ds.dtsi" ++#include "bcm283x-rpi-csi0-2lane.dtsi" ++#include "bcm283x-rpi-csi1-4lane.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; ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; + }; + + /delete-node/ wifi-pwrseq; @@ -7614,102 +9888,67 @@ +}; + +&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>; -+ }; ++ gpio-line-names = "ID_SDA", ++ "ID_SCL", ++ "GPIO2", ++ "GPIO3", ++ "GPIO4", ++ "GPIO5", ++ "GPIO6", ++ "GPIO7", ++ "GPIO8", ++ "GPIO9", ++ "GPIO10", ++ "GPIO11", ++ "GPIO12", ++ "GPIO13", ++ "GPIO14", ++ "GPIO15", ++ "GPIO16", ++ "GPIO17", ++ "GPIO18", ++ "GPIO19", ++ "GPIO20", ++ "GPIO21", ++ "GPIO22", ++ "GPIO23", ++ "GPIO24", ++ "GPIO25", ++ "GPIO26", ++ "GPIO27", ++ "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"; + + bt_pins: bt_pins { + brcm,pins = "-"; // non-empty to keep btuart happy, //4 = 0 @@ -7730,28 +9969,10 @@ + 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>; ++ uart1_bt_pins: uart1_bt_pins { ++ brcm,pins = <32 33 30 31>; ++ brcm,function = <BCM2835_FSEL_ALT5>; /* alt5=UART1 */ ++ brcm,pull = <0 2 2 0>; + }; +}; + @@ -7773,12 +9994,8 @@ +// ============================================= +// Board specific stuff here + -+/ { -+ power_ctrl: power_ctrl { -+ compatible = "gpio-poweroff"; -+ gpios = <&expgpio 5 0>; -+ force; -+ }; ++&pcie0 { ++ brcm,enable-l1ss; +}; + +&sdhost { @@ -7796,176 +10013,97 @@ + }; +}; + -+&leds { -+ act_led: led-act { -+ label = "led0"; -+ linux,default-trigger = "default-on"; -+ default-state = "on"; -+ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; -+ }; ++&led_act { ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; ++}; + -+ pwr_led: led-pwr { -+ label = "led1"; -+ linux,default-trigger = "default-on"; -+ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; -+ }; ++&led_pwr { ++ default-state = "off"; +}; + +&pwm1 { + status = "disabled"; +}; + -+&audio { ++&vchiq { + pinctrl-names = "default"; + pinctrl-0 = <&audio_pins>; -+ brcm,disable-headphones = <1>; +}; + -+&genet_mdio { -+ clock-frequency = <1950000>; ++cam0_reg: &cam1_reg { ++ gpio = <&expgpio 5 GPIO_ACTIVE_HIGH>; ++}; ++ ++i2c_csi_dsi0: &i2c0 { +}; + +/ { + __overrides__ { -+ act_led_gpio = <&act_led>,"gpios:4"; -+ act_led_activelow = <&act_led>,"gpios:8"; -+ act_led_trigger = <&act_led>,"linux,default-trigger"; ++ audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_hdmi=0'}"; ++ ++ act_led_gpio = <&led_act>,"gpios:4"; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>,"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"; ++ pwr_led_gpio = <&led_pwr>,"gpios:4"; ++ pwr_led_activelow = <&led_pwr>,"gpios:8"; ++ pwr_led_trigger = <&led_pwr>,"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>; ++ 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"; ++ ++ cam0_reg = <&cam0_reg>,"status"; ++ cam0_reg_gpio = <&cam0_reg>,"gpio:4", ++ <&cam0_reg>,"gpio:0=", <&gpio>; ++ cam1_reg = <&cam1_reg>,"status"; ++ cam1_reg_gpio = <&cam1_reg>,"gpio:4", ++ <&cam1_reg>,"gpio:0=", <&gpio>; ++ ++ pcie_tperst_clk_ms = <&pcie0>,"brcm,tperst-clk-ms:0"; + }; +}; -diff --git a/arch/arm/boot/dts/bcm2711-rpi-cm4.dts b/arch/arm/boot/dts/bcm2711-rpi-cm4.dts +diff --git a/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts new file mode 100644 -index 000000000000..5dbd1b77260b +index 000000000000..4cabd53bf45d --- /dev/null -+++ b/arch/arm/boot/dts/bcm2711-rpi-cm4.dts -@@ -0,0 +1,652 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts +@@ -0,0 +1,297 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; ++#define BCM2711 ++#define i2c0 i2c0if +#include "bcm2711.dtsi" -+#include "bcm2835-rpi.dtsi" ++//#include "bcm283x-rpi-wifi-bt.dtsi" ++#undef i2c0 ++#include "bcm270x.dtsi" ++#define i2c0 i2c0mux ++#include "bcm2711-rpi.dtsi" ++#undef i2c0 ++#include "bcm283x-rpi-led-deprecated.dtsi" + +/ { -+ 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 { -+ led-act { -+ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; -+ }; -+ -+ led-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>; -+ }; ++ compatible = "raspberrypi,4-compute-module-s", "brcm,bcm2711"; ++ model = "Raspberry Pi Compute Module 4S"; +}; + +&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 @@ -7977,21 +10115,20 @@ + */ + gpio-line-names = "ID_SDA", + "ID_SCL", -+ "SDA1", -+ "SCL1", -+ "GPIO_GCLK", ++ "GPIO2", ++ "GPIO3", ++ "GPIO4", + "GPIO5", + "GPIO6", -+ "SPI_CE1_N", -+ "SPI_CE0_N", -+ "SPI_MISO", -+ "SPI_MOSI", -+ "SPI_SCLK", ++ "GPIO7", ++ "GPIO8", ++ "GPIO9", ++ "GPIO10", ++ "GPIO11", + "GPIO12", + "GPIO13", -+ /* Serial port */ -+ "TXD1", -+ "RXD1", ++ "GPIO14", ++ "GPIO15", + "GPIO16", + "GPIO17", + "GPIO18", @@ -8004,57 +10141,32 @@ + "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 */ ++ "GPIO28", ++ "GPIO29", ++ "GPIO30", ++ "GPIO31", ++ "GPIO32", ++ "GPIO33", ++ "GPIO34", ++ "GPIO35", ++ "GPIO36", ++ "GPIO37", ++ "GPIO38", ++ "GPIO39", + "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"; ++ "GPIO42", ++ "GPIO43", ++ "GPIO44", ++ "GPIO45"; +}; + +&hdmi0 { -+ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>; -+ clock-names = "hdmi", "bvb", "audio", "cec"; -+ wifi-2.4ghz-coexistence; -+ status = "okay"; -+}; -+ -+&hdmi1 { -+ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>; -+ clock-names = "hdmi", "bvb", "audio", "cec"; -+ wifi-2.4ghz-coexistence; + status = "okay"; +}; + -+&hvs { -+ clocks = <&firmware_clocks 4>; ++&led_act { ++ gpios = <&virtgpio 0 GPIO_ACTIVE_HIGH>; +}; + +&pixelvalve0 { @@ -8079,91 +10191,15 @@ + 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@0 { -+ /* No PHY interrupt */ -+ reg = <0x0>; -+ }; -+}; -+ +&pcie0 { -+ pci@0,0 { -+ device_type = "pci"; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ ranges; -+ -+ reg = <0 0 0 0 0>; -+ }; -+}; -+ -+/* 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"; ++ status = "disabled"; +}; + +&vchiq { @@ -8181,66 +10217,48 @@ +// ============================================= +// Downstream rpi- changes + -+#define BCM2711 -+ -+#include "bcm270x.dtsi" -+#include "bcm271x-rpi-bt.dtsi" ++#include "bcm2711-rpi-ds.dtsi" + +/ { + soc { + /delete-node/ pixelvalve@7e807000; + /delete-node/ hdmi@7e902000; ++ ++ virtgpio: virtgpio { ++ compatible = "brcm,bcm2835-virtgpio"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ firmware = <&firmware>; ++ status = "okay"; ++ }; + }; +}; + -+#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-i2c0mux_0_28.dtsi" + +/ { + chosen { -+ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1"; ++ bootargs = "coherent_pool=1M snd_bcm2835.enable_headphones=0"; + }; + + 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; ++ serial0 = &uart0; ++ serial1 = &uart1; ++ /delete-property/ i2c20; ++ /delete-property/ i2c21; + }; + + /delete-node/ wifi-pwrseq; +}; + -+&mmcnr { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdio_pins>; -+ bus-width = <4>; -+ status = "okay"; -+}; -+ +&uart0 { -+ pinctrl-0 = <&uart0_pins &bt_pins>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0_pins>; + status = "okay"; +}; + -+&uart1 { -+ pinctrl-0 = <&uart1_pins>; -+}; -+ +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins &spi0_cs_pins>; @@ -8264,145 +10282,11 @@ +}; + +&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 { @@ -8423,18 +10307,20 @@ +// ============================================= +// Board specific stuff here + -+&pcie0 { -+ brcm,enable-l1ss; ++/* Enable USB in OTG-aware mode */ ++&usb { ++ 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"; +}; + +&sdhost { + status = "disabled"; +}; + -+&phy1 { -+ led-modes = <0x00 0x08>; /* link/activity link */ -+}; -+ +&gpio { + audio_pins: audio_pins { + brcm,pins = <>; @@ -8442,332 +10328,287 @@ + }; +}; + -+&leds { -+ act_led: led-act { -+ label = "led0"; -+ linux,default-trigger = "mmc0"; -+ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; -+ }; ++/* Permanently disable HDMI1 */ ++&hdmi1 { ++ compatible = "disabled"; ++}; + -+ pwr_led: led-pwr { -+ label = "led1"; -+ linux,default-trigger = "default-on"; -+ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; -+ }; ++/* Permanently disable DDC1 */ ++&ddc1 { ++ compatible = "disabled"; ++}; ++ ++&led_act { ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; +}; + +&pwm1 { + status = "disabled"; +}; + -+&audio { ++&vchiq { + pinctrl-names = "default"; + pinctrl-0 = <&audio_pins>; -+ brcm,disable-headphones = <1>; +}; + -+cam0_reg: &cam1_reg { -+ gpio = <&expgpio 5 GPIO_ACTIVE_HIGH>; ++&cam1_reg { ++ gpio = <&gpio 3 GPIO_ACTIVE_HIGH>; ++ status = "disabled"; ++}; ++ ++cam0_reg: &cam0_regulator { ++ gpio = <&gpio 31 GPIO_ACTIVE_HIGH>; ++ status = "disabled"; ++}; ++ ++i2c_csi_dsi0: &i2c0 { +}; + +/ { + __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"; ++ audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_hdmi=0'}"; + -+ 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"; ++ act_led_gpio = <&led_act>,"gpios:4"; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>,"linux,default-trigger"; + -+ sd_poll_once = <&emmc2>, "non-removable?"; -+ spi_dma4 = <&spi0>, "dmas:0=", <&dma40>, -+ <&spi0>, "dmas:8=", <&dma40>; ++ cam0_reg = <&cam0_reg>,"status"; ++ cam0_reg_gpio = <&cam0_reg>,"gpio:4"; ++ cam1_reg = <&cam1_reg>,"status"; ++ cam1_reg_gpio = <&cam1_reg>,"gpio:4"; + }; +}; -diff --git a/arch/arm/boot/dts/bcm2711-rpi-cm4s.dts b/arch/arm/boot/dts/bcm2711-rpi-cm4s.dts +diff --git a/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi b/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi new file mode 100644 -index 000000000000..f90785abc92f +index 000000000000..c45685339992 --- /dev/null -+++ b/arch/arm/boot/dts/bcm2711-rpi-cm4s.dts -@@ -0,0 +1,467 @@ ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi +@@ -0,0 +1,561 @@ +// SPDX-License-Identifier: GPL-2.0 -+/dts-v1/; -+#include "bcm2711.dtsi" -+#include "bcm2835-rpi.dtsi" -+ -+#include <dt-bindings/reset/raspberrypi,firmware-reset.h> ++#include "bcm270x-rpi.dtsi" + +/ { -+ compatible = "raspberrypi,4-compute-module-s", "brcm,bcm2711"; -+ model = "Raspberry Pi Compute Module 4S"; -+ -+ chosen { -+ /* 8250 auxiliary UART instead of pl011 */ -+ stdout-path = "serial1:115200n8"; ++ chosen: chosen { + }; + -+ /* Will be filled by the bootloader */ -+ memory@0 { -+ device_type = "memory"; -+ reg = <0 0 0>; ++ __overrides__ { ++ arm_freq; ++ eee = <&chosen>,"bootargs{on='',off='genet.eee=N'}"; ++ hdmi = <&hdmi0>,"status", ++ <&hdmi1>,"status"; ++ nvmem_cust_rw = <&nvmem_cust>,"rw?"; ++ nvmem_priv_rw = <&nvmem_priv>,"rw?"; ++ pcie = <&pcie0>,"status"; ++ sd = <&emmc2>,"status"; ++ ++ sd_poll_once = <&emmc2>, "non-removable?"; ++ spi_dma4 = <&spi0>, "dmas:0=", <&dma40>, ++ <&spi0>, "dmas:8=", <&dma40>; ++ i2s_dma4 = <&i2s>, "dmas:0=", <&dma40>, ++ <&i2s>, "dmas:8=", <&dma40>; + }; + -+ aliases { -+ emmc2bus = &emmc2bus; -+ blconfig = &blconfig; ++ scb: scb { ++ /* Add a label */ + }; + -+ leds { -+ led-act { -+ gpios = <&virtgpio 0 0>; -+ }; ++ soc: soc { ++ /* Add a label */ + }; -+}; + -+&ddc0 { -+ status = "okay"; -+}; ++ arm-pmu { ++ compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3", "arm,cortex-a7-pmu"; + -+&firmware { -+ firmware_clocks: clocks { -+ compatible = "raspberrypi,firmware-clocks"; -+ #clock-cells = <1>; + }; + -+ reset: reset { -+ compatible = "raspberrypi,firmware-reset"; -+ #reset-cells = <1>; ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ aliases { ++ uart2 = &uart2; ++ uart3 = &uart3; ++ uart4 = &uart4; ++ uart5 = &uart5; ++ serial0 = &uart1; ++ serial1 = &uart0; ++ serial2 = &uart2; ++ serial3 = &uart3; ++ serial4 = &uart4; ++ serial5 = &uart5; ++ 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; + }; -+}; + -+&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 ++ * Add a node with a dma-ranges value that exists only to be found ++ * by of_dma_get_max_cpu_address, and hence limit the DMA zone. + */ -+ 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", -+ "GPIO28", -+ "GPIO29", -+ "GPIO30", -+ "GPIO31", -+ "GPIO32", -+ "GPIO33", -+ "GPIO34", -+ "GPIO35", -+ "GPIO36", -+ "GPIO37", -+ "GPIO38", -+ "GPIO39", -+ "PWM0_MISO", -+ "PWM1_MOSI", -+ "GPIO42", -+ "GPIO43", -+ "GPIO44", -+ "GPIO45"; ++ zone_dma { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ dma-ranges = <0x0 0x0 0x0 0x40000000>; ++ }; +}; + -+&hdmi0 { -+ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>; -+ clock-names = "hdmi", "bvb", "audio", "cec"; -+ wifi-2.4ghz-coexistence; -+ status = "okay"; ++&vc4 { ++ raspberrypi,firmware = <&firmware>; +}; + -+ -+&hvs { -+ clocks = <&firmware_clocks 4>; ++&cma { ++ /* Limit cma to the lower 768MB to allow room for HIGHMEM on 32-bit */ ++ alloc-ranges = <0x0 0x00000000 0x30000000>; +}; + -+&pixelvalve0 { -+ status = "okay"; -+}; ++&soc { ++ /* Add the physical <-> DMA mapping for the I/O space */ ++ dma-ranges = <0xc0000000 0x0 0x00000000 0x40000000>, ++ <0x7c000000 0x0 0xfc000000 0x03800000>; + -+&pixelvalve1 { -+ status = "okay"; -+}; ++ nvmem_otp: nvmem_otp { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <0 166>; ++ status = "okay"; ++ }; + -+&pixelvalve2 { -+ status = "okay"; -+}; ++ nvmem_cust: nvmem_cust { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <1 8>; ++ status = "okay"; ++ }; + -+&pixelvalve4 { -+ status = "okay"; ++ nvmem_priv: nvmem_priv { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <3 8>; ++ status = "okay"; ++ }; +}; + -+&pwm1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pwm1_0_gpio40 &pwm1_1_gpio41>; -+ status = "okay"; -+}; ++&scb { ++ #size-cells = <2>; + -+&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; ++ 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 = <0x4 0x7c000000 0x0 0xfc000000 0x0 0x03800000>, ++ <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>; + }; -+}; + -+/* EMMC2 is used to drive the EMMC card */ -+&emmc2 { -+ bus-width = <8>; -+ broken-cd; -+ status = "okay"; ++ 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"; ++ }; +}; + +&pcie0 { -+ status = "disabled"; ++ reg = <0x0 0x7d500000 0x0 0x9310>; ++ ranges = <0x02000000 0x0 0xc0000000 0x6 0x00000000 ++ 0x0 0x40000000>; +}; + -+&vchiq { -+ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>; ++&genet { ++ reg = <0x0 0x7d580000 0x0 0x10000>; +}; + -+&vc4 { -+ status = "okay"; ++&dma40 { ++ /* The VPU firmware uses DMA channel 11 for VCHIQ */ ++ brcm,dma-channel-mask = <0x7000>; +}; + -+&vec { -+ status = "disabled"; ++&vchiq { ++ compatible = "brcm,bcm2711-vchiq"; +}; + -+// ============================================= -+// Downstream rpi- changes -+ -+#define BCM2711 -+ -+#include "bcm270x.dtsi" -+ -+/ { -+ soc { -+ /delete-node/ pixelvalve@7e807000; -+ /delete-node/ hdmi@7e902000; ++&firmwarekms { ++ compatible = "raspberrypi,rpi-firmware-kms-2711"; ++ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>; ++}; + -+ virtgpio: virtgpio { -+ compatible = "brcm,bcm2835-virtgpio"; -+ gpio-controller; -+ #gpio-cells = <2>; -+ firmware = <&firmware>; -+ status = "okay"; -+ }; -+ }; ++&smi { ++ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>; +}; + -+#include "bcm2711-rpi.dtsi" -+#include "bcm283x-rpi-csi0-2lane.dtsi" -+#include "bcm283x-rpi-csi1-4lane.dtsi" -+#include "bcm283x-rpi-i2c0mux_0_28.dtsi" ++&mmc { ++ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>; ++}; + -+/ { -+ chosen { -+ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1"; -+ }; ++&mmcnr { ++ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>; ++}; + -+ aliases { -+ serial0 = &uart0; -+ mmc0 = &emmc2; -+ mmc1 = &mmcnr; -+ mmc2 = &sdhost; -+ i2c3 = &i2c3; -+ i2c4 = &i2c4; -+ i2c5 = &i2c5; -+ i2c6 = &i2c6; -+ spi3 = &spi3; -+ spi4 = &spi4; -+ spi5 = &spi5; -+ spi6 = &spi6; -+ /delete-property/ intc; -+ }; ++&csi0 { ++ interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>; ++}; + -+ /delete-node/ wifi-pwrseq; ++&csi1 { ++ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>; +}; + -+&uart0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart0_pins>; ++&random { ++ compatible = "brcm,bcm2711-rng200"; + 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>; -+ }; ++&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>; ++ + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = <BCM2835_FSEL_ALT0>; @@ -8865,12 +10706,6 @@ + brcm,pull = <0 2 2 2 2 2>; + }; + -+ uart0_pins: uart0_pins { -+ brcm,pins; -+ brcm,function; -+ brcm,pull; -+ }; -+ + uart2_pins: uart2_pins { + brcm,pins = <0 1>; + brcm,function = <BCM2835_FSEL_ALT4>; @@ -8896,98 +10731,197 @@ + }; +}; + -+&i2c0if { -+ clock-frequency = <100000>; ++&emmc2 { ++ mmc-ddr-3_3v; +}; + -+&i2c1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c1_pins>; -+ clock-frequency = <100000>; ++&vc4 { ++ status = "disabled"; +}; + -+&i2s { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2s_pins>; ++&pixelvalve0 { ++ status = "disabled"; +}; + -+// ============================================= -+// Board specific stuff here ++&pixelvalve1 { ++ status = "disabled"; ++}; + -+&sdhost { ++&pixelvalve2 { + status = "disabled"; +}; + -+&gpio { -+ audio_pins: audio_pins { -+ brcm,pins = <>; -+ brcm,function = <>; -+ }; ++&pixelvalve3 { ++ status = "disabled"; ++}; ++ ++&pixelvalve4 { ++ status = "disabled"; ++}; ++ ++&hdmi0 { ++ reg = <0x7ef00700 0x300>, ++ <0x7ef00300 0x200>, ++ <0x7ef00f00 0x80>, ++ <0x7ef00f80 0x80>, ++ <0x7ef01b00 0x200>, ++ <0x7ef01f00 0x400>, ++ <0x7ef00200 0x80>, ++ <0x7ef04300 0x100>, ++ <0x7ef20000 0x100>, ++ <0x7ef00100 0x30>; ++ reg-names = "hdmi", ++ "dvp", ++ "phy", ++ "rm", ++ "packet", ++ "metadata", ++ "csc", ++ "cec", ++ "hd", ++ "intr2"; ++ clocks = <&firmware_clocks 13>, ++ <&firmware_clocks 14>, ++ <&dvp 0>, ++ <&clk_27MHz>; ++ dmas = <&dma40 (10|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; ++ status = "disabled"; ++}; ++ ++&ddc0 { ++ status = "disabled"; +}; + -+/* Permanently disable HDMI1 */ +&hdmi1 { -+ compatible = "disabled"; ++ reg = <0x7ef05700 0x300>, ++ <0x7ef05300 0x200>, ++ <0x7ef05f00 0x80>, ++ <0x7ef05f80 0x80>, ++ <0x7ef06b00 0x200>, ++ <0x7ef06f00 0x400>, ++ <0x7ef00280 0x80>, ++ <0x7ef09300 0x100>, ++ <0x7ef20000 0x100>, ++ <0x7ef00100 0x30>; ++ reg-names = "hdmi", ++ "dvp", ++ "phy", ++ "rm", ++ "packet", ++ "metadata", ++ "csc", ++ "cec", ++ "hd", ++ "intr2"; ++ clocks = <&firmware_clocks 13>, ++ <&firmware_clocks 14>, ++ <&dvp 1>, ++ <&clk_27MHz>; ++ dmas = <&dma40 (17|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; ++ status = "disabled"; +}; + -+/* Permanently disable DDC1 */ +&ddc1 { -+ compatible = "disabled"; ++ status = "disabled"; +}; + -+&leds { -+ act_led: led-act { -+ label = "led0"; -+ linux,default-trigger = "mmc0"; -+ gpios = <&virtgpio 0 0>; -+ }; ++&dvp { ++ status = "disabled"; +}; + -+&pwm1 { ++&vec { ++ clocks = <&firmware_clocks 15>; ++}; ++ ++&aon_intr { ++ interrupts = <GIC_SPI 96 IRQ_TYPE_EDGE_RISING>; ++ status = "disabled"; ++}; ++ ++&system_timer { + status = "disabled"; +}; + -+&audio { ++&i2c0 { ++ /delete-property/ compatible; ++ /delete-property/ interrupts; ++}; ++ ++&i2c0if { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>; ++}; ++ ++i2c_arm: &i2c1 {}; ++i2c_vc: &i2c0 {}; ++ ++&i2c3 { ++ pinctrl-0 = <&i2c3_pins>; + pinctrl-names = "default"; -+ pinctrl-0 = <&audio_pins>; -+ brcm,disable-headphones = <1>; +}; + -+&cam1_reg { -+ gpio = <&gpio 2 GPIO_ACTIVE_HIGH>; -+ status = "disabled"; ++&i2c4 { ++ pinctrl-0 = <&i2c4_pins>; ++ pinctrl-names = "default"; +}; + -+cam0_reg: &cam0_regulator { -+ gpio = <&gpio 30 GPIO_ACTIVE_HIGH>; -+ status = "disabled"; ++&i2c5 { ++ pinctrl-0 = <&i2c5_pins>; ++ pinctrl-names = "default"; +}; + -+/ { -+ __overrides__ { -+ act_led_gpio = <&act_led>,"gpios:4"; -+ act_led_activelow = <&act_led>,"gpios:8"; -+ act_led_trigger = <&act_led>,"linux,default-trigger"; ++&i2c6 { ++ pinctrl-0 = <&i2c6_pins>; ++ pinctrl-names = "default"; ++}; + -+ sd_poll_once = <&emmc2>, "non-removable?"; -+ spi_dma4 = <&spi0>, "dmas:0=", <&dma40>, -+ <&spi0>, "dmas:8=", <&dma40>; -+ }; ++&spi3 { ++ pinctrl-0 = <&spi3_pins &spi3_cs_pins>; ++ pinctrl-names = "default"; +}; -diff --git a/arch/arm/boot/dts/bcm2711-rpi.dtsi b/arch/arm/boot/dts/bcm2711-rpi.dtsi -new file mode 100644 -index 000000000000..ebf73b789b4a ---- /dev/null -+++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi -@@ -0,0 +1,205 @@ -+// SPDX-License-Identifier: GPL-2.0 -+#include "bcm270x-rpi.dtsi" + -+/ { -+ __overrides__ { -+ arm_freq; -+ }; ++&spi4 { ++ pinctrl-0 = <&spi4_pins &spi4_cs_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&spi5 { ++ pinctrl-0 = <&spi5_pins &spi5_cs_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&spi6 { ++ pinctrl-0 = <&spi6_pins &spi6_cs_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&uart2 { ++ pinctrl-0 = <&uart2_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&uart3 { ++ pinctrl-0 = <&uart3_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&uart4 { ++ pinctrl-0 = <&uart4_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&uart5 { ++ pinctrl-0 = <&uart5_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&axiperf { ++ compatible = "brcm,bcm2711-axiperf"; ++}; + ++/delete-node/ &v3d; ++ ++/ { + v3dbus: v3dbus { + compatible = "simple-bus"; + #address-cells = <1>; @@ -9011,1219 +10945,5577 @@ + status = "disabled"; + }; + }; ++}; +diff --git a/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi b/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi +index 98817a6675b9..7b9e946db985 100644 +--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi +@@ -15,6 +15,7 @@ aliases { + ethernet0 = &genet; + pcie0 = &pcie0; + blconfig = &blconfig; ++ blpubkey = &blpubkey; + }; + }; + +@@ -67,6 +68,18 @@ blconfig: nvram@0 { + no-map; + status = "disabled"; + }; ++ /* ++ * RPi4 will copy the binary public key blob (if present) from the bootloader ++ * into memory for use by the OS. ++ */ ++ blpubkey: nvram@1 { ++ compatible = "raspberrypi,bootloader-public-key", "nvmem-rmem"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x0 0x0 0x0>; ++ no-map; ++ status = "disabled"; ++ }; + }; + + &v3d { +diff --git a/arch/arm/boot/dts/broadcom/bcm2711.dtsi b/arch/arm/boot/dts/broadcom/bcm2711.dtsi +index 4a379a14966d..09dbe7b3ca39 100644 +--- a/arch/arm/boot/dts/broadcom/bcm2711.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm2711.dtsi +@@ -277,7 +277,7 @@ pwm1: pwm@7e20c800 { + reg = <0x7e20c800 0x28>; + clocks = <&clocks BCM2835_CLOCK_PWM>; + assigned-clocks = <&clocks BCM2835_CLOCK_PWM>; +- assigned-clock-rates = <10000000>; ++ assigned-clock-rates = <50000000>; + #pwm-cells = <3>; + status = "disabled"; + }; +diff --git a/arch/arm/boot/dts/broadcom/bcm2712-rpi-5-b.dts b/arch/arm/boot/dts/broadcom/bcm2712-rpi-5-b.dts +new file mode 100644 +index 000000000000..f0e752436b68 +--- /dev/null ++++ b/arch/arm/boot/dts/broadcom/bcm2712-rpi-5-b.dts +@@ -0,0 +1,863 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/dts-v1/; + -+ scb: scb { -+ /* Add a label */ ++#include <dt-bindings/gpio/gpio.h> ++#include <dt-bindings/clock/rp1.h> ++#include <dt-bindings/interrupt-controller/irq.h> ++#include <dt-bindings/mfd/rp1.h> ++#include <dt-bindings/pwm/pwm.h> ++#include <dt-bindings/reset/raspberrypi,firmware-reset.h> ++ ++#define i2c0 _i2c0 ++#define i2c3 _i2c3 ++#define i2c4 _i2c4 ++#define i2c5 _i2c5 ++#define i2c6 _i2c6 ++#define i2c8 _i2c8 ++#define i2s _i2s ++#define pwm0 _pwm0 ++#define pwm1 _pwm1 ++#define spi0 _spi0 ++#define spi3 _spi3 ++#define spi4 _spi4 ++#define spi5 _spi5 ++#define spi6 _spi6 ++#define uart0 _uart0 ++#define uart2 _uart2 ++#define uart5 _uart5 ++ ++#include "bcm2712.dtsi" ++ ++#undef i2c0 ++#undef i2c3 ++#undef i2c4 ++#undef i2c5 ++#undef i2c6 ++#undef i2c8 ++#undef i2s ++#undef pwm0 ++#undef pwm1 ++#undef spi0 ++#undef spi3 ++#undef spi4 ++#undef spi5 ++#undef spi6 ++#undef uart0 ++#undef uart2 ++#undef uart3 ++#undef uart4 ++#undef uart5 ++ ++/ { ++ compatible = "raspberrypi,5-model-b", "brcm,bcm2712"; ++ model = "Raspberry Pi 5"; ++ ++ /* Will be filled by the bootloader */ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0 0 0x28000000>; + }; -+}; + -+&vc4 { -+ raspberrypi,firmware = <&firmware>; -+}; ++ leds: leds { ++ compatible = "gpio-leds"; + -+&cma { -+ /* Limit cma to the lower 768MB to allow room for HIGHMEM on 32-bit */ -+ alloc-ranges = <0x0 0x00000000 0x30000000>; -+}; ++ led_pwr: led-pwr { ++ label = "PWR"; ++ gpios = <&rp1_gpio 44 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ linux,default-trigger = "none"; ++ }; + -+&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>; ++ led_act: led-act { ++ label = "ACT"; ++ gpios = <&gio_aon 9 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; ++ }; ++ }; + -+ 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>; ++ sd_io_1v8_reg: sd_io_1v8_reg { ++ compatible = "regulator-gpio"; ++ regulator-name = "vdd-sd-io"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ regulator-settling-time-us = <5000>; ++ gpios = <&gio_aon 3 GPIO_ACTIVE_HIGH>; ++ states = <1800000 0x1 ++ 3300000 0x0>; ++ status = "okay"; + }; + -+ xhci: xhci@7e9c0000 { -+ compatible = "generic-xhci"; ++ sd_vcc_reg: sd_vcc_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc-sd"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ enable-active-high; ++ gpios = <&gio_aon 4 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++ }; ++ ++ wl_on_reg: wl_on_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "wl-on-regulator"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ pinctrl-0 = <&wl_on_pins>; ++ pinctrl-names = "default"; ++ ++ gpio = <&gio 28 GPIO_ACTIVE_HIGH>; ++ ++ startup-delay-us = <150000>; ++ enable-active-high; ++ }; ++ ++ clocks: clocks { ++ }; ++ ++ cam1_clk: cam1_clk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; + status = "disabled"; -+ 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"; ++ cam0_clk: cam0_clk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ status = "disabled"; + }; + -+ rpivid-local-intc@7eb10000 { -+ compatible = "raspberrypi,rpivid-local-intc"; -+ reg = <0x0 0x7eb10000 0x0 0x1000>; ++ cam0_reg: cam0_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "cam0_reg"; ++ enable-active-high; + status = "okay"; -+ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; ++ gpio = <&rp1_gpio 34 0>; // CD0_IO0_MICCLK, to MIPI 0 connector + }; + -+ h264-decoder@7eb20000 { -+ compatible = "raspberrypi,rpivid-h264-decoder"; -+ reg = <0x0 0x7eb20000 0x0 0x10000>; ++ cam1_reg: cam1_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "cam1_reg"; ++ enable-active-high; + status = "okay"; ++ gpio = <&rp1_gpio 46 0>; // CD1_IO0_MICCLK, to MIPI 1 connector + }; + -+ vp9-decoder@7eb30000 { -+ compatible = "raspberrypi,rpivid-vp9-decoder"; -+ reg = <0x0 0x7eb30000 0x0 0x10000>; ++ cam_dummy_reg: cam_dummy_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "cam-dummy-reg"; + status = "okay"; + }; ++ ++ dummy: dummy { ++ // A target for unwanted overlay fragments ++ }; ++ ++ ++ // A few extra labels to keep overlays happy ++ ++ i2c0if: i2c0if {}; ++ i2c0mux: i2c0mux {}; +}; + -+&dma40 { -+ /* The VPU firmware uses DMA channel 11 for VCHIQ */ -+ brcm,dma-channel-mask = <0x7000>; ++rp1_target: &pcie2 { ++ brcm,enable-mps-rcb; ++ brcm,vdm-qos-map = <0xbbaa9888>; ++ aspm-no-l0s; ++ status = "okay"; +}; + -+&vchiq { -+ compatible = "brcm,bcm2711-vchiq"; ++// Add some labels to 2712 device ++ ++// The system UART ++uart10: &_uart0 { status = "okay"; }; ++ ++// The system SPI for the bootloader EEPROM ++spi10: &_spi0 { status = "okay"; }; ++ ++i2c_rp1boot: &_i2c3 { }; ++ ++#include "rp1.dtsi" ++ ++&rp1 { ++ // PCIe address space layout: ++ // 00_00000000-00_00xxxxxx = RP1 peripherals ++ // 10_00000000-1x_xxxxxxxx = up to 64GB system RAM ++ ++ // outbound access aimed at PCIe 0_00xxxxxx -> RP1 c0_40xxxxxx ++ // This is the RP1 peripheral space ++ ranges = <0xc0 0x40000000 ++ 0x02000000 0x00 0x00000000 ++ 0x00 0x00400000>; ++ ++ dma-ranges = ++ // inbound RP1 1x_xxxxxxxx -> PCIe 1x_xxxxxxxx ++ <0x10 0x00000000 ++ 0x43000000 0x10 0x00000000 ++ 0x10 0x00000000>, ++ ++ // inbound RP1 c0_40xxxxxx -> PCIe 00_00xxxxxx ++ // This allows the RP1 DMA controller to address RP1 hardware ++ <0xc0 0x40000000 ++ 0x02000000 0x0 0x00000000 ++ 0x0 0x00400000>, ++ ++ // inbound RP1 0x_xxxxxxxx -> PCIe 1x_xxxxxxxx ++ <0x00 0x00000000 ++ 0x02000000 0x10 0x00000000 ++ 0x10 0x00000000>; +}; + -+&firmwarekms { -+ compatible = "raspberrypi,rpi-firmware-kms-2711"; -+ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>; ++// Expose RP1 nodes as system nodes with labels ++ ++&rp1_dma { ++ status = "okay"; +}; + -+&smi { -+ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>; ++&rp1_eth { ++ status = "okay"; ++ phy-handle = <&phy1>; ++ phy-reset-gpios = <&rp1_gpio 32 GPIO_ACTIVE_LOW>; ++ phy-reset-duration = <5>; ++ ++ phy1: ethernet-phy@1 { ++ reg = <0x1>; ++ brcm,powerdown-enable; ++ }; +}; + -+&mmc { -+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>; ++gpio: &rp1_gpio { ++ status = "okay"; +}; + -+&mmcnr { -+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>; ++aux: &dummy {}; ++ ++&rp1_usb0 { ++ pinctrl-0 = <&usb_vbus_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&rp1_usb1 { ++ status = "okay"; ++}; ++ ++#include "bcm2712-rpi.dtsi" ++ ++i2c_csi_dsi0: &i2c6 { // Note: This is for MIPI0 connector only ++ pinctrl-0 = <&rp1_i2c6_38_39>; ++ pinctrl-names = "default"; ++ clock-frequency = <100000>; ++}; ++ ++i2c_csi_dsi1: &i2c4 { // Note: This is for MIPI1 connector only ++ pinctrl-0 = <&rp1_i2c4_40_41>; ++ pinctrl-names = "default"; ++ clock-frequency = <100000>; +}; + ++i2c_csi_dsi: &i2c_csi_dsi1 { }; // An alias for compatibility ++ ++csi0: &rp1_csi0 { }; ++csi1: &rp1_csi1 { }; ++dsi0: &rp1_dsi0 { }; ++dsi1: &rp1_dsi1 { }; ++dpi: &rp1_dpi { }; ++vec: &rp1_vec { }; ++dpi_gpio0: &rp1_dpi_24bit_gpio0 { }; ++dpi_gpio1: &rp1_dpi_24bit_gpio2 { }; ++dpi_18bit_cpadhi_gpio0: &rp1_dpi_18bit_cpadhi_gpio0 { }; ++dpi_18bit_cpadhi_gpio2: &rp1_dpi_18bit_cpadhi_gpio2 { }; ++dpi_18bit_gpio0: &rp1_dpi_18bit_gpio0 { }; ++dpi_18bit_gpio2: &rp1_dpi_18bit_gpio2 { }; ++dpi_16bit_cpadhi_gpio0: &rp1_dpi_16bit_cpadhi_gpio0 { }; ++dpi_16bit_cpadhi_gpio2: &rp1_dpi_16bit_cpadhi_gpio2 { }; ++dpi_16bit_gpio0: &rp1_dpi_16bit_gpio0 { }; ++dpi_16bit_gpio2: &rp1_dpi_16bit_gpio2 { }; ++ ++/* Add the IOMMUs for some RP1 bus masters */ ++ +&csi0 { -+ interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>; ++ iommus = <&iommu5>; +}; + +&csi1 { -+ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>; ++ iommus = <&iommu5>; +}; + -+&random { -+ compatible = "brcm,bcm2711-rng200"; -+ status = "okay"; ++&dsi0 { ++ iommus = <&iommu5>; +}; + -+&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"; ++&dsi1 { ++ iommus = <&iommu5>; +}; + -+&gpio { -+ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>, -+ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>; ++&dpi { ++ iommus = <&iommu5>; +}; + -+&emmc2 { -+ mmc-ddr-3_3v; ++&vec { ++ iommus = <&iommu5>; +}; + -+&vc4 { ++&ddc0 { + status = "disabled"; +}; + -+&pixelvalve0 { ++&ddc1 { + status = "disabled"; +}; + -+&pixelvalve1 { ++&hdmi0 { ++ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>; ++ clock-names = "hdmi", "bvb", "audio", "cec"; + status = "disabled"; +}; + -+&pixelvalve2 { ++&hdmi1 { ++ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>; ++ clock-names = "hdmi", "bvb", "audio", "cec"; + status = "disabled"; +}; + -+&pixelvalve3 { -+ status = "disabled"; ++&hvs { ++ clocks = <&firmware_clocks 4>, <&firmware_clocks 16>; ++ clock-names = "core", "disp"; +}; + -+&pixelvalve4 { ++&mop { + status = "disabled"; +}; + -+&hdmi0 { -+ dmas = <&dma (10|(1<<27)|(1<<24)|(10<<16)|(15<<20))>; ++&moplet { + status = "disabled"; +}; + -+&ddc0 { ++&pixelvalve0 { + status = "disabled"; +}; + -+&hdmi1 { -+ dmas = <&dma (17|(1<<27)|(1<<24)|(10<<16)|(15<<20))>; ++&pixelvalve1 { + status = "disabled"; +}; + -+&ddc1 { ++&disp_intr { + status = "disabled"; +}; + -+&dvp { -+ status = "disabled"; ++/* SDIO1 is used to drive the SD card */ ++&sdio1 { ++ pinctrl-0 = <&emmc_sd_pulls>, <&emmc_aon_cd_pins>; ++ pinctrl-names = "default"; ++ vqmmc-supply = <&sd_io_1v8_reg>; ++ vmmc-supply = <&sd_vcc_reg>; ++ bus-width = <4>; ++ sd-uhs-sdr50; ++ sd-uhs-ddr50; ++ sd-uhs-sdr104; ++ cd-gpios = <&gio_aon 5 GPIO_ACTIVE_LOW>; ++ //no-1-8-v; ++ status = "okay"; +}; -diff --git a/arch/arm/boot/dts/bcm2711.dtsi b/arch/arm/boot/dts/bcm2711.dtsi -index 55ec83bde5a6..2b834efddc06 100644 ---- a/arch/arm/boot/dts/bcm2711.dtsi -+++ b/arch/arm/boot/dts/bcm2711.dtsi -@@ -300,6 +300,14 @@ pixelvalve3: pixelvalve@7ec12000 { - status = "disabled"; - }; - -+ vec: vec@7ec13000 { -+ compatible = "brcm,bcm2711-vec"; -+ reg = <0x7ec13000 0x1000>; -+ clocks = <&firmware_clocks 15>; -+ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>; -+ status = "disabled"; -+ }; + - dvp: clock@7ef00000 { - compatible = "brcm,brcm2711-dvp"; - reg = <0x7ef00000 0x10>; -@@ -308,6 +316,15 @@ dvp: clock@7ef00000 { - #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_EDGE_RISING>; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ status = "disabled"; -+ }; ++&pinctrl_aon { ++ emmc_aon_cd_pins: emmc_aon_cd_pins { ++ function = "sd_card_g"; ++ pins = "aon_gpio5"; ++ bias-pull-up; ++ }; + - hdmi0: hdmi@7ef00700 { - compatible = "brcm,bcm2711-hdmi0"; - reg = <0x7ef00700 0x300>, -@@ -318,7 +335,8 @@ hdmi0: hdmi@7ef00700 { - <0x7ef01f00 0x400>, - <0x7ef00200 0x80>, - <0x7ef04300 0x100>, -- <0x7ef20000 0x100>; -+ <0x7ef20000 0x100>, -+ <0x7ef00100 0x30>; - reg-names = "hdmi", - "dvp", - "phy", -@@ -327,11 +345,21 @@ hdmi0: hdmi@7ef00700 { - "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"; - }; -@@ -354,7 +382,8 @@ hdmi1: hdmi@7ef05700 { - <0x7ef06f00 0x400>, - <0x7ef00280 0x80>, - <0x7ef09300 0x100>, -- <0x7ef20000 0x100>; -+ <0x7ef20000 0x100>, -+ <0x7ef00100 0x30>; - reg-names = "hdmi", - "dvp", - "phy", -@@ -363,11 +392,21 @@ hdmi1: hdmi@7ef05700 { - "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>, // This is correct -+ <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"; - }; -@@ -468,14 +507,14 @@ cpu3: cpu@3 { - 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>; -@@ -495,8 +534,8 @@ IRQ_TYPE_LEVEL_HIGH>, - 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 -@@ -509,7 +548,7 @@ IRQ_TYPE_LEVEL_HIGH>, - - 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>, -@@ -546,6 +585,7 @@ &dsi0 { - - &dsi1 { - interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>; -+ compatible = "brcm,bcm2711-dsi1"; - }; - - &gpio { -@@ -1018,7 +1058,7 @@ &cma { - alloc-ranges = <0x0 0x00000000 0x40000000>; - }; - --&i2c0 { -+&i2c0if { - compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; - interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>; - }; -@@ -1074,7 +1114,3 @@ &uart1 { - &usb { - interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; - }; -- --&vec { -- interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>; --}; -diff --git a/arch/arm/boot/dts/bcm271x-rpi-bt.dtsi b/arch/arm/boot/dts/bcm271x-rpi-bt.dtsi -new file mode 100644 -index 000000000000..6b9b79f74cf3 ---- /dev/null -+++ b/arch/arm/boot/dts/bcm271x-rpi-bt.dtsi -@@ -0,0 +1,26 @@ -+// SPDX-License-Identifier: GPL-2.0 ++ /* Slight hack - only one PWM pin (status LED) is usable */ ++ aon_pwm_1pin: aon_pwm_1pin { ++ function = "aon_pwm"; ++ pins = "aon_gpio9"; ++ }; ++}; + -+&uart0 { -+ bt: bluetooth { -+ compatible = "brcm,bcm43438-bt"; -+ max-speed = <3000000>; -+ shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>; -+ status = "disabled"; ++&pinctrl { ++ pwr_button_pins: pwr_button_pins { ++ function = "gpio"; ++ pins = "gpio20"; ++ bias-pull-up; ++ }; ++ ++ wl_on_pins: wl_on_pins { ++ function = "gpio"; ++ pins = "gpio28"; ++ }; ++ ++ bt_shutdown_pins: bt_shutdown_pins { ++ function = "gpio"; ++ pins = "gpio29"; ++ }; ++ ++ emmc_sd_pulls: emmc_sd_pulls { ++ pins = "emmc_cmd", "emmc_dat0", "emmc_dat1", "emmc_dat2", "emmc_dat3"; ++ bias-pull-up; + }; +}; + -+&uart1 { -+ minibt: bluetooth { ++/* uarta communicates with the BT module */ ++&uarta { ++ uart-has-rtscts; ++ auto-flow-control; ++ status = "okay"; ++ clock-frequency = <96000000>; ++ pinctrl-0 = <&uarta_24_pins &bt_shutdown_pins>; ++ pinctrl-names = "default"; ++ ++ bluetooth: bluetooth { + compatible = "brcm,bcm43438-bt"; -+ max-speed = <460800>; -+ shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>; -+ status = "disabled"; ++ max-speed = <3000000>; ++ shutdown-gpios = <&gio 29 GPIO_ACTIVE_HIGH>; ++ local-bd-address = 00 00 00 00 00 00 ; + }; +}; + ++&i2c_rp1boot { ++ clock-frequency = <400000>; ++ pinctrl-0 = <&i2c3_m4_agpio0_pins>; ++ pinctrl-names = "default"; ++}; ++ +/ { -+ __overrides__ { -+ krnbt = <&bt>,"status"; -+ krnbt_baudrate = <&bt>,"max-speed:0"; ++ chosen: chosen { ++ bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1"; ++ stdout-path = "serial10:115200n8"; + }; -+}; -diff --git a/arch/arm/boot/dts/bcm2835-common.dtsi b/arch/arm/boot/dts/bcm2835-common.dtsi -index 4119271c979d..7f46a6ec512c 100644 ---- a/arch/arm/boot/dts/bcm2835-common.dtsi -+++ b/arch/arm/boot/dts/bcm2835-common.dtsi -@@ -106,6 +106,14 @@ i2c2: i2c@7e805000 { - status = "okay"; - }; - -+ vec: vec@7e806000 { -+ compatible = "brcm,bcm2835-vec"; -+ reg = <0x7e806000 0x1000>; -+ clocks = <&firmware_clocks 15>; -+ interrupts = <2 27>; -+ status = "disabled"; -+ }; + - pixelvalve@7e807000 { - compatible = "brcm,bcm2835-pixelvalve2"; - reg = <0x7e807000 0x100>; -@@ -116,12 +124,14 @@ hdmi: hdmi@7e902000 { - 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 = <&firmware_clocks 9>, - <&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 --git a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts -index 40b9405f1a8e..d2384d8e8555 100644 ---- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts -+++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts -@@ -126,3 +126,8 @@ &uart0 { - pinctrl-0 = <&uart0_gpio14>; - status = "okay"; - }; ++ fan: cooling_fan { ++ status = "disabled"; ++ compatible = "pwm-fan"; ++ #cooling-cells = <2>; ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ cooling-levels = <0 75 125 175 250>; ++ pwms = <&rp1_pwm1 3 41566 PWM_POLARITY_INVERTED>; ++ rpm-regmap = <&rp1_pwm1>; ++ rpm-offset = <0x3c>; ++ }; + -+/* i2c on camera/display connector is gpio 28&29 */ -+&i2c0mux { -+ pinctrl-1 = <&i2c0_gpio28>; -+}; -diff --git a/arch/arm/boot/dts/bcm2835-rpi-a.dts b/arch/arm/boot/dts/bcm2835-rpi-a.dts -index 11edb581dbaf..4ceca674b752 100644 ---- a/arch/arm/boot/dts/bcm2835-rpi-a.dts -+++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts -@@ -121,3 +121,10 @@ &uart0 { - pinctrl-0 = <&uart0_gpio14>; - status = "okay"; - }; ++ pwr_button { ++ compatible = "gpio-keys"; + -+/* 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 --git a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts -index 1b435c64bd9c..8f2d10d82fa1 100644 ---- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts -+++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts -@@ -128,3 +128,8 @@ &uart0 { - pinctrl-0 = <&uart0_gpio14>; - status = "okay"; - }; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwr_button_pins>; ++ status = "okay"; + -+/* i2c on camera/display connector is gpio 28&29 */ -+&i2c0mux { -+ pinctrl-1 = <&i2c0_gpio28>; ++ pwr_key: pwr { ++ label = "pwr_button"; ++ // linux,code = <205>; // KEY_SUSPEND ++ linux,code = <116>; // KEY_POWER ++ gpios = <&gio 20 GPIO_ACTIVE_LOW>; ++ debounce-interval = <50>; // ms ++ }; ++ }; +}; -diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts -index a23c25c00eea..547c88a3ae9f 100644 ---- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts -+++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts -@@ -121,3 +121,10 @@ &uart0 { - 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>; ++&usb { ++ power-domains = <&power RPI_POWER_DOMAIN_USB>; +}; -diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts b/arch/arm/boot/dts/bcm2835-rpi-b.dts -index 1b63d6b19750..073fc99ef8a2 100644 ---- a/arch/arm/boot/dts/bcm2835-rpi-b.dts -+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts -@@ -116,3 +116,10 @@ &uart0 { - 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 --git a/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts b/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts -index a75c882e6575..95564c93a645 100644 ---- a/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts -+++ b/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts -@@ -95,3 +95,8 @@ &uart0 { - pinctrl-0 = <&uart0_gpio14>; - status = "okay"; - }; ++/* SDIO2 drives the WLAN interface */ ++&sdio2 { ++ pinctrl-0 = <&sdio2_30_pins>; ++ pinctrl-names = "default"; ++ bus-width = <4>; ++ vmmc-supply = <&wl_on_reg>; ++ sd-uhs-ddr50; ++ non-removable; ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; + -+/* WHAT TO DO HERE? */ -+&i2c0mux { -+ pinctrl-1 = <&i2c0_gpio28>; ++ wifi: wifi@1 { ++ reg = <1>; ++ compatible = "brcm,bcm4329-fmac"; ++ local-mac-address = 00 00 00 00 00 00; ++ }; +}; -diff --git a/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts b/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts -index 33b2b77aa47d..3ea5c7e6be54 100644 ---- a/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts -+++ b/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts -@@ -149,3 +149,8 @@ &uart1 { - pinctrl-0 = <&uart1_gpio14>; - status = "okay"; - }; + -+/* i2c on camera/display connector is gpio 28&29 */ -+&i2c0mux { -+ pinctrl-1 = <&i2c0_gpio28>; ++&rpivid { ++ status = "okay"; +}; -diff --git a/arch/arm/boot/dts/bcm2835-rpi-zero.dts b/arch/arm/boot/dts/bcm2835-rpi-zero.dts -index 6f9b3a908f28..a0eabab12c99 100644 ---- a/arch/arm/boot/dts/bcm2835-rpi-zero.dts -+++ b/arch/arm/boot/dts/bcm2835-rpi-zero.dts -@@ -117,3 +117,8 @@ &uart0 { - pinctrl-0 = <&uart0_gpio14>; - status = "okay"; - }; + -+/* i2c on camera/display connector is gpio 28&29 */ -+&i2c0mux { -+ pinctrl-1 = <&i2c0_gpio28>; -+}; -diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi -index 87ddcad76083..edc55bba5ff4 100644 ---- a/arch/arm/boot/dts/bcm2835-rpi.dtsi -+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi -@@ -19,6 +19,11 @@ firmware: firmware { - - mboxes = <&mailbox>; - dma-ranges; -+ -+ firmware_clocks: clocks { -+ compatible = "raspberrypi,firmware-clocks"; -+ #clock-cells = <1>; -+ }; - }; - - power: power { -@@ -49,13 +54,17 @@ alt0: alt0 { - }; - }; - --&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"; ++&pinctrl { ++ spi10_gpio2: spi10_gpio2 { ++ function = "vc_spi0"; ++ pins = "gpio2", "gpio3", "gpio4"; ++ bias-disable; ++ }; ++ ++ spi10_cs_gpio1: spi10_cs_gpio1 { ++ function = "gpio"; ++ pins = "gpio1"; ++ bias-pull-up; ++ }; +}; + - &i2c1 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c1_gpio2>; -@@ -67,6 +76,10 @@ &usb { - power-domains = <&power RPI_POWER_DOMAIN_USB>; - }; - -+&vc4 { -+ raspberrypi,firmware = <&firmware>; ++spi10_pins: &spi10_gpio2 {}; ++spi10_cs_pins: &spi10_cs_gpio1 {}; ++ ++&spi10 { ++ pinctrl-names = "default"; ++ cs-gpios = <&gio 1 1>; ++ pinctrl-0 = <&spi10_pins &spi10_cs_pins>; ++ ++ spidev10: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <20000000>; ++ status = "okay"; ++ }; +}; + - &vec { - power-domains = <&power RPI_POWER_DOMAIN_VEC>; - status = "okay"; -diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi -index 0549686134ea..2ea891228ea0 100644 ---- a/arch/arm/boot/dts/bcm2835.dtsi -+++ b/arch/arm/boot/dts/bcm2835.dtsi -@@ -19,7 +19,7 @@ cpu@0 { - - soc { - ranges = <0x7e000000 0x20000000 0x02000000>; -- dma-ranges = <0x40000000 0x00000000 0x20000000>; -+ dma-ranges = <0x80000000 0x00000000 0x20000000>; - }; - - arm-pmu { -diff --git a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts -index d8af8eeac7b6..bf22b74359d8 100644 ---- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts -+++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts -@@ -128,3 +128,8 @@ &uart0 { - pinctrl-0 = <&uart0_gpio14>; - status = "okay"; - }; ++// ============================================= ++// Board specific stuff here + -+/* i2c on camera/display connector is gpio 28&29 */ -+&i2c0mux { -+ pinctrl-1 = <&i2c0_gpio28>; ++&gio_aon { ++ // Don't use GIO_AON as an interrupt controller because it will ++ // clash with the firmware monitoring the PMIC interrupt via the VPU. ++ ++ /delete-property/ interrupt-controller; +}; -diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts b/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts -index 77099a7871b0..9529c0475673 100644 ---- a/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts -+++ b/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts -@@ -178,3 +178,8 @@ &uart1 { - pinctrl-0 = <&uart1_gpio14>; - status = "okay"; - }; + -+/* i2c on camera/display connector is gpio 44&45 */ -+&i2c0mux { -+ pinctrl-1 = <&i2c0_gpio44>; ++&main_aon_irq { ++ // Don't use the MAIN_AON_IRQ interrupt controller because it will ++ // clash with the firmware monitoring the PMIC interrupt via the VPU. ++ ++ status = "disabled"; +}; -diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts b/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts -index 61010266ca9a..40cb269aed0f 100644 ---- a/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts -+++ b/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts -@@ -181,3 +181,8 @@ &uart1 { - pinctrl-0 = <&uart1_gpio14>; - status = "okay"; - }; + -+/* i2c on camera/display connector is gpio 44&45 */ -+&i2c0mux { -+ pinctrl-1 = <&i2c0_gpio44>; ++&rp1_pwm1 { ++ status = "disabled"; ++ pinctrl-0 = <&rp1_pwm1_gpio45>; ++ pinctrl-names = "default"; +}; -diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts -index dd4a48604097..8f16b6b3fe08 100644 ---- a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts -+++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts -@@ -174,3 +174,8 @@ &sdhost { - status = "okay"; - bus-width = <4>; - }; + -+/* i2c on camera/display connector is gpio 44&45 */ -+&i2c0mux { -+ pinctrl-1 = <&i2c0_gpio44>; ++&thermal_trips { ++ cpu_tepid: cpu-tepid { ++ temperature = <50000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ ++ cpu_warm: cpu-warm { ++ temperature = <60000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ ++ cpu_hot: cpu-hot { ++ temperature = <67500>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ ++ cpu_vhot: cpu-vhot { ++ temperature = <75000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++}; ++ ++&cooling_maps { ++ tepid { ++ trip = <&cpu_tepid>; ++ cooling-device = <&fan 1 1>; ++ }; ++ ++ warm { ++ trip = <&cpu_warm>; ++ cooling-device = <&fan 2 2>; ++ }; ++ ++ hot { ++ trip = <&cpu_hot>; ++ cooling-device = <&fan 3 3>; ++ }; ++ ++ vhot { ++ trip = <&cpu_vhot>; ++ cooling-device = <&fan 4 4>; ++ }; ++ ++ melt { ++ trip = <&cpu_crit>; ++ cooling-device = <&fan 4 4>; ++ }; ++}; ++ ++&gio { ++ // The GPIOs above 35 are not used on Pi 5, so shrink the upper bank ++ // to reduce the clutter in gpioinfo/pinctrl ++ brcm,gpio-bank-widths = <32 4>; ++ ++ gpio-line-names = ++ "-", // GPIO_000 ++ "2712_BOOT_CS_N", // GPIO_001 ++ "2712_BOOT_MISO", // GPIO_002 ++ "2712_BOOT_MOSI", // GPIO_003 ++ "2712_BOOT_SCLK", // GPIO_004 ++ "-", // GPIO_005 ++ "-", // GPIO_006 ++ "-", // GPIO_007 ++ "-", // GPIO_008 ++ "-", // GPIO_009 ++ "-", // GPIO_010 ++ "-", // GPIO_011 ++ "-", // GPIO_012 ++ "-", // GPIO_013 ++ "PCIE_SDA", // GPIO_014 ++ "PCIE_SCL", // GPIO_015 ++ "-", // GPIO_016 ++ "-", // GPIO_017 ++ "-", // GPIO_018 ++ "-", // GPIO_019 ++ "PWR_GPIO", // GPIO_020 ++ "2712_G21_FS", // GPIO_021 ++ "-", // GPIO_022 ++ "-", // GPIO_023 ++ "BT_RTS", // GPIO_024 ++ "BT_CTS", // GPIO_025 ++ "BT_TXD", // GPIO_026 ++ "BT_RXD", // GPIO_027 ++ "WL_ON", // GPIO_028 ++ "BT_ON", // GPIO_029 ++ "WIFI_SDIO_CLK", // GPIO_030 ++ "WIFI_SDIO_CMD", // GPIO_031 ++ "WIFI_SDIO_D0", // GPIO_032 ++ "WIFI_SDIO_D1", // GPIO_033 ++ "WIFI_SDIO_D2", // GPIO_034 ++ "WIFI_SDIO_D3"; // GPIO_035 ++}; ++ ++&gio_aon { ++ gpio-line-names = ++ "RP1_SDA", // AON_GPIO_00 ++ "RP1_SCL", // AON_GPIO_01 ++ "RP1_RUN", // AON_GPIO_02 ++ "SD_IOVDD_SEL", // AON_GPIO_03 ++ "SD_PWR_ON", // AON_GPIO_04 ++ "SD_CDET_N", // AON_GPIO_05 ++ "SD_FLG_N", // AON_GPIO_06 ++ "-", // AON_GPIO_07 ++ "2712_WAKE", // AON_GPIO_08 ++ "2712_STAT_LED", // AON_GPIO_09 ++ "-", // AON_GPIO_10 ++ "-", // AON_GPIO_11 ++ "PMIC_INT", // AON_GPIO_12 ++ "UART_TX_FS", // AON_GPIO_13 ++ "UART_RX_FS", // AON_GPIO_14 ++ "-", // AON_GPIO_15 ++ "-", // AON_GPIO_16 ++ ++ // Pad bank0 out to 32 entries ++ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ++ ++ "HDMI0_SCL", // AON_SGPIO_00 ++ "HDMI0_SDA", // AON_SGPIO_01 ++ "HDMI1_SCL", // AON_SGPIO_02 ++ "HDMI1_SDA", // AON_SGPIO_03 ++ "PMIC_SCL", // AON_SGPIO_04 ++ "PMIC_SDA"; // AON_SGPIO_05 ++ ++ rp1_run_hog { ++ gpio-hog; ++ gpios = <2 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "RP1 RUN pin"; ++ }; ++}; ++ ++&rp1_gpio { ++ gpio-line-names = ++ "ID_SDA", // GPIO0 ++ "ID_SCL", // GPIO1 ++ "GPIO2", // GPIO2 ++ "GPIO3", // GPIO3 ++ "GPIO4", // GPIO4 ++ "GPIO5", // GPIO5 ++ "GPIO6", // GPIO6 ++ "GPIO7", // GPIO7 ++ "GPIO8", // GPIO8 ++ "GPIO9", // GPIO9 ++ "GPIO10", // GPIO10 ++ "GPIO11", // GPIO11 ++ "GPIO12", // GPIO12 ++ "GPIO13", // GPIO13 ++ "GPIO14", // GPIO14 ++ "GPIO15", // GPIO15 ++ "GPIO16", // GPIO16 ++ "GPIO17", // GPIO17 ++ "GPIO18", // GPIO18 ++ "GPIO19", // GPIO19 ++ "GPIO20", // GPIO20 ++ "GPIO21", // GPIO21 ++ "GPIO22", // GPIO22 ++ "GPIO23", // GPIO23 ++ "GPIO24", // GPIO24 ++ "GPIO25", // GPIO25 ++ "GPIO26", // GPIO26 ++ "GPIO27", // GPIO27 ++ ++ "PCIE_RP1_WAKE", // GPIO28 ++ "FAN_TACH", // GPIO29 ++ "HOST_SDA", // GPIO30 ++ "HOST_SCL", // GPIO31 ++ "ETH_RST_N", // GPIO32 ++ "-", // GPIO33 ++ ++ "CD0_IO0_MICCLK", // GPIO34 ++ "CD0_IO0_MICDAT0", // GPIO35 ++ "RP1_PCIE_CLKREQ_N", // GPIO36 ++ "-", // GPIO37 ++ "CD0_SDA", // GPIO38 ++ "CD0_SCL", // GPIO39 ++ "CD1_SDA", // GPIO40 ++ "CD1_SCL", // GPIO41 ++ "USB_VBUS_EN", // GPIO42 ++ "USB_OC_N", // GPIO43 ++ "RP1_STAT_LED", // GPIO44 ++ "FAN_PWM", // GPIO45 ++ "CD1_IO0_MICCLK", // GPIO46 ++ "2712_WAKE", // GPIO47 ++ "CD1_IO1_MICDAT1", // GPIO48 ++ "EN_MAX_USB_CUR", // GPIO49 ++ "-", // GPIO50 ++ "-", // GPIO51 ++ "-", // GPIO52 ++ "-"; // GPIO53 ++ ++ usb_vbus_pins: usb_vbus_pins { ++ function = "vbus1"; ++ pins = "gpio42", "gpio43"; ++ }; +}; -diff --git a/arch/arm/boot/dts/bcm2837-rpi-cm3-io3.dts b/arch/arm/boot/dts/bcm2837-rpi-cm3-io3.dts -index 588d9411ceb6..dde209ade51b 100644 ---- a/arch/arm/boot/dts/bcm2837-rpi-cm3-io3.dts -+++ b/arch/arm/boot/dts/bcm2837-rpi-cm3-io3.dts -@@ -94,3 +94,8 @@ &uart0 { - pinctrl-0 = <&uart0_gpio14>; - status = "okay"; - }; + -+/* WHAT TO DO HERE? */ -+&i2c0mux { -+ pinctrl-1 = <&i2c0_gpio28>; ++/ { ++ aliases: aliases { ++ blconfig = &blconfig; ++ blpubkey = &blpubkey; ++ bluetooth = &bluetooth; ++ console = &uart10; ++ ethernet0 = &rp1_eth; ++ wifi0 = &wifi; ++ fb = &fb; ++ mailbox = &mailbox; ++ mmc0 = &sdio1; ++ uart0 = &uart0; ++ uart1 = &uart1; ++ uart2 = &uart2; ++ uart3 = &uart3; ++ uart4 = &uart4; ++ uart10 = &uart10; ++ serial0 = &uart0; ++ serial1 = &uart1; ++ serial2 = &uart2; ++ serial3 = &uart3; ++ serial4 = &uart4; ++ serial10 = &uart10; ++ i2c = &i2c_arm; ++ i2c0 = &i2c0; ++ i2c1 = &i2c1; ++ i2c2 = &i2c2; ++ i2c3 = &i2c3; ++ i2c4 = &i2c4; ++ i2c5 = &i2c5; ++ i2c6 = &i2c6; ++ i2c10 = &i2c_rp1boot; ++ // Bit-bashed i2c_gpios start at 10 ++ spi0 = &spi0; ++ spi1 = &spi1; ++ spi2 = &spi2; ++ spi3 = &spi3; ++ spi4 = &spi4; ++ spi5 = &spi5; ++ spi10 = &spi10; ++ gpio0 = &gpio; ++ gpio1 = &gio; ++ gpio2 = &gio_aon; ++ gpio3 = &pinctrl; ++ gpio4 = &pinctrl_aon; ++ usb0 = &rp1_usb0; ++ usb1 = &rp1_usb1; ++ drm-dsi1 = &dsi0; ++ drm-dsi2 = &dsi1; ++ }; ++ ++ __overrides__ { ++ bdaddr = <&bluetooth>, "local-bd-address"; ++ button_debounce = <&pwr_key>, "debounce-interval:0"; ++ cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status"; ++ uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0; ++ i2c0 = <&i2c0>, "status"; ++ i2c1 = <&i2c1>, "status"; ++ i2c = <&i2c1>, "status"; ++ i2c_arm = <&i2c_arm>, "status"; ++ i2c_vc = <&i2c_vc>, "status"; ++ i2c_csi_dsi = <&i2c_csi_dsi>, "status"; ++ i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status"; ++ i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status"; ++ i2c0_baudrate = <&i2c0>, "clock-frequency:0"; ++ i2c1_baudrate = <&i2c1>, "clock-frequency:0"; ++ i2c_baudrate = <&i2c_arm>, "clock-frequency:0"; ++ i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0"; ++ i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0"; ++ krnbt = <&bluetooth>, "status"; ++ nvme = <&pciex1>, "status"; ++ pciex1 = <&pciex1>, "status"; ++ pciex1_gen = <&pciex1> , "max-link-speed:0"; ++ pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?"; ++ pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; ++ pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; ++ random = <&random>, "status"; ++ rtc = <&rpi_rtc>, "status"; ++ rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0"; ++ sd_cqe = <&sdio1>, "supports-cqe?"; ++ spi = <&spi0>, "status"; ++ suspend = <&pwr_key>, "linux,code:0=205"; ++ uart0 = <&uart0>, "status"; ++ wifiaddr = <&wifi>, "local-mac-address"; ++ ++ act_led_gpio = <&led_act>,"gpios:4",<&led_act>,"gpios:0=",<&gpio>; ++ act_led_activelow = <&led_act>,"gpios:8"; ++ act_led_trigger = <&led_act>, "linux,default-trigger"; ++ pwr_led_gpio = <&led_pwr>,"gpios:4"; ++ pwr_led_activelow = <&led_pwr>, "gpios:8"; ++ pwr_led_trigger = <&led_pwr>, "linux,default-trigger"; ++ eth_led0 = <&phy1>,"led-modes:0"; ++ eth_led1 = <&phy1>,"led-modes:4"; ++ drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0; ++ drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1; ++ drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi; ++ drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4; ++ drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0; ++ drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1; ++ drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi; ++ drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4; ++ drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0; ++ drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1; ++ drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi; ++ drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4; ++ ++ fan_temp0 = <&cpu_tepid>,"temperature:0"; ++ fan_temp1 = <&cpu_warm>,"temperature:0"; ++ fan_temp2 = <&cpu_hot>,"temperature:0"; ++ fan_temp3 = <&cpu_vhot>,"temperature:0"; ++ fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0"; ++ fan_temp1_hyst = <&cpu_warm>,"hysteresis:0"; ++ fan_temp2_hyst = <&cpu_hot>,"hysteresis:0"; ++ fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0"; ++ fan_temp0_speed = <&fan>, "cooling-levels:4"; ++ fan_temp1_speed = <&fan>, "cooling-levels:8"; ++ fan_temp2_speed = <&fan>, "cooling-levels:12"; ++ fan_temp3_speed = <&fan>, "cooling-levels:16"; ++ }; +}; -diff --git a/arch/arm/boot/dts/bcm283x-rpi-csi0-2lane.dtsi b/arch/arm/boot/dts/bcm283x-rpi-csi0-2lane.dtsi +diff --git a/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts b/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts new file mode 100644 -index 000000000000..6e4ce8622b47 +index 000000000000..f89321921f27 --- /dev/null -+++ b/arch/arm/boot/dts/bcm283x-rpi-csi0-2lane.dtsi -@@ -0,0 +1,4 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+&csi0 { -+ brcm,num-data-lanes = <2>; ++++ b/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts +@@ -0,0 +1,20 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/dts-v1/; ++ ++#include "bcm2712-rpi-cm5.dtsi" ++ ++// The RP1 USB3 interfaces are not usable on CM4IO ++ ++&rp1_usb0 { ++ status = "disabled"; +}; -diff --git a/arch/arm/boot/dts/bcm283x-rpi-csi1-2lane.dtsi b/arch/arm/boot/dts/bcm283x-rpi-csi1-2lane.dtsi -new file mode 100644 -index 000000000000..6938f4daacdc ---- /dev/null -+++ b/arch/arm/boot/dts/bcm283x-rpi-csi1-2lane.dtsi -@@ -0,0 +1,4 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+&csi1 { -+ brcm,num-data-lanes = <2>; ++ ++&rp1_usb1 { ++ status = "disabled"; +}; -diff --git a/arch/arm/boot/dts/bcm283x-rpi-csi1-4lane.dtsi b/arch/arm/boot/dts/bcm283x-rpi-csi1-4lane.dtsi -new file mode 100644 -index 000000000000..b37037437bee ---- /dev/null -+++ b/arch/arm/boot/dts/bcm283x-rpi-csi1-4lane.dtsi -@@ -0,0 +1,4 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+&csi1 { -+ brcm,num-data-lanes = <4>; ++ ++/ { ++ __overrides__ { ++ i2c_csi_dsi = <&i2c_csi_dsi>, "status"; ++ }; +}; -diff --git a/arch/arm/boot/dts/bcm283x-rpi-i2c0mux_0_28.dtsi b/arch/arm/boot/dts/bcm283x-rpi-i2c0mux_0_28.dtsi +diff --git a/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts b/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts new file mode 100644 -index 000000000000..38f0074bce3f +index 000000000000..47ce4ff5049a --- /dev/null -+++ b/arch/arm/boot/dts/bcm283x-rpi-i2c0mux_0_28.dtsi -@@ -0,0 +1,4 @@ -+&i2c0mux { -+ pinctrl-0 = <&i2c0_gpio0>; -+ pinctrl-1 = <&i2c0_gpio28>; ++++ b/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts +@@ -0,0 +1,10 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/dts-v1/; ++ ++#include "bcm2712-rpi-cm5.dtsi" ++ ++/ { ++ __overrides__ { ++ i2c_csi_dsi = <&i2c_csi_dsi>, "status"; ++ }; +}; -diff --git a/arch/arm/boot/dts/bcm283x-rpi-i2c0mux_0_44.dtsi b/arch/arm/boot/dts/bcm283x-rpi-i2c0mux_0_44.dtsi +diff --git a/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi b/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi new file mode 100644 -index 000000000000..119946d878db +index 000000000000..068138904695 --- /dev/null -+++ b/arch/arm/boot/dts/bcm283x-rpi-i2c0mux_0_44.dtsi -@@ -0,0 +1,4 @@ -+&i2c0mux { -+ pinctrl-0 = <&i2c0_gpio0>; -+ pinctrl-1 = <&i2c0_gpio44>; -+}; -diff --git a/arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi b/arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi -deleted file mode 100644 -index 0ff0e9e25327..000000000000 ---- a/arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi -+++ /dev/null -@@ -1,7 +0,0 @@ --// 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 --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi -index ffdf7c4fba46..62d7ee513549 100644 ---- a/arch/arm/boot/dts/bcm283x.dtsi -+++ b/arch/arm/boot/dts/bcm283x.dtsi -@@ -336,7 +336,7 @@ spi: spi@7e204000 { - status = "disabled"; - }; - -- i2c0: i2c@7e205000 { -+ i2c0if: i2c@7e205000 { - compatible = "brcm,bcm2835-i2c"; - reg = <0x7e205000 0x200>; - interrupts = <2 21>; -@@ -346,6 +346,30 @@ i2c0: i2c@7e205000 { - status = "disabled"; - }; - -+ i2c0mux: i2c0mux { -+ compatible = "i2c-mux-pinctrl"; -+ #address-cells = <1>; -+ #size-cells = <0>; ++++ b/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi +@@ -0,0 +1,860 @@ ++// SPDX-License-Identifier: GPL-2.0 + -+ i2c-parent = <&i2c0if>; ++#include <dt-bindings/gpio/gpio.h> ++#include <dt-bindings/clock/rp1.h> ++#include <dt-bindings/interrupt-controller/irq.h> ++#include <dt-bindings/mfd/rp1.h> ++#include <dt-bindings/pwm/pwm.h> ++#include <dt-bindings/reset/raspberrypi,firmware-reset.h> + -+ pinctrl-names = "i2c0", "i2c_csi_dsi"; ++#define i2c0 _i2c0 ++#define i2c3 _i2c3 ++#define i2c4 _i2c4 ++#define i2c5 _i2c5 ++#define i2c6 _i2c6 ++#define i2c8 _i2c8 ++#define i2s _i2s ++#define pwm0 _pwm0 ++#define pwm1 _pwm1 ++#define spi0 _spi0 ++#define spi3 _spi3 ++#define spi4 _spi4 ++#define spi5 _spi5 ++#define spi6 _spi6 ++#define uart0 _uart0 ++#define uart2 _uart2 ++#define uart5 _uart5 ++ ++#include "bcm2712.dtsi" ++ ++#undef i2c0 ++#undef i2c3 ++#undef i2c4 ++#undef i2c5 ++#undef i2c6 ++#undef i2c8 ++#undef i2s ++#undef pwm0 ++#undef pwm1 ++#undef spi0 ++#undef spi3 ++#undef spi4 ++#undef spi5 ++#undef spi6 ++#undef uart0 ++#undef uart2 ++#undef uart3 ++#undef uart4 ++#undef uart5 + -+ status = "disabled"; ++/ { ++ compatible = "raspberrypi,5-compute-model", "brcm,bcm2712"; ++ model = "Raspberry Pi Compute Module 5"; + -+ i2c0: i2c@0 { -+ reg = <0>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ }; ++ /* Will be filled by the bootloader */ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0 0 0x28000000>; ++ }; + -+ i2c_csi_dsi: i2c@1 { -+ reg = <1>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ }; -+ }; ++ leds: leds { ++ compatible = "gpio-leds"; + - dpi: dpi@7e208000 { - compatible = "brcm,bcm2835-dpi"; - reg = <0x7e208000 0x8c>; -@@ -466,14 +490,6 @@ i2c1: i2c@7e804000 { - 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 --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile -new file mode 100644 -index 000000000000..6fcacdccb608 ---- /dev/null -+++ b/arch/arm/boot/dts/overlays/Makefile -@@ -0,0 +1,257 @@ -+# Overlays for the Raspberry Pi platform ++ led_pwr: led-pwr { ++ label = "PWR"; ++ gpios = <&rp1_gpio 44 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ linux,default-trigger = "none"; ++ }; + -+dtb-$(CONFIG_ARCH_BCM2835) += overlay_map.dtb ++ led_act: led-act { ++ label = "ACT"; ++ gpios = <&gio_aon 9 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; ++ }; ++ }; + -+dtbo-$(CONFIG_ARCH_BCM2835) += \ -+ act-led.dtbo \ -+ adafruit-st7735r.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-dac.dtbo \ -+ cma.dtbo \ -+ cutiepi-panel.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 \ -+ fbtft.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 \ -+ imx519.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.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 \ -+ midi-uart2.dtbo \ -+ midi-uart3.dtbo \ -+ midi-uart4.dtbo \ -+ midi-uart5.dtbo \ -+ minipitft13.dtbo \ -+ miniuart-bt.dtbo \ -+ mlx90640.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 \ -+ qca7000-uart0.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-0cs.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-fkms-v3d-pi4.dtbo \ -+ vc4-kms-dpi-generic.dtbo \ -+ vc4-kms-dpi-panel.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 \ -+ vl805.dtbo \ -+ w1-gpio.dtbo \ -+ w1-gpio-pullup.dtbo \ -+ w5500.dtbo \ -+ wittypi.dtbo \ -+ wm8960-soundcard.dtbo ++ sd_io_1v8_reg: sd_io_1v8_reg { ++ compatible = "regulator-gpio"; ++ regulator-name = "vdd-sd-io"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ regulator-settling-time-us = <5000>; ++ gpios = <&gio_aon 3 GPIO_ACTIVE_HIGH>; ++ states = <1800000 0x1 ++ 3300000 0x0>; ++ status = "okay"; ++ }; + -+targets += dtbs dtbs_install -+targets += $(dtbo-y) ++ sd_vcc_reg: sd_vcc_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc-sd"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ enable-active-high; ++ gpios = <&gio_aon 4 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++ }; + -+always-y := $(dtbo-y) -+clean-files := *.dtbo -diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README -new file mode 100644 -index 000000000000..3a0961540427 ---- /dev/null -+++ b/arch/arm/boot/dts/overlays/README -@@ -0,0 +1,3861 @@ -+Introduction -+============ ++ wl_on_reg: wl_on_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "wl-on-regulator"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ pinctrl-0 = <&wl_on_pins>; ++ pinctrl-names = "default"; + -+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. ++ gpio = <&gio 28 GPIO_ACTIVE_HIGH>; + -+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: ++ startup-delay-us = <150000>; ++ enable-active-high; ++ }; + -+ device_tree= ++ clocks: clocks { ++ }; + -+to your config.txt, which should cause your Pi to revert to the old way of -+doing things after a reboot. ++ cam1_clk: cam1_clk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ status = "disabled"; ++ }; + -+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: ++ cam0_clk: cam0_clk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ status = "disabled"; ++ }; + -+ dtparam=i2c=on,i2s=on,spi=on ++ cam0_reg: cam0_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "cam0_reg"; ++ enable-active-high; ++ status = "okay"; ++ gpio = <&rp1_gpio 34 0>; // CD0_IO0_MICCLK, to CAM_GPIO on connector ++ }; + -+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. ++ cam_dummy_reg: cam_dummy_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "cam-dummy-reg"; ++ status = "okay"; ++ }; + -+Configuring additional, optional hardware is done using Device Tree overlays -+(see below). ++ dummy: dummy { ++ // A target for unwanted overlay fragments ++ }; + -+GPIO numbering uses the hardware pin numbering scheme (aka BCM scheme) and -+not the physical pin numbers. + -+raspi-config -+============ ++ // A few extra labels to keep overlays happy + -+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. ++ i2c0if: i2c0if {}; ++ i2c0mux: i2c0mux {}; ++}; + -+Modules -+======= ++rp1_target: &pcie2 { ++ brcm,enable-mps-rcb; ++ brcm,vdm-qos-map = <0xbbaa9888>; ++ aspm-no-l0s; ++ status = "okay"; ++}; + -+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). ++// Add some labels to 2712 device + -+Using Overlays -+============== ++// The system UART ++uart10: &_uart0 { status = "okay"; }; + -+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: ++// The system SPI for the bootloader EEPROM ++spi10: &_spi0 { status = "okay"; }; + -+ modprobe i2c-bcm2835 -+ modprobe rtc-ds1307 -+ echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device ++i2c_rp1boot: &_i2c3 { }; + -+With DT enabled, this becomes a line in config.txt: ++#include "rp1.dtsi" + -+ dtoverlay=i2c-rtc,ds1307 ++&rp1 { ++ // PCIe address space layout: ++ // 00_00000000-00_00xxxxxx = RP1 peripherals ++ // 10_00000000-1x_xxxxxxxx = up to 64GB system RAM + -+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: ++ // outbound access aimed at PCIe 0_00xxxxxx -> RP1 c0_40xxxxxx ++ // This is the RP1 peripheral space ++ ranges = <0xc0 0x40000000 ++ 0x02000000 0x00 0x00000000 ++ 0x00 0x00400000>; + -+ dtoverlay=i2c-rtc,ds1307,addr=0x68 ++ dma-ranges = ++ // inbound RP1 1x_xxxxxxxx -> PCIe 1x_xxxxxxxx ++ <0x10 0x00000000 ++ 0x43000000 0x10 0x00000000 ++ 0x10 0x00000000>, + -+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. ++ // inbound RP1 c0_40xxxxxx -> PCIe 00_00xxxxxx ++ // This allows the RP1 DMA controller to address RP1 hardware ++ <0xc0 0x40000000 ++ 0x02000000 0x0 0x00000000 ++ 0x0 0x00400000>, + -+Making new Overlays based on existing Overlays -+============================================== ++ // inbound RP1 0x_xxxxxxxx -> PCIe 1x_xxxxxxxx ++ <0x00 0x00000000 ++ 0x02000000 0x10 0x00000000 ++ 0x10 0x00000000>; ++}; + -+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. ++// Expose RP1 nodes as system nodes with labels + -+ # 2 CAN FD interfaces on spi but with different pins -+ dtoverlay=mcp251xfd,spi0-0,interrupt=25 -+ dtoverlay=mcp251xfd,spi0-1,interrupt=24 ++&rp1_dma { ++ status = "okay"; ++}; + -+ # a realtime clock on i2c -+ dtoverlay=i2c-rtc,pcf85063 ++&rp1_eth { ++ status = "okay"; ++ phy-handle = <&phy1>; ++ phy-reset-gpios = <&rp1_gpio 32 GPIO_ACTIVE_LOW>; ++ phy-reset-duration = <5>; + -+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. ++ phy1: ethernet-phy@1 { ++ reg = <0x1>; ++ brcm,powerdown-enable; ++ interrupt-parent = <&gpio>; ++ interrupts = <37 IRQ_TYPE_LEVEL_LOW>; ++ }; ++}; + -+A new overlay can be generated by using ovmerge utility. -+https://github.com/raspberrypi/utils/blob/master/ovmerge/ovmerge ++gpio: &rp1_gpio { ++ status = "okay"; ++}; + -+To generate an overlay for the above configuration we pass the configuration -+to ovmerge and add the -c flag. ++aux: &dummy {}; + -+ ovmerge -c mcp251xfd-overlay.dts,spi0-0,interrupt=25 \ -+ mcp251xfd-overlay.dts,spi0-1,interrupt=24 \ -+ i2c-rtc-overlay.dts,pcf85063 \ -+ >> merged-overlay.dts ++&rp1_usb0 { ++ pinctrl-0 = <&usb_vbus_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; + -+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. ++&rp1_usb1 { ++ status = "okay"; ++}; + -+ dtoverlay=merged ++#include "bcm2712-rpi.dtsi" + -+It does the same as the original configuration but without parameters. ++i2c_csi_dsi0: &i2c6 { // Note: This is for MIPI0 connector only ++ pinctrl-0 = <&rp1_i2c6_38_39>; ++ pinctrl-names = "default"; ++ clock-frequency = <100000>; ++}; + -+The Overlay and Parameter Reference -+=================================== ++i2c_csi_dsi1: &i2c0 { // Note: This is for MIPI1 connector ++}; + -+N.B. When editing this file, please preserve the indentation levels to make it -+simple to parse programmatically. NO HARD TABS. ++i2c_csi_dsi: &i2c_csi_dsi1 { }; // An alias for compatibility + ++cam1_reg: &cam0_reg { // Shares CAM_GPIO with cam0_reg ++}; + -+Name: <The base DTB> -+Info: Configures the base Raspberry Pi hardware -+Load: <loaded automatically> -+Params: -+ ant1 Select antenna 1 (default). CM4 only. ++csi0: &rp1_csi0 { }; ++csi1: &rp1_csi1 { }; ++dsi0: &rp1_dsi0 { }; ++dsi1: &rp1_dsi1 { }; ++dpi: &rp1_dpi { }; ++vec: &rp1_vec { }; ++dpi_gpio0: &rp1_dpi_24bit_gpio0 { }; ++dpi_gpio1: &rp1_dpi_24bit_gpio2 { }; ++dpi_18bit_cpadhi_gpio0: &rp1_dpi_18bit_cpadhi_gpio0 { }; ++dpi_18bit_cpadhi_gpio2: &rp1_dpi_18bit_cpadhi_gpio2 { }; ++dpi_18bit_gpio0: &rp1_dpi_18bit_gpio0 { }; ++dpi_18bit_gpio2: &rp1_dpi_18bit_gpio2 { }; ++dpi_16bit_cpadhi_gpio0: &rp1_dpi_16bit_cpadhi_gpio0 { }; ++dpi_16bit_cpadhi_gpio2: &rp1_dpi_16bit_cpadhi_gpio2 { }; ++dpi_16bit_gpio0: &rp1_dpi_16bit_gpio0 { }; ++dpi_16bit_gpio2: &rp1_dpi_16bit_gpio2 { }; + -+ ant2 Select antenna 2. CM4 only. ++/* Add the IOMMUs for some RP1 bus masters */ + -+ noant Disable both antennas. CM4 only. ++&csi0 { ++ iommus = <&iommu5>; ++}; + -+ audio Set to "on" to enable the onboard ALSA audio -+ interface (default "off") ++&csi1 { ++ iommus = <&iommu5>; ++}; + -+ axiperf Set to "on" to enable the AXI bus performance -+ monitors. -+ See /sys/kernel/debug/raspberrypi_axi_monitor -+ for the results. ++&dsi0 { ++ iommus = <&iommu5>; ++}; + -+ cam0_reg Enables CAM 0 regulator. CM1 & 3 only. ++&dsi1 { ++ iommus = <&iommu5>; ++}; + -+ cam0_reg_gpio Set GPIO for CAM 0 regulator. Default 30. -+ CM1 & 3 only. ++&dpi { ++ iommus = <&iommu5>; ++}; + -+ cam1_reg Enables CAM 1 regulator. CM1 & 3 only. ++&vec { ++ iommus = <&iommu5>; ++}; + -+ cam1_reg_gpio Set GPIO for CAM 1 regulator. Default 2. -+ CM1 & 3 only. ++&ddc0 { ++ status = "disabled"; ++}; + -+ eee Enable Energy Efficient Ethernet support for -+ compatible devices (default "on"). See also -+ "tx_lpi_timer". Pi3B+ only. ++&ddc1 { ++ status = "disabled"; ++}; + -+ 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. ++&hdmi0 { ++ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>; ++ clock-names = "hdmi", "bvb", "audio", "cec"; ++ status = "disabled"; ++}; + -+ eth_led0 Set mode of LED0 - amber on Pi3B+ (default "1"), -+ green on Pi4 (default "0"). -+ The legal values are: ++&hdmi1 { ++ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>; ++ clock-names = "hdmi", "bvb", "audio", "cec"; ++ status = "disabled"; ++}; + -+ Pi3B+ ++&hvs { ++ clocks = <&firmware_clocks 4>, <&firmware_clocks 16>; ++ clock-names = "core", "disp"; ++}; + -+ 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 ++&mop { ++ status = "disabled"; ++}; + -+ Pi4 ++&moplet { ++ status = "disabled"; ++}; ++ ++&pixelvalve0 { ++ status = "disabled"; ++}; ++ ++&pixelvalve1 { ++ status = "disabled"; ++}; ++ ++&disp_intr { ++ status = "disabled"; ++}; ++ ++/* SDIO1 is used to drive the eMMC/SD card */ ++&sdio1 { ++ pinctrl-0 = <&emmc_cmddat_pulls>, <&emmc_ds_pull>, <&emmc_aon_cd_pins>; ++ pinctrl-names = "default"; ++ vqmmc-supply = <&sd_io_1v8_reg>; ++ vmmc-supply = <&sd_vcc_reg>; ++ bus-width = <8>; ++ sd-uhs-sdr50; ++ sd-uhs-ddr50; ++ sd-uhs-sdr104; ++ mmc-hs200-1_8v; ++ broken-cd; ++ supports-cqe; ++ status = "okay"; ++}; ++ ++&pinctrl_aon { ++ emmc_aon_cd_pins: emmc_aon_cd_pins { ++ function = "sd_card_g"; ++ pins = "aon_gpio5"; ++ bias-pull-up; ++ }; ++ ++ /* Slight hack - only one PWM pin (status LED) is usable */ ++ aon_pwm_1pin: aon_pwm_1pin { ++ function = "aon_pwm"; ++ pins = "aon_gpio9"; ++ }; ++}; ++ ++&pinctrl { ++ pwr_button_pins: pwr_button_pins { ++ function = "gpio"; ++ pins = "gpio20"; ++ bias-pull-up; ++ }; ++ ++ wl_on_pins: wl_on_pins { ++ function = "gpio"; ++ pins = "gpio28"; ++ }; ++ ++ bt_shutdown_pins: bt_shutdown_pins { ++ function = "gpio"; ++ pins = "gpio29"; ++ }; ++ ++ emmc_ds_pull: emmc_ds_pull { ++ pins = "emmc_ds"; ++ bias-pull-down; ++ }; ++ ++ emmc_cmddat_pulls: emmc_cmddat_pulls { ++ pins = "emmc_cmd", "emmc_dat0", "emmc_dat1", "emmc_dat2", "emmc_dat3", ++ "emmc_dat4", "emmc_dat5", "emmc_dat6", "emmc_dat7"; ++ bias-pull-up; ++ }; ++}; ++ ++/* uarta communicates with the BT module */ ++&uarta { ++ uart-has-rtscts; ++ auto-flow-control; ++ status = "okay"; ++ clock-frequency = <96000000>; ++ pinctrl-0 = <&uarta_24_pins &bt_shutdown_pins>; ++ pinctrl-names = "default"; ++ ++ bluetooth: bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ max-speed = <3000000>; ++ shutdown-gpios = <&gio 29 GPIO_ACTIVE_HIGH>; ++ local-bd-address = 00 00 00 00 00 00 ; ++ }; ++}; ++ ++&i2c_rp1boot { ++ clock-frequency = <400000>; ++ pinctrl-0 = <&i2c3_m4_agpio0_pins>; ++ pinctrl-names = "default"; ++}; ++ ++/ { ++ chosen: chosen { ++ bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1"; ++ stdout-path = "serial10:115200n8"; ++ }; ++ ++ fan: cooling_fan { ++ status = "disabled"; ++ compatible = "pwm-fan"; ++ #cooling-cells = <2>; ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ cooling-levels = <0 75 125 175 250>; ++ pwms = <&rp1_pwm1 3 41566 PWM_POLARITY_INVERTED>; ++ rpm-regmap = <&rp1_pwm1>; ++ rpm-offset = <0x3c>; ++ }; ++ ++ pwr_button { ++ compatible = "gpio-keys"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwr_button_pins>; ++ status = "okay"; ++ ++ pwr_key: pwr { ++ label = "pwr_button"; ++ // linux,code = <205>; // KEY_SUSPEND ++ linux,code = <116>; // KEY_POWER ++ gpios = <&gio 20 GPIO_ACTIVE_LOW>; ++ debounce-interval = <50>; // ms ++ }; ++ }; ++}; ++ ++&usb { ++ power-domains = <&power RPI_POWER_DOMAIN_USB>; ++}; ++ ++/* SDIO2 drives the WLAN interface */ ++&sdio2 { ++ pinctrl-0 = <&sdio2_30_pins>; ++ pinctrl-names = "default"; ++ bus-width = <4>; ++ vmmc-supply = <&wl_on_reg>; ++ sd-uhs-ddr50; ++ non-removable; ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ wifi: wifi@1 { ++ reg = <1>; ++ compatible = "brcm,bcm4329-fmac"; ++ local-mac-address = 00 00 00 00 00 00; ++ }; ++}; ++ ++&rpivid { ++ status = "okay"; ++}; ++ ++&pinctrl { ++ spi10_gpio2: spi10_gpio2 { ++ function = "vc_spi0"; ++ pins = "gpio2", "gpio3", "gpio4"; ++ bias-disable; ++ }; ++ ++ spi10_cs_gpio1: spi10_cs_gpio1 { ++ function = "gpio"; ++ pins = "gpio1"; ++ bias-pull-up; ++ }; ++}; ++ ++spi10_pins: &spi10_gpio2 {}; ++spi10_cs_pins: &spi10_cs_gpio1 {}; ++ ++&spi10 { ++ pinctrl-names = "default"; ++ cs-gpios = <&gio 1 1>; ++ pinctrl-0 = <&spi10_pins &spi10_cs_pins>; ++ ++ spidev10: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <20000000>; ++ status = "okay"; ++ }; ++}; ++ ++// ============================================= ++// Board specific stuff here ++ ++&gio_aon { ++ // Don't use GIO_AON as an interrupt controller because it will ++ // clash with the firmware monitoring the PMIC interrupt via the VPU. ++ ++ /delete-property/ interrupt-controller; ++}; ++ ++&main_aon_irq { ++ // Don't use the MAIN_AON_IRQ interrupt controller because it will ++ // clash with the firmware monitoring the PMIC interrupt via the VPU. ++ ++ status = "disabled"; ++}; ++ ++&rp1_pwm1 { ++ status = "disabled"; ++ pinctrl-0 = <&rp1_pwm1_gpio45>; ++ pinctrl-names = "default"; ++}; ++ ++&thermal_trips { ++ cpu_tepid: cpu-tepid { ++ temperature = <50000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ ++ cpu_warm: cpu-warm { ++ temperature = <60000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ ++ cpu_hot: cpu-hot { ++ temperature = <67500>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ ++ cpu_vhot: cpu-vhot { ++ temperature = <75000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++}; ++ ++&cooling_maps { ++ tepid { ++ trip = <&cpu_tepid>; ++ cooling-device = <&fan 1 1>; ++ }; ++ ++ warm { ++ trip = <&cpu_warm>; ++ cooling-device = <&fan 2 2>; ++ }; ++ ++ hot { ++ trip = <&cpu_hot>; ++ cooling-device = <&fan 3 3>; ++ }; ++ ++ vhot { ++ trip = <&cpu_vhot>; ++ cooling-device = <&fan 4 4>; ++ }; ++ ++ melt { ++ trip = <&cpu_crit>; ++ cooling-device = <&fan 4 4>; ++ }; ++}; ++ ++&gio { ++ // The GPIOs above 35 are not used on Pi 5, so shrink the upper bank ++ // to reduce the clutter in gpioinfo/pinctrl ++ brcm,gpio-bank-widths = <32 4>; ++ ++ gpio-line-names = ++ "-", // GPIO_000 ++ "2712_BOOT_CS_N", // GPIO_001 ++ "2712_BOOT_MISO", // GPIO_002 ++ "2712_BOOT_MOSI", // GPIO_003 ++ "2712_BOOT_SCLK", // GPIO_004 ++ "-", // GPIO_005 ++ "-", // GPIO_006 ++ "-", // GPIO_007 ++ "-", // GPIO_008 ++ "-", // GPIO_009 ++ "-", // GPIO_010 ++ "-", // GPIO_011 ++ "-", // GPIO_012 ++ "-", // GPIO_013 ++ "-", // GPIO_014 ++ "-", // GPIO_015 ++ "-", // GPIO_016 ++ "-", // GPIO_017 ++ "-", // GPIO_018 ++ "-", // GPIO_019 ++ "PWR_GPIO", // GPIO_020 ++ "2712_G21_FS", // GPIO_021 ++ "-", // GPIO_022 ++ "-", // GPIO_023 ++ "BT_RTS", // GPIO_024 ++ "BT_CTS", // GPIO_025 ++ "BT_TXD", // GPIO_026 ++ "BT_RXD", // GPIO_027 ++ "WL_ON", // GPIO_028 ++ "BT_ON", // GPIO_029 ++ "WIFI_SDIO_CLK", // GPIO_030 ++ "WIFI_SDIO_CMD", // GPIO_031 ++ "WIFI_SDIO_D0", // GPIO_032 ++ "WIFI_SDIO_D1", // GPIO_033 ++ "WIFI_SDIO_D2", // GPIO_034 ++ "WIFI_SDIO_D3"; // GPIO_035 ++}; ++ ++&gio_aon { ++ gpio-line-names = ++ "RP1_SDA", // AON_GPIO_00 ++ "RP1_SCL", // AON_GPIO_01 ++ "RP1_RUN", // AON_GPIO_02 ++ "SD_IOVDD_SEL", // AON_GPIO_03 ++ "SD_PWR_ON", // AON_GPIO_04 ++ "ANT1", // AON_GPIO_05 ++ "ANT2", // AON_GPIO_06 ++ "-", // AON_GPIO_07 ++ "2712_WAKE", // AON_GPIO_08 ++ "2712_STAT_LED", // AON_GPIO_09 ++ "-", // AON_GPIO_10 ++ "-", // AON_GPIO_11 ++ "PMIC_INT", // AON_GPIO_12 ++ "UART_TX_FS", // AON_GPIO_13 ++ "UART_RX_FS", // AON_GPIO_14 ++ "-", // AON_GPIO_15 ++ "-", // AON_GPIO_16 ++ ++ // Pad bank0 out to 32 entries ++ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ++ ++ "HDMI0_SCL", // AON_SGPIO_00 ++ "HDMI0_SDA", // AON_SGPIO_01 ++ "HDMI1_SCL", // AON_SGPIO_02 ++ "HDMI1_SDA", // AON_SGPIO_03 ++ "PMIC_SCL", // AON_SGPIO_04 ++ "PMIC_SDA"; // AON_SGPIO_05 ++ ++ rp1_run_hog { ++ gpio-hog; ++ gpios = <2 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "RP1 RUN pin"; ++ }; ++}; ++ ++&rp1_gpio { ++ gpio-line-names = ++ "ID_SDA", // GPIO0 ++ "ID_SCL", // GPIO1 ++ "GPIO2", // GPIO2 ++ "GPIO3", // GPIO3 ++ "GPIO4", // GPIO4 ++ "GPIO5", // GPIO5 ++ "GPIO6", // GPIO6 ++ "GPIO7", // GPIO7 ++ "GPIO8", // GPIO8 ++ "GPIO9", // GPIO9 ++ "GPIO10", // GPIO10 ++ "GPIO11", // GPIO11 ++ "GPIO12", // GPIO12 ++ "GPIO13", // GPIO13 ++ "GPIO14", // GPIO14 ++ "GPIO15", // GPIO15 ++ "GPIO16", // GPIO16 ++ "GPIO17", // GPIO17 ++ "GPIO18", // GPIO18 ++ "GPIO19", // GPIO19 ++ "GPIO20", // GPIO20 ++ "GPIO21", // GPIO21 ++ "GPIO22", // GPIO22 ++ "GPIO23", // GPIO23 ++ "GPIO24", // GPIO24 ++ "GPIO25", // GPIO25 ++ "GPIO26", // GPIO26 ++ "GPIO27", // GPIO27 ++ ++ "PCIE_PWR_EN", // GPIO28 ++ "FAN_TACH", // GPIO29 ++ "HOST_SDA", // GPIO30 ++ "HOST_SCL", // GPIO31 ++ "ETH_RST_N", // GPIO32 ++ "PCIE_DET_WAKE", // GPIO33 ++ ++ "CD0_IO0_MICCLK", // GPIO34 ++ "CD0_IO0_MICDAT0", // GPIO35 ++ "RP1_PCIE_CLKREQ_N", // GPIO36 ++ "ETH_IRQ_N", // GPIO37 ++ "SDA0", // GPIO38 ++ "SCL0", // GPIO39 ++ "-", // GPIO40 ++ "-", // GPIO41 ++ "USB_VBUS_EN", // GPIO42 ++ "USB_OC_N", // GPIO43 ++ "RP1_STAT_LED", // GPIO44 ++ "FAN_PWM", // GPIO45 ++ "-", // GPIO46 ++ "2712_WAKE", // GPIO47 ++ "-", // GPIO48 ++ "-", // GPIO49 ++ "-", // GPIO50 ++ "-", // GPIO51 ++ "-", // GPIO52 ++ "-"; // GPIO53 ++ ++ usb_vbus_pins: usb_vbus_pins { ++ function = "vbus1"; ++ pins = "gpio42", "gpio43"; ++ }; ++}; ++ ++/ { ++ aliases: aliases { ++ blconfig = &blconfig; ++ blpubkey = &blpubkey; ++ bluetooth = &bluetooth; ++ console = &uart10; ++ ethernet0 = &rp1_eth; ++ wifi0 = &wifi; ++ fb = &fb; ++ mailbox = &mailbox; ++ mmc0 = &sdio1; ++ uart0 = &uart0; ++ uart1 = &uart1; ++ uart2 = &uart2; ++ uart3 = &uart3; ++ uart4 = &uart4; ++ uart10 = &uart10; ++ serial0 = &uart0; ++ serial1 = &uart1; ++ serial2 = &uart2; ++ serial3 = &uart3; ++ serial4 = &uart4; ++ serial10 = &uart10; ++ i2c = &i2c_arm; ++ i2c0 = &i2c0; ++ i2c1 = &i2c1; ++ i2c2 = &i2c2; ++ i2c3 = &i2c3; ++ i2c4 = &i2c4; ++ i2c5 = &i2c5; ++ i2c6 = &i2c6; ++ i2c10 = &i2c_rp1boot; ++ // Bit-bashed i2c_gpios start at 10 ++ spi0 = &spi0; ++ spi1 = &spi1; ++ spi2 = &spi2; ++ spi3 = &spi3; ++ spi4 = &spi4; ++ spi5 = &spi5; ++ spi10 = &spi10; ++ gpio0 = &gpio; ++ gpio1 = &gio; ++ gpio2 = &gio_aon; ++ gpio3 = &pinctrl; ++ gpio4 = &pinctrl_aon; ++ usb0 = &rp1_usb0; ++ usb1 = &rp1_usb1; ++ drm-dsi1 = &dsi0; ++ drm-dsi2 = &dsi1; ++ }; ++ ++ __overrides__ { ++ bdaddr = <&bluetooth>, "local-bd-address"; ++ button_debounce = <&pwr_key>, "debounce-interval:0"; ++ cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status"; ++ uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0; ++ i2c0 = <&i2c0>, "status"; ++ i2c1 = <&i2c1>, "status"; ++ i2c = <&i2c1>, "status"; ++ i2c_arm = <&i2c_arm>, "status"; ++ i2c_vc = <&i2c_vc>, "status"; ++ i2c_csi_dsi = <&i2c_csi_dsi>, "status"; ++ i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status"; ++ i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status"; ++ i2c0_baudrate = <&i2c0>, "clock-frequency:0"; ++ i2c1_baudrate = <&i2c1>, "clock-frequency:0"; ++ i2c_baudrate = <&i2c_arm>, "clock-frequency:0"; ++ i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0"; ++ i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0"; ++ krnbt = <&bluetooth>, "status"; ++ nvme = <&pciex1>, "status"; ++ pciex1 = <&pciex1>, "status"; ++ pciex1_gen = <&pciex1> , "max-link-speed:0"; ++ pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?"; ++ pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; ++ pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; ++ random = <&random>, "status"; ++ rtc = <&rpi_rtc>, "status"; ++ rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0"; ++ spi = <&spi0>, "status"; ++ suspend = <&pwr_key>, "linux,code:0=205"; ++ uart0 = <&uart0>, "status"; ++ wifiaddr = <&wifi>, "local-mac-address"; ++ ++ act_led_activelow = <&led_act>, "active-low?"; ++ act_led_trigger = <&led_act>, "linux,default-trigger"; ++ pwr_led_activelow = <&led_pwr>, "gpios:8"; ++ pwr_led_trigger = <&led_pwr>, "linux,default-trigger"; ++ eth_led0 = <&phy1>,"led-modes:0"; ++ eth_led1 = <&phy1>,"led-modes:4"; ++ drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0; ++ drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1; ++ drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi; ++ drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4; ++ drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0; ++ drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1; ++ drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi; ++ drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4; ++ drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0; ++ drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1; ++ drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi; ++ drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4; ++ ++ fan_temp0 = <&cpu_tepid>,"temperature:0"; ++ fan_temp1 = <&cpu_warm>,"temperature:0"; ++ fan_temp2 = <&cpu_hot>,"temperature:0"; ++ fan_temp3 = <&cpu_vhot>,"temperature:0"; ++ fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0"; ++ fan_temp1_hyst = <&cpu_warm>,"hysteresis:0"; ++ fan_temp2_hyst = <&cpu_hot>,"hysteresis:0"; ++ fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0"; ++ fan_temp0_speed = <&fan>, "cooling-levels:4"; ++ fan_temp1_speed = <&fan>, "cooling-levels:8"; ++ fan_temp2_speed = <&fan>, "cooling-levels:12"; ++ fan_temp3_speed = <&fan>, "cooling-levels:16"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi b/arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi +new file mode 100644 +index 000000000000..359a30d6ef5f +--- /dev/null ++++ b/arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi +@@ -0,0 +1,336 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include <dt-bindings/power/raspberrypi-power.h> ++ ++&soc { ++ firmware: firmware { ++ compatible = "raspberrypi,bcm2835-firmware", "simple-mfd"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ mboxes = <&mailbox>; ++ dma-ranges; ++ ++ firmware_clocks: clocks { ++ compatible = "raspberrypi,firmware-clocks"; ++ #clock-cells = <1>; ++ }; ++ ++ reset: reset { ++ compatible = "raspberrypi,firmware-reset"; ++ #reset-cells = <1>; ++ }; ++ ++ vcio: vcio { ++ compatible = "raspberrypi,vcio"; ++ }; ++ }; ++ ++ power: power { ++ compatible = "raspberrypi,bcm2835-power"; ++ firmware = <&firmware>; ++ #power-domain-cells = <1>; ++ }; ++ ++ fb: fb { ++ compatible = "brcm,bcm2708-fb"; ++ firmware = <&firmware>; ++ status = "okay"; ++ }; ++ ++ rpi_rtc: rpi_rtc { ++ compatible = "raspberrypi,rpi-rtc"; ++ firmware = <&firmware>; ++ status = "okay"; ++ trickle-charge-microvolt = <0>; ++ }; ++ ++ nvmem_otp: nvmem_otp { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <0 192>; ++ status = "okay"; ++ }; ++ ++ nvmem_cust: nvmem_cust { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <1 8>; ++ status = "okay"; ++ }; ++ ++ nvmem_mac: nvmem_mac { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <2 6>; ++ status = "okay"; ++ }; ++ ++ nvmem_priv: nvmem_priv { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <3 16>; ++ status = "okay"; ++ }; ++ ++ /* Define these notional regulators for use by overlays, etc. */ ++ vdd_3v3_reg: fixedregulator_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-always-on; ++ regulator-max-microvolt = <3300000>; ++ regulator-min-microvolt = <3300000>; ++ regulator-name = "3v3"; ++ }; ++ ++ vdd_5v0_reg: fixedregulator_5v0 { ++ compatible = "regulator-fixed"; ++ regulator-always-on; ++ regulator-max-microvolt = <5000000>; ++ regulator-min-microvolt = <5000000>; ++ regulator-name = "5v0"; ++ }; ++}; ++ ++/ { ++ __overrides__ { ++ arm_freq; ++ axiperf = <&axiperf>,"status"; ++ ++ nvmem_cust_rw = <&nvmem_cust>,"rw?"; ++ nvmem_priv_rw = <&nvmem_priv>,"rw?"; ++ nvmem_mac_rw = <&nvmem_mac>,"rw?"; ++ }; ++}; ++ ++pciex1: &pcie1 { }; ++pciex4: &pcie2 { }; ++ ++&dma32 { ++ /* The VPU firmware uses DMA channel 11 for VCHIQ */ ++ brcm,dma-channel-mask = <0x03f>; ++}; ++ ++&dma40 { ++ /* The VPU firmware DMA channel 11 for VCHIQ */ ++ brcm,dma-channel-mask = <0x07c0>; ++}; ++ ++&hdmi0 { ++ dmas = <&dma40 (10|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; ++}; ++ ++&hdmi1 { ++ dmas = <&dma40 (17|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; ++}; ++ ++&spi10 { ++ dmas = <&dma40 6>, <&dma40 7>; ++ dma-names = "tx", "rx"; ++}; ++ ++&usb { ++ power-domains = <&power RPI_POWER_DOMAIN_USB>; ++}; ++ ++&rmem { ++ /* ++ * RPi5'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"; ++ }; ++ /* ++ * RPi5 will copy the binary public key blob (if present) from the bootloader ++ * into memory for use by the OS. ++ */ ++ blpubkey: nvram@1 { ++ compatible = "raspberrypi,bootloader-public-key", "nvmem-rmem"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x0 0x0 0x0>; ++ no-map; ++ status = "disabled"; ++ }; ++}; ++ ++&rp1_adc { ++ status = "okay"; ++}; ++ ++/* Add some gpiomem nodes to make the devices accessible to userspace. ++ * /dev/gpiomem<n> should expose the registers for the interface with DT alias ++ * gpio<n>. ++ */ ++ ++&rp1 { ++ gpiomem@d0000 { ++ /* Export IO_BANKs, RIO_BANKs and PADS_BANKs to userspace */ ++ compatible = "raspberrypi,gpiomem"; ++ reg = <0xc0 0x400d0000 0x0 0x30000>; ++ chardev-name = "gpiomem0"; ++ }; ++}; ++ ++&soc { ++ gpiomem@7d508500 { ++ compatible = "raspberrypi,gpiomem"; ++ reg = <0x7d508500 0x40>; ++ chardev-name = "gpiomem1"; ++ }; ++ ++ gpiomem@7d517c00 { ++ compatible = "raspberrypi,gpiomem"; ++ reg = <0x7d517c00 0x40>; ++ chardev-name = "gpiomem2"; ++ }; ++ ++ gpiomem@7d504100 { ++ compatible = "raspberrypi,gpiomem"; ++ reg = <0x7d504100 0x20>; ++ chardev-name = "gpiomem3"; ++ }; ++ ++ gpiomem@7d510700 { ++ compatible = "raspberrypi,gpiomem"; ++ reg = <0x7d510700 0x20>; ++ chardev-name = "gpiomem4"; ++ }; ++ ++ sound: sound { ++ status = "disabled"; ++ }; ++}; ++ ++i2c0: &rp1_i2c0 { }; ++i2c1: &rp1_i2c1 { }; ++i2c2: &rp1_i2c2 { }; ++i2c3: &rp1_i2c3 { }; ++i2c4: &rp1_i2c4 { }; ++i2c5: &rp1_i2c5 { }; ++i2c6: &rp1_i2c6 { }; ++i2s: &rp1_i2s0 { }; ++i2s_clk_producer: &rp1_i2s0 { }; ++i2s_clk_consumer: &rp1_i2s1 { }; ++pwm0: &rp1_pwm0 { }; ++pwm1: &rp1_pwm1 { }; ++pwm: &pwm0 { }; ++spi0: &rp1_spi0 { }; ++spi1: &rp1_spi1 { }; ++spi2: &rp1_spi2 { }; ++spi3: &rp1_spi3 { }; ++spi4: &rp1_spi4 { }; ++spi5: &rp1_spi5 { }; ++ ++uart0_pins: &rp1_uart0_14_15 {}; ++uart0_ctsrts_pins: &rp1_uart0_ctsrts_16_17 {}; ++uart0: &rp1_uart0 { ++ pinctrl-0 = <&uart0_pins>; ++}; ++ ++uart1_pins: &rp1_uart1_0_1 {}; ++uart1_ctsrts_pins: &rp1_uart1_ctsrts_2_3 {}; ++uart1: &rp1_uart1 { }; ++ ++uart2_pins: &rp1_uart2_4_5 {}; ++uart2_ctsrts_pins: &rp1_uart2_ctsrts_6_7 {}; ++uart2: &rp1_uart2 { }; ++ ++uart3_pins: &rp1_uart3_8_9 {}; ++uart3_ctsrts_pins: &rp1_uart3_ctsrts_10_11 {}; ++uart3: &rp1_uart3 { }; ++ ++uart4_pins: &rp1_uart4_12_13 {}; ++uart4_ctsrts_pins: &rp1_uart4_ctsrts_14_15 {}; ++uart4: &rp1_uart4 { }; ++ ++i2c0_pins: &rp1_i2c0_0_1 {}; ++i2c_vc: &i2c0 { // This is pins 27,28 on the header (not MIPI) ++ pinctrl-0 = <&i2c0_pins>; ++ pinctrl-names = "default"; ++ clock-frequency = <100000>; ++}; ++ ++i2c1_pins: &rp1_i2c1_2_3 {}; ++i2c_arm: &i2c1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c1_pins>; ++ clock-frequency = <100000>; ++}; ++ ++i2c2_pins: &rp1_i2c2_4_5 {}; ++&i2c2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c2_pins>; ++}; ++ ++i2c3_pins: &rp1_i2c3_6_7 {}; ++&i2c3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c3_pins>; ++}; ++ ++&i2s_clk_producer { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rp1_i2s0_18_21>; ++}; ++ ++&i2s_clk_consumer { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rp1_i2s1_18_21>; ++}; ++ ++spi0_pins: &rp1_spi0_gpio9 {}; ++spi0_cs_pins: &rp1_spi0_cs_gpio7 {}; ++ ++&spi0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi0_pins &spi0_cs_pins>; ++ cs-gpios = <&gpio 8 1>, <&gpio 7 1>; ++ ++ spidev0: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ }; ++ ++ spidev1: spidev@1 { ++ compatible = "spidev"; ++ reg = <1>; /* CE1 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ }; ++}; ++ ++spi2_pins: &rp1_spi2_gpio1 {}; ++&spi2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi2_pins>; ++}; ++ ++spi3_pins: &rp1_spi3_gpio5 {}; ++&spi3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi3_pins>; ++}; ++ ++spi4_pins: &rp1_spi4_gpio9 {}; ++&spi4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi4_pins>; ++}; ++ ++spi5_pins: &rp1_spi5_gpio13 {}; ++&spi5 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi5_pins>; ++}; +diff --git a/arch/arm/boot/dts/broadcom/bcm2712.dtsi b/arch/arm/boot/dts/broadcom/bcm2712.dtsi +new file mode 100644 +index 000000000000..ee389a9cf89b +--- /dev/null ++++ b/arch/arm/boot/dts/broadcom/bcm2712.dtsi +@@ -0,0 +1,1304 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include <dt-bindings/interrupt-controller/arm-gic.h> ++#include <dt-bindings/soc/bcm2835-pm.h> ++#include <dt-bindings/phy/phy.h> ++ ++/ { ++ compatible = "brcm,bcm2712", "brcm,bcm2711"; ++ model = "BCM2712"; ++ ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ++ interrupt-parent = <&gicv2>; ++ ++ rmem: reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges; ++ ++ atf@0 { ++ reg = <0x0 0x0 0x80000>; ++ no-map; ++ }; ++ ++ cma: linux,cma { ++ compatible = "shared-dma-pool"; ++ size = <0x4000000>; /* 64MB */ ++ reusable; ++ linux,cma-default; ++ ++ /* ++ * arm64 reserves the CMA by default somewhere in ++ * ZONE_DMA32, that's not good enough for the BCM2711 ++ * as some devices can only address the lower 1G of ++ * memory (ZONE_DMA). ++ */ ++ alloc-ranges = <0x0 0x00000000 0x40000000>; ++ }; ++ }; ++ ++ thermal-zones { ++ cpu_thermal: cpu-thermal { ++ polling-delay-passive = <2000>; ++ polling-delay = <1000>; ++ coefficients = <(-550) 450000>; ++ thermal-sensors = <&thermal>; ++ ++ thermal_trips: trips { ++ cpu_crit: cpu-crit { ++ temperature = <110000>; ++ hysteresis = <0>; ++ type = "critical"; ++ }; ++ }; ++ ++ cooling_maps: cooling-maps { ++ }; ++ }; ++ }; ++ ++ clk_27MHz: clk-27M { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <27000000>; ++ clock-output-names = "27MHz-clock"; ++ }; ++ ++ clk_108MHz: clk-108M { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <108000000>; ++ clock-output-names = "108MHz-clock"; ++ }; ++ ++ hvs: hvs@107c580000 { ++ compatible = "brcm,bcm2712-hvs"; ++ reg = <0x10 0x7c580000 0x1a000>; ++ interrupt-parent = <&disp_intr>; ++ interrupts = <2>, <9>, <16>; ++ interrupt-names = "ch0-eof", "ch1-eof", "ch2-eof"; ++ //iommus = <&iommu4>; ++ status = "disabled"; ++ }; ++ ++ soc: soc { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ ranges = <0x7c000000 0x10 0x7c000000 0x04000000>; ++ /* Emulate a contiguous 30-bit address range for DMA */ ++ dma-ranges = <0xc0000000 0x00 0x00000000 0x40000000>, ++ <0x7c000000 0x10 0x7c000000 0x04000000>; ++ ++ system_timer: timer@7c003000 { ++ compatible = "brcm,bcm2835-system-timer"; ++ reg = <0x7c003000 0x1000>; ++ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; ++ clock-frequency = <1000000>; ++ }; ++ ++ firmwarekms: firmwarekms@7d503000 { ++ compatible = "raspberrypi,rpi-firmware-kms-2712"; ++ /* SUN_L2 interrupt reg */ ++ reg = <0x7d503000 0x18>; ++ interrupt-parent = <&cpu_l2_irq>; ++ interrupts = <19>; ++ brcm,firmware = <&firmware>; ++ status = "disabled"; ++ }; ++ ++ axiperf: axiperf { ++ compatible = "brcm,bcm2712-axiperf"; ++ reg = <0x7c012800 0x100>, ++ <0x7e000000 0x100>; ++ firmware = <&firmware>; ++ status = "disabled"; ++ }; ++ ++ mailbox: mailbox@7c013880 { ++ compatible = "brcm,bcm2835-mbox"; ++ reg = <0x7c013880 0x40>; ++ interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>; ++ #mbox-cells = <0>; ++ }; ++ ++ pixelvalve0: pixelvalve@7c410000 { ++ compatible = "brcm,bcm2712-pixelvalve0"; ++ reg = <0x7c410000 0x100>; ++ interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>; ++ status = "disabled"; ++ }; ++ ++ pixelvalve1: pixelvalve@7c411000 { ++ compatible = "brcm,bcm2712-pixelvalve1"; ++ reg = <0x7c411000 0x100>; ++ interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; ++ status = "disabled"; ++ }; ++ ++ mop: mop@7c500000 { ++ compatible = "brcm,bcm2712-mop"; ++ reg = <0x7c500000 0x28>; ++ interrupt-parent = <&disp_intr>; ++ interrupts = <1>; ++ status = "disabled"; ++ }; ++ ++ moplet: moplet@7c501000 { ++ compatible = "brcm,bcm2712-moplet"; ++ reg = <0x7c501000 0x20>; ++ interrupt-parent = <&disp_intr>; ++ interrupts = <0>; ++ status = "disabled"; ++ }; ++ ++ disp_intr: interrupt-controller@7c502000 { ++ compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc"; ++ reg = <0x7c502000 0x30>; ++ interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ status = "disabled"; ++ }; ++ ++ dvp: clock@7c700000 { ++ compatible = "brcm,brcm2711-dvp"; ++ reg = <0x7c700000 0x10>; ++ clocks = <&clk_108MHz>; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; ++ ++ /* ++ * This node is the provider for the enable-method for ++ * bringing up secondary cores. ++ */ ++ local_intc: local_intc@7cd00000 { ++ compatible = "brcm,bcm2836-l1-intc"; ++ reg = <0x7cd00000 0x100>; ++ }; ++ ++ uart0: serial@7d001000 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7d001000 0x200>; ++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_uart>, ++ <&clk_vpu>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ uart2: serial@7d001400 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7d001400 0x200>; ++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_uart>, ++ <&clk_vpu>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ uart5: serial@7d001a00 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7d001a00 0x200>; ++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_uart>, ++ <&clk_vpu>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ sdhost: mmc@7d002000 { ++ compatible = "brcm,bcm2835-sdhost"; ++ reg = <0x7d002000 0x100>; ++ //interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_vpu>; ++ status = "disabled"; ++ }; ++ ++ i2s: i2s@7d003000 { ++ compatible = "brcm,bcm2835-i2s"; ++ reg = <0x7d003000 0x24>; ++ //clocks = <&cprman BCM2835_CLOCK_PCM>; ++ status = "disabled"; ++ }; ++ ++ spi0: spi@7d004000 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004000 0x200>; ++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_vpu>; ++ num-cs = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi3: spi@7d004600 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004600 0x0200>; ++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi4: spi@7d004800 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004800 0x0200>; ++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi5: spi@7d004a00 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004a00 0x0200>; ++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi6: spi@7d004c00 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004c00 0x0200>; ++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c0: i2c@7d005000 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005000 0x20>; ++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c3: i2c@7d005600 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005600 0x20>; ++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c4: i2c@7d005800 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005800 0x20>; ++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c5: i2c@7d005a00 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005a00 0x20>; ++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c6: i2c@7d005c00 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005c00 0x20>; ++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c8: i2c@7d005e00 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005e00 0x20>; ++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ pwm0: pwm@7d00c000 { ++ compatible = "brcm,bcm2835-pwm"; ++ reg = <0x7d00c000 0x28>; ++ assigned-clock-rates = <50000000>; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ ++ pwm1: pwm@7d00c800 { ++ compatible = "brcm,bcm2835-pwm"; ++ reg = <0x7d00c800 0x28>; ++ assigned-clock-rates = <50000000>; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ ++ pm: watchdog@7d200000 { ++ compatible = "brcm,bcm2712-pm"; ++ reg = <0x7d200000 0x308>; ++ reg-names = "pm"; ++ #power-domain-cells = <1>; ++ #reset-cells = <1>; ++ //clocks = <&cprman BCM2835_CLOCK_V3D>, ++ // <&cprman BCM2835_CLOCK_PERI_IMAGE>, ++ // <&cprman BCM2835_CLOCK_H264>, ++ // <&cprman BCM2835_CLOCK_ISP>; ++ clock-names = "v3d", "peri_image", "h264", "isp"; ++ system-power-controller; ++ }; ++ ++ cprman: cprman@7d202000 { ++ compatible = "brcm,bcm2711-cprman"; ++ reg = <0x7d202000 0x2000>; ++ #clock-cells = <1>; ++ ++ /* CPRMAN derives almost everything from the ++ * platform's oscillator. However, the DSI ++ * pixel clocks come from the DSI analog PHY. ++ */ ++ clocks = <&clk_osc>; ++ status = "disabled"; ++ }; ++ ++ random: rng@7d208000 { ++ compatible = "brcm,bcm2711-rng200"; ++ reg = <0x7d208000 0x28>; ++ status = "okay"; ++ }; ++ ++ cpu_l2_irq: intc@7d503000 { ++ compatible = "brcm,l2-intc"; ++ reg = <0x7d503000 0x18>; ++ interrupts = <GIC_SPI 238 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ ++ pinctrl: pinctrl@7d504100 { ++ compatible = "brcm,bcm2712-pinctrl"; ++ reg = <0x7d504100 0x30>; ++ ++ uarta_24_pins: uarta_24_pins { ++ pin_rts { ++ function = "uart0"; ++ pins = "gpio24"; ++ bias-disable; ++ }; ++ pin_cts { ++ function = "uart0"; ++ pins = "gpio25"; ++ bias-pull-up; ++ }; ++ pin_txd { ++ function = "uart0"; ++ pins = "gpio26"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart0"; ++ pins = "gpio27"; ++ bias-pull-up; ++ }; ++ }; ++ ++ sdio2_30_pins: sdio2_30_pins { ++ pin_clk { ++ function = "sd2"; ++ pins = "gpio30"; ++ bias-disable; ++ }; ++ pin_cmd { ++ function = "sd2"; ++ pins = "gpio31"; ++ bias-pull-up; ++ }; ++ pins_dat { ++ function = "sd2"; ++ pins = "gpio32", "gpio33", "gpio34", "gpio35"; ++ bias-pull-up; ++ }; ++ }; ++ }; ++ ++ ddc0: i2c@7d508200 { ++ compatible = "brcm,brcmstb-i2c"; ++ reg = <0x7d508200 0x58>; ++ interrupt-parent = <&bsc_irq>; ++ interrupts = <1>; ++ clock-frequency = <97500>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ ddc1: i2c@7d508280 { ++ compatible = "brcm,brcmstb-i2c"; ++ reg = <0x7d508280 0x58>; ++ interrupt-parent = <&bsc_irq>; ++ interrupts = <2>; ++ clock-frequency = <97500>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ bscd: i2c@7d508300 { ++ compatible = "brcm,brcmstb-i2c"; ++ reg = <0x7d508300 0x58>; ++ interrupt-parent = <&bsc_irq>; ++ interrupts = <0>; ++ clock-frequency = <200000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ bsc_irq: intc@7d508380 { ++ compatible = "brcm,bcm7271-l2-intc"; ++ reg = <0x7d508380 0x10>; ++ interrupts = <GIC_SPI 242 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ ++ main_irq: intc@7d508400 { ++ compatible = "brcm,bcm7271-l2-intc"; ++ reg = <0x7d508400 0x10>; ++ interrupts = <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ ++ gio: gpio@7d508500 { ++ compatible = "brcm,brcmstb-gpio"; ++ reg = <0x7d508500 0x40>; ++ interrupt-parent = <&main_irq>; ++ interrupts = <0>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ brcm,gpio-bank-widths = <32 22>; ++ brcm,gpio-direct; ++ }; ++ ++ uarta: serial@7d50c000 { ++ compatible = "brcm,bcm7271-uart"; ++ reg = <0x7d50c000 0x20>; ++ reg-names = "uart"; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ interrupts = <GIC_SPI 276 IRQ_TYPE_LEVEL_HIGH>; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ uartb: serial@7d50d000 { ++ compatible = "brcm,bcm7271-uart"; ++ reg = <0x7d50d000 0x20>; ++ reg-names = "uart"; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ interrupts = <GIC_SPI 277 IRQ_TYPE_LEVEL_HIGH>; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ aon_intr: interrupt-controller@7d510600 { ++ compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc"; ++ reg = <0x7d510600 0x30>; ++ interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ status = "disabled"; ++ }; ++ ++ pinctrl_aon: pinctrl@7d510700 { ++ compatible = "brcm,bcm2712-aon-pinctrl"; ++ reg = <0x7d510700 0x20>; ++ ++ i2c3_m4_agpio0_pins: i2c3_m4_agpio0_pins { ++ function = "vc_i2c3"; ++ pins = "aon_gpio0", "aon_gpio1"; ++ bias-pull-up; ++ }; ++ ++ bsc_m1_agpio13_pins: bsc_m1_agpio13_pins { ++ function = "bsc_m1"; ++ pins = "aon_gpio13", "aon_gpio14"; ++ bias-pull-up; ++ }; ++ ++ bsc_pmu_sgpio4_pins: bsc_pmu_sgpio4_pins { ++ function = "avs_pmu_bsc"; ++ pins = "aon_sgpio4", "aon_sgpio5"; ++ }; ++ ++ bsc_m2_sgpio4_pins: bsc_m2_sgpio4_pins { ++ function = "bsc_m2"; ++ pins = "aon_sgpio4", "aon_sgpio5"; ++ }; ++ ++ pwm_aon_agpio1_pins: pwm_aon_agpio1_pins { ++ function = "aon_pwm"; ++ pins = "aon_gpio1", "aon_gpio2"; ++ }; ++ ++ pwm_aon_agpio4_pins: pwm_aon_agpio4_pins { ++ function = "vc_pwm0"; ++ pins = "aon_gpio4", "aon_gpio5"; ++ }; ++ ++ pwm_aon_agpio7_pins: pwm_aon_agpio7_pins { ++ function = "aon_pwm"; ++ pins = "aon_gpio7", "aon_gpio9"; ++ }; ++ }; ++ ++ intc@7d517000 { ++ compatible = "brcm,bcm7271-l2-intc"; ++ reg = <0x7d517000 0x10>; ++ interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ status = "disabled"; ++ }; ++ ++ bscc: i2c@7d517a00 { ++ compatible = "brcm,brcmstb-i2c"; ++ reg = <0x7d517a00 0x58>; ++ interrupt-parent = <&bsc_aon_irq>; ++ interrupts = <0>; ++ clock-frequency = <200000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ pwm_aon: pwm@7d517a80 { ++ compatible = "brcm,bcm7038-pwm"; ++ reg = <0x7d517a80 0x28>; ++ #pwm-cells = <3>; ++ clocks = <&clk_27MHz>; ++ }; ++ ++ main_aon_irq: intc@7d517ac0 { ++ compatible = "brcm,bcm7271-l2-intc"; ++ reg = <0x7d517ac0 0x10>; ++ interrupts = <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ ++ bsc_aon_irq: intc@7d517b00 { ++ compatible = "brcm,bcm7271-l2-intc"; ++ reg = <0x7d517b00 0x10>; ++ interrupts = <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ ++ gio_aon: gpio@7d517c00 { ++ compatible = "brcm,brcmstb-gpio"; ++ reg = <0x7d517c00 0x40>; ++ interrupt-parent = <&main_aon_irq>; ++ interrupts = <0>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ brcm,gpio-bank-widths = <17 6>; ++ brcm,gpio-direct; ++ }; ++ ++ avs_monitor: avs-monitor@7d542000 { ++ compatible = "brcm,bcm2711-avs-monitor", ++ "syscon", "simple-mfd"; ++ reg = <0x7d542000 0xf00>; ++ status = "okay"; ++ ++ thermal: thermal { ++ compatible = "brcm,bcm2711-thermal"; ++ #thermal-sensor-cells = <0>; ++ }; ++ }; ++ ++ bsc_pmu: i2c@7d544000 { ++ compatible = "brcm,brcmstb-i2c"; ++ reg = <0x7d544000 0x58>; ++ interrupt-parent = <&bsc_aon_irq>; ++ interrupts = <1>; ++ clock-frequency = <200000>; ++ status = "disabled"; ++ }; ++ ++ hdmi0: hdmi@7ef00700 { ++ compatible = "brcm,bcm2712-hdmi0"; ++ reg = <0x7c701400 0x300>, ++ <0x7c701000 0x200>, ++ <0x7c701d00 0x300>, ++ <0x7c702000 0x80>, ++ <0x7c703800 0x200>, ++ <0x7c704000 0x800>, ++ <0x7c700100 0x80>, ++ <0x7d510800 0x100>, ++ <0x7c720000 0x100>; ++ reg-names = "hdmi", ++ "dvp", ++ "phy", ++ "rm", ++ "packet", ++ "metadata", ++ "csc", ++ "cec", ++ "hd"; ++ resets = <&dvp 1>; ++ interrupt-parent = <&aon_intr>; ++ interrupts = <1>, <2>, <3>, ++ <7>, <8>; ++ interrupt-names = "cec-tx", "cec-rx", "cec-low", ++ "hpd-connected", "hpd-removed"; ++ ddc = <&ddc0>; ++ dmas = <&dma32 10>; ++ dma-names = "audio-rx"; ++ status = "disabled"; ++ }; ++ ++ hdmi1: hdmi@7ef05700 { ++ compatible = "brcm,bcm2712-hdmi1"; ++ reg = <0x7c706400 0x300>, ++ <0x7c706000 0x200>, ++ <0x7c706d00 0x300>, ++ <0x7c707000 0x80>, ++ <0x7c708800 0x200>, ++ <0x7c709000 0x800>, ++ <0x7c700180 0x80>, ++ <0x7d511000 0x100>, ++ <0x7c720000 0x100>; ++ reg-names = "hdmi", ++ "dvp", ++ "phy", ++ "rm", ++ "packet", ++ "metadata", ++ "csc", ++ "cec", ++ "hd"; ++ ddc = <&ddc1>; ++ resets = <&dvp 2>; ++ interrupt-parent = <&aon_intr>; ++ interrupts = <11>, <12>, <13>, ++ <14>, <15>; ++ interrupt-names = "cec-tx", "cec-rx", "cec-low", ++ "hpd-connected", "hpd-removed"; ++ dmas = <&dma32 17>; ++ dma-names = "audio-rx"; ++ status = "disabled"; ++ }; ++ }; ++ ++ arm-pmu { ++ compatible = "arm,cortex-a76-pmu"; ++ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; ++ }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | ++ IRQ_TYPE_LEVEL_LOW)>, ++ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | ++ IRQ_TYPE_LEVEL_LOW)>, ++ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | ++ IRQ_TYPE_LEVEL_LOW)>, ++ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | ++ IRQ_TYPE_LEVEL_LOW)>; ++ /* This only applies to the ARMv7 stub */ ++ arm,cpu-registers-not-fw-configured; ++ }; ++ ++ cpus: cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit ++ ++ /* Source for d/i cache-line-size, cache-sets, cache-size ++ * https://developer.arm.com/documentation/100798/0401 ++ * /L1-memory-system/About-the-L1-memory-system?lang=en ++ */ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a76"; ++ reg = <0x000>; ++ enable-method = "psci"; ++ d-cache-size = <0x10000>; ++ d-cache-line-size = <64>; ++ d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set ++ i-cache-size = <0x10000>; ++ i-cache-line-size = <64>; ++ i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set ++ next-level-cache = <&l2_cache_l0>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a76"; ++ reg = <0x100>; ++ enable-method = "psci"; ++ d-cache-size = <0x10000>; ++ d-cache-line-size = <64>; ++ d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set ++ i-cache-size = <0x10000>; ++ i-cache-line-size = <64>; ++ i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set ++ next-level-cache = <&l2_cache_l1>; ++ }; ++ ++ cpu2: cpu@2 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a76"; ++ reg = <0x200>; ++ enable-method = "psci"; ++ d-cache-size = <0x10000>; ++ d-cache-line-size = <64>; ++ d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set ++ i-cache-size = <0x10000>; ++ i-cache-line-size = <64>; ++ i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set ++ next-level-cache = <&l2_cache_l2>; ++ }; ++ ++ cpu3: cpu@3 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a76"; ++ reg = <0x300>; ++ enable-method = "psci"; ++ d-cache-size = <0x10000>; ++ d-cache-line-size = <64>; ++ d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set ++ i-cache-size = <0x10000>; ++ i-cache-line-size = <64>; ++ i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set ++ next-level-cache = <&l2_cache_l3>; ++ }; ++ ++ /* Source for cache-line-size and cache-sets: ++ * https://developer.arm.com/documentation/100798/0401 ++ * /L2-memory-system/About-the-L2-memory-system?lang=en ++ * and for cache-size: ++ * https://www.raspberrypi.com/documentation/computers ++ * /processors.html#bcm2712 ++ */ ++ l2_cache_l0: l2-cache-l0 { ++ compatible = "cache"; ++ cache-size = <0x80000>; ++ cache-line-size = <128>; ++ cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set ++ cache-level = <2>; ++ cache-unified; ++ next-level-cache = <&l3_cache>; ++ }; ++ ++ l2_cache_l1: l2-cache-l1 { ++ compatible = "cache"; ++ cache-size = <0x80000>; ++ cache-line-size = <128>; ++ cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set ++ cache-level = <2>; ++ cache-unified; ++ next-level-cache = <&l3_cache>; ++ }; ++ ++ l2_cache_l2: l2-cache-l2 { ++ compatible = "cache"; ++ cache-size = <0x80000>; ++ cache-line-size = <128>; ++ cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set ++ cache-level = <2>; ++ cache-unified; ++ next-level-cache = <&l3_cache>; ++ }; ++ ++ l2_cache_l3: l2-cache-l3 { ++ compatible = "cache"; ++ cache-size = <0x80000>; ++ cache-line-size = <128>; ++ cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set ++ cache-level = <2>; ++ cache-unified; ++ next-level-cache = <&l3_cache>; ++ }; ++ ++ /* Source for cache-line-size and cache-sets: ++ * https://developer.arm.com/documentation/100453/0401/L3-cache?lang=en ++ * Source for cache-size: ++ * https://www.raspberrypi.com/documentation/computers/processors.html#bcm2712 ++ */ ++ l3_cache: l3-cache { ++ compatible = "cache"; ++ cache-size = <0x200000>; ++ cache-line-size = <64>; ++ cache-sets = <2048>; // 2MiB(size)/64(line-size)=32768ways/16-way set ++ cache-level = <3>; ++ }; ++ }; ++ ++ psci { ++ method = "smc"; ++ compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci"; ++ cpu_on = <0xc4000003>; ++ cpu_suspend = <0xc4000001>; ++ cpu_off = <0x84000002>; ++ }; ++ ++ axi: axi { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ ranges = <0x00 0x00000000 0x00 0x00000000 0x10 0x00000000>, ++ <0x10 0x00000000 0x10 0x00000000 0x01 0x00000000>, ++ <0x14 0x00000000 0x14 0x00000000 0x04 0x00000000>, ++ <0x18 0x00000000 0x18 0x00000000 0x04 0x00000000>, ++ <0x1c 0x00000000 0x1c 0x00000000 0x04 0x00000000>; ++ ++ dma-ranges = <0x00 0x00000000 0x00 0x00000000 0x10 0x00000000>, ++ <0x10 0x00000000 0x10 0x00000000 0x01 0x00000000>, ++ <0x14 0x00000000 0x14 0x00000000 0x04 0x00000000>, ++ <0x18 0x00000000 0x18 0x00000000 0x04 0x00000000>, ++ <0x1c 0x00000000 0x1c 0x00000000 0x04 0x00000000>; ++ ++ vc4: gpu { ++ compatible = "brcm,bcm2712-vc6"; ++ }; ++ ++ iommu2: iommu@5100 { ++ /* IOMMU2 for PISP-BE, HEVC; and (unused) H264 accelerators */ ++ compatible = "brcm,bcm2712-iommu"; ++ reg = <0x10 0x5100 0x0 0x80>; ++ cache = <&iommuc>; ++ #iommu-cells = <0>; ++ }; ++ ++ iommu4: iommu@5200 { ++ /* IOMMU4 for HVS, MPL/TXP; and (unused) Unicam, PISP-FE, MiniBVN */ ++ compatible = "brcm,bcm2712-iommu"; ++ reg = <0x10 0x5200 0x0 0x80>; ++ cache = <&iommuc>; ++ #iommu-cells = <0>; ++ #interconnect-cells = <0>; ++ }; ++ ++ iommu5: iommu@5280 { ++ /* IOMMU5 for PCIe2 (RP1); and (unused) BSTM */ ++ compatible = "brcm,bcm2712-iommu"; ++ reg = <0x10 0x5280 0x0 0x80>; ++ cache = <&iommuc>; ++ #iommu-cells = <0>; ++ dma-iova-offset = <0x10 0x00000000>; // HACK for RP1 masters over PCIe ++ }; ++ ++ iommuc: iommuc@5b00 { ++ compatible = "brcm,bcm2712-iommuc"; ++ reg = <0x10 0x5b00 0x0 0x80>; ++ }; ++ ++ dma32: dma@10000 { ++ compatible = "brcm,bcm2712-dma"; ++ reg = <0x10 0x00010000 0 0x600>; ++ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "dma0", ++ "dma1", ++ "dma2", ++ "dma3", ++ "dma4", ++ "dma5"; ++ #dma-cells = <1>; ++ brcm,dma-channel-mask = <0x0035>; ++ }; ++ ++ dma40: dma@10600 { ++ compatible = "brcm,bcm2712-dma"; ++ reg = <0x10 0x00010600 0 0x600>; ++ interrupts = ++ <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>, /* dma4 6 */ ++ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>, /* dma4 7 */ ++ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>, /* dma4 8 */ ++ <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 9 */ ++ <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, /* dma4 10 */ ++ <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>; /* dma4 11 */ ++ interrupt-names = "dma6", ++ "dma7", ++ "dma8", ++ "dma9", ++ "dma10", ++ "dma11"; ++ #dma-cells = <1>; ++ brcm,dma-channel-mask = <0x0fc0>; ++ }; ++ ++ // Single-lane Gen3 PCIe ++ // Outbound window at 0x14_000000-0x17_ffffff ++ pcie0: pcie@100000 { ++ compatible = "brcm,bcm2712-pcie"; ++ reg = <0x10 0x00100000 0x0 0x9310>; ++ device_type = "pci"; ++ max-link-speed = <2>; ++ #address-cells = <3>; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ /* ++ * Unused interrupts: ++ * 208: AER ++ * 215: NMI ++ * 216: PME ++ */ ++ interrupt-parent = <&gicv2>; ++ interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "pcie", "msi"; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 209 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 2 &gicv2 GIC_SPI 210 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 3 &gicv2 GIC_SPI 211 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 4 &gicv2 GIC_SPI 212 ++ IRQ_TYPE_LEVEL_HIGH>; ++ resets = <&bcm_reset 5>, <&bcm_reset 42>, <&pcie_rescal>; ++ reset-names = "swinit", "bridge", "rescal"; ++ msi-controller; ++ msi-parent = <&pcie0>; ++ ++ ranges = <0x02000000 0x00 0x00000000 ++ 0x17 0x00000000 ++ 0x0 0xfffffffc>, ++ <0x43000000 0x04 0x00000000 ++ 0x14 0x00000000 ++ 0x3 0x00000000>; ++ ++ dma-ranges = <0x43000000 0x10 0x00000000 ++ 0x00 0x00000000 ++ 0x10 0x00000000>; ++ ++ status = "disabled"; ++ }; ++ ++ // Single-lane Gen3 PCIe ++ // Outbound window at 0x18_000000-0x1b_ffffff ++ pcie1: pcie@110000 { ++ compatible = "brcm,bcm2712-pcie"; ++ reg = <0x10 0x00110000 0x0 0x9310>; ++ device_type = "pci"; ++ max-link-speed = <2>; ++ #address-cells = <3>; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ /* ++ * Unused interrupts: ++ * 218: AER ++ * 225: NMI ++ * 226: PME ++ */ ++ interrupt-parent = <&gicv2>; ++ interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "pcie", "msi"; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 219 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 2 &gicv2 GIC_SPI 220 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 3 &gicv2 GIC_SPI 221 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 4 &gicv2 GIC_SPI 222 ++ IRQ_TYPE_LEVEL_HIGH>; ++ resets = <&bcm_reset 7>, <&bcm_reset 43>, <&pcie_rescal>; ++ reset-names = "swinit", "bridge", "rescal"; ++ msi-controller; ++ msi-parent = <&mip1>; ++ ++ ranges = <0x02000000 0x00 0x00000000 ++ 0x1b 0x00000000 ++ 0x00 0xfffffffc>, ++ <0x43000000 0x04 0x00000000 ++ 0x18 0x00000000 ++ 0x03 0x00000000>; ++ ++ dma-ranges = <0x03000000 0x10 0x00000000 ++ 0x00 0x00000000 ++ 0x10 0x00000000>; ++ ++ brcm,enable-l1ss; ++ status = "disabled"; ++ }; ++ ++ pcie_rescal: reset-controller@119500 { ++ compatible = "brcm,bcm7216-pcie-sata-rescal"; ++ reg = <0x10 0x00119500 0x0 0x10>; ++ #reset-cells = <0>; ++ }; ++ ++ // Quad-lane Gen3 PCIe ++ // Outbound window at 0x1c_000000-0x1f_ffffff ++ pcie2: pcie@120000 { ++ compatible = "brcm,bcm2712-pcie"; ++ reg = <0x10 0x00120000 0x0 0x9310>; ++ device_type = "pci"; ++ max-link-speed = <2>; ++ #address-cells = <3>; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ /* ++ * Unused interrupts: ++ * 228: AER ++ * 235: NMI ++ * 236: PME ++ */ ++ interrupt-parent = <&gicv2>; ++ interrupts = <GIC_SPI 233 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 234 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "pcie", "msi"; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 229 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 2 &gicv2 GIC_SPI 230 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 3 &gicv2 GIC_SPI 231 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 4 &gicv2 GIC_SPI 232 ++ IRQ_TYPE_LEVEL_HIGH>; ++ resets = <&bcm_reset 32>, <&bcm_reset 44>, <&pcie_rescal>; ++ reset-names = "swinit", "bridge", "rescal"; ++ msi-controller; ++ msi-parent = <&mip0>; ++ ++ // ~4GB, 32-bit, not-prefetchable at PCIe 00_00000000 ++ ranges = <0x02000000 0x00 0x00000000 ++ 0x1f 0x00000000 ++ 0x0 0xfffffffc>, ++ // 12GB, 64-bit, prefetchable at PCIe 04_00000000 ++ <0x43000000 0x04 0x00000000 ++ 0x1c 0x00000000 ++ 0x03 0x00000000>; ++ ++ // 64GB system RAM space at PCIe 10_00000000 ++ dma-ranges = <0x02000000 0x00 0x00000000 ++ 0x1f 0x00000000 ++ 0x00 0x00400000>, ++ <0x43000000 0x10 0x00000000 ++ 0x00 0x00000000 ++ 0x10 0x00000000>; ++ ++ brcm,enable-l1ss; ++ status = "disabled"; ++ }; ++ ++ mip0: msi-controller@130000 { ++ compatible = "brcm,bcm2712-mip-intc"; ++ reg = <0x10 0x00130000 0x0 0xc0>; ++ msi-controller; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ brcm,msi-base-spi = <128>; ++ brcm,msi-num-spis = <64>; ++ brcm,msi-offset = <0>; ++ brcm,msi-pci-addr = <0xff 0xfffff000>; ++ }; ++ ++ mip1: msi-controller@131000 { ++ compatible = "brcm,bcm2712-mip-intc"; ++ reg = <0x10 0x00131000 0x0 0xc0>; ++ msi-controller; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ brcm,msi-base-spi = <247>; ++ /* Actually 20 total, but the others are ++ * both sparse and non-consecutive */ ++ brcm,msi-num-spis = <8>; ++ brcm,msi-offset = <8>; ++ brcm,msi-pci-addr = <0xff 0xffffe000>; ++ }; ++ ++ syscon_piarbctl: syscon@400018 { ++ compatible = "brcm,syscon-piarbctl", "syscon", "simple-mfd"; ++ reg = <0x10 0x00400018 0x0 0x18>; ++ }; ++ ++ usb: usb@480000 { ++ compatible = "brcm,bcm2835-usb"; ++ reg = <0x10 0x00480000 0x0 0x10000>; ++ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk_usb>; ++ clock-names = "otg"; ++ phys = <&usbphy>; ++ phy-names = "usb2-phy"; ++ status = "disabled"; ++ }; ++ ++ rpivid: codec@800000 { ++ compatible = "raspberrypi,rpivid-vid-decoder"; ++ reg = <0x10 0x00800000 0x0 0x10000>, /* HEVC */ ++ <0x10 0x00840000 0x0 0x1000>; /* INTC */ ++ reg-names = "hevc", ++ "intc"; ++ ++ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; ++ ++ clocks = <&firmware_clocks 11>; ++ clock-names = "hevc"; ++ iommus = <&iommu2>; ++ status = "disabled"; ++ }; ++ ++ sdio1: mmc@fff000 { ++ compatible = "brcm,bcm2712-sdhci"; ++ reg = <0x10 0x00fff000 0x0 0x260>, ++ <0x10 0x00fff400 0x0 0x200>, ++ <0x10 0x015040b0 0x0 0x4>, // Bus isolation control ++ <0x10 0x015200f0 0x0 0x24>; // LCPLL control misc0-8 ++ reg-names = "host", "cfg", "busisol", "lcpll"; ++ interrupts = <GIC_SPI 273 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_emmc2>; ++ sdhci-caps-mask = <0x0000C000 0x0>; ++ sdhci-caps = <0x0 0x0>; ++ mmc-ddr-3_3v; ++ }; ++ ++ sdio2: mmc@1100000 { ++ compatible = "brcm,bcm2712-sdhci"; ++ reg = <0x10 0x01100000 0x0 0x260>, ++ <0x10 0x01100400 0x0 0x200>; ++ reg-names = "host", "cfg"; ++ interrupts = <GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_emmc2>; ++ sdhci-caps-mask = <0x0000C000 0x0>; ++ sdhci-caps = <0x0 0x0>; ++ supports-cqe; ++ mmc-ddr-3_3v; ++ status = "disabled"; ++ }; ++ ++ bcm_reset: reset-controller@1504318 { ++ compatible = "brcm,brcmstb-reset"; ++ reg = <0x10 0x01504318 0x0 0x30>; ++ #reset-cells = <1>; ++ }; ++ ++ v3d: v3d@2000000 { ++ compatible = "brcm,2712-v3d"; ++ reg = <0x10 0x02000000 0x0 0x4000>, ++ <0x10 0x02008000 0x0 0x6000>; ++ reg-names = "hub", "core0"; ++ ++ power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>; ++ resets = <&pm BCM2835_RESET_V3D>; ++ clocks = <&firmware_clocks 5>; ++ clocks-names = "v3d"; ++ interrupts = <GIC_SPI 250 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 249 IRQ_TYPE_LEVEL_HIGH>; ++ status = "disabled"; ++ }; ++ ++ gicv2: interrupt-controller@7fff9000 { ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ compatible = "arm,gic-400"; ++ reg = <0x10 0x7fff9000 0x0 0x1000>, ++ <0x10 0x7fffa000 0x0 0x2000>, ++ <0x10 0x7fffc000 0x0 0x2000>, ++ <0x10 0x7fffe000 0x0 0x2000>; ++ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | ++ IRQ_TYPE_LEVEL_HIGH)>; ++ }; ++ ++ pisp_be: pisp_be@880000 { ++ compatible = "raspberrypi,pispbe"; ++ reg = <0x10 0x00880000 0x0 0x4000>; ++ interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&firmware_clocks 7>; ++ clocks-names = "isp_be"; ++ status = "okay"; ++ iommus = <&iommu2>; ++ }; ++ }; ++ ++ clocks { ++ /* The oscillator is the root of the clock tree. */ ++ clk_osc: clk-osc { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "osc"; ++ clock-frequency = <54000000>; ++ }; ++ ++ clk_usb: clk-usb { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "otg"; ++ clock-frequency = <480000000>; ++ }; ++ ++ clk_vpu: clk_vpu { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <750000000>; ++ clock-output-names = "vpu-clock"; ++ }; ++ ++ clk_uart: clk_uart { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <9216000>; ++ clock-output-names = "uart-clock"; ++ }; ++ ++ clk_emmc2: clk_emmc2 { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <200000000>; ++ clock-output-names = "emmc2-clock"; ++ }; ++ }; ++ ++ usbphy: phy { ++ compatible = "usb-nop-xceiv"; ++ #phy-cells = <0>; ++ }; ++}; +diff --git a/arch/arm/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts b/arch/arm/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts +new file mode 100644 +index 000000000000..32aab40524b3 +--- /dev/null ++++ b/arch/arm/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts +@@ -0,0 +1,107 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include "bcm2712-rpi-5-b.dts" ++ ++&gio { ++ brcm,gpio-bank-widths = <32 4>; ++ ++ gpio-line-names = ++ "", // GPIO_000 ++ "2712_BOOT_CS_N", // GPIO_001 ++ "2712_BOOT_MISO", // GPIO_002 ++ "2712_BOOT_MOSI", // GPIO_003 ++ "2712_BOOT_SCLK", // GPIO_004 ++ "", // GPIO_005 ++ "", // GPIO_006 ++ "", // GPIO_007 ++ "", // GPIO_008 ++ "", // GPIO_009 ++ "", // GPIO_010 ++ "", // GPIO_011 ++ "", // GPIO_012 ++ "", // GPIO_013 ++ "PCIE_SDA", // GPIO_014 ++ "PCIE_SCL", // GPIO_015 ++ "", // GPIO_016 ++ "", // GPIO_017 ++ "-", // GPIO_018 ++ "-", // GPIO_019 ++ "PWR_GPIO", // GPIO_020 ++ "2712_G21_FS", // GPIO_021 ++ "-", // GPIO_022 ++ "-", // GPIO_023 ++ "BT_RTS", // GPIO_024 ++ "BT_CTS", // GPIO_025 ++ "BT_TXD", // GPIO_026 ++ "BT_RXD", // GPIO_027 ++ "WL_ON", // GPIO_028 ++ "BT_ON", // GPIO_029 ++ "WIFI_SDIO_CLK", // GPIO_030 ++ "WIFI_SDIO_CMD", // GPIO_031 ++ "WIFI_SDIO_D0", // GPIO_032 ++ "WIFI_SDIO_D1", // GPIO_033 ++ "WIFI_SDIO_D2", // GPIO_034 ++ "WIFI_SDIO_D3"; // GPIO_035 ++}; ++ ++&gio_aon { ++ brcm,gpio-bank-widths = <15 6>; ++ ++ gpio-line-names = ++ "RP1_SDA", // AON_GPIO_00 ++ "RP1_SCL", // AON_GPIO_01 ++ "RP1_RUN", // AON_GPIO_02 ++ "SD_IOVDD_SEL", // AON_GPIO_03 ++ "SD_PWR_ON", // AON_GPIO_04 ++ "SD_CDET_N", // AON_GPIO_05 ++ "SD_FLG_N", // AON_GPIO_06 ++ "", // AON_GPIO_07 ++ "2712_WAKE", // AON_GPIO_08 ++ "2712_STAT_LED", // AON_GPIO_09 ++ "", // AON_GPIO_10 ++ "", // AON_GPIO_11 ++ "PMIC_INT", // AON_GPIO_12 ++ "UART_TX_FS", // AON_GPIO_13 ++ "UART_RX_FS", // AON_GPIO_14 ++ "", // AON_GPIO_15 ++ "", // AON_GPIO_16 ++ ++ // Pad bank0 out to 32 entries ++ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ++ ++ "HDMI0_SCL", // AON_SGPIO_00 ++ "HDMI0_SDA", // AON_SGPIO_01 ++ "HDMI1_SCL", // AON_SGPIO_02 ++ "HDMI1_SDA", // AON_SGPIO_03 ++ "PMIC_SCL", // AON_SGPIO_04 ++ "PMIC_SDA"; // AON_SGPIO_05 ++}; ++ ++&pinctrl { ++ compatible = "brcm,bcm2712d0-pinctrl"; ++ reg = <0x7d504100 0x20>; ++}; ++ ++&pinctrl_aon { ++ compatible = "brcm,bcm2712d0-aon-pinctrl"; ++ reg = <0x7d510700 0x1c>; ++}; ++ ++&vc4 { ++ compatible = "brcm,bcm2712d0-vc6"; ++}; ++ ++&uart10 { ++ interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; ++}; ++ ++&spi10 { ++ dmas = <&dma40 3>, <&dma40 4>; ++}; ++ ++&hdmi0 { ++ dmas = <&dma40 (12|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; ++}; ++ ++&hdmi1 { ++ dmas = <&dma40 (13|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; ++}; +diff --git a/arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi b/arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi +new file mode 100644 +index 000000000000..400efdc5f03c +--- /dev/null ++++ b/arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++&uart0 { ++ bt: bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ max-speed = <3000000>; ++ shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>; ++ local-bd-address = 00 00 00 00 00 00 ; ++ fallback-bd-address; // Don't override a valid address ++ status = "okay"; ++ }; ++}; ++ ++&uart1 { ++ minibt: bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ max-speed = <230400>; ++ shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>; ++ local-bd-address = 00 00 00 00 00 00 ; ++ fallback-bd-address; // Don't override a valid address ++ status = "disabled"; ++ }; ++}; ++ ++/ { ++ aliases { ++ bluetooth = &bt; ++ }; ++ ++ __overrides__ { ++ bdaddr = <&bt>,"local-bd-address", ++ <&bt>,"fallback-bd-address?=0", ++ <&minibt>,"local-bd-address", ++ <&minibt>,"fallback-bd-address?=0"; ++ krnbt = <&bt>,"status"; ++ krnbt_baudrate = <&bt>,"max-speed:0", <&minibt>,"max-speed:0"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/broadcom/bcm283x-rpi-csi0-2lane.dtsi b/arch/arm/boot/dts/broadcom/bcm283x-rpi-csi0-2lane.dtsi +new file mode 100644 +index 000000000000..6e4ce8622b47 +--- /dev/null ++++ b/arch/arm/boot/dts/broadcom/bcm283x-rpi-csi0-2lane.dtsi +@@ -0,0 +1,4 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++&csi0 { ++ brcm,num-data-lanes = <2>; ++}; +diff --git a/arch/arm/boot/dts/broadcom/bcm283x-rpi-csi1-2lane.dtsi b/arch/arm/boot/dts/broadcom/bcm283x-rpi-csi1-2lane.dtsi +new file mode 100644 +index 000000000000..6938f4daacdc +--- /dev/null ++++ b/arch/arm/boot/dts/broadcom/bcm283x-rpi-csi1-2lane.dtsi +@@ -0,0 +1,4 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++&csi1 { ++ brcm,num-data-lanes = <2>; ++}; +diff --git a/arch/arm/boot/dts/broadcom/bcm283x-rpi-csi1-4lane.dtsi b/arch/arm/boot/dts/broadcom/bcm283x-rpi-csi1-4lane.dtsi +new file mode 100644 +index 000000000000..b37037437bee +--- /dev/null ++++ b/arch/arm/boot/dts/broadcom/bcm283x-rpi-csi1-4lane.dtsi +@@ -0,0 +1,4 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++&csi1 { ++ brcm,num-data-lanes = <4>; ++}; +diff --git a/arch/arm/boot/dts/broadcom/bcm283x-rpi-i2c0mux_0_28.dtsi b/arch/arm/boot/dts/broadcom/bcm283x-rpi-i2c0mux_0_28.dtsi +new file mode 100644 +index 000000000000..38f0074bce3f +--- /dev/null ++++ b/arch/arm/boot/dts/broadcom/bcm283x-rpi-i2c0mux_0_28.dtsi +@@ -0,0 +1,4 @@ ++&i2c0mux { ++ pinctrl-0 = <&i2c0_gpio0>; ++ pinctrl-1 = <&i2c0_gpio28>; ++}; +diff --git a/arch/arm/boot/dts/broadcom/bcm283x-rpi-i2c0mux_0_44.dtsi b/arch/arm/boot/dts/broadcom/bcm283x-rpi-i2c0mux_0_44.dtsi +new file mode 100644 +index 000000000000..119946d878db +--- /dev/null ++++ b/arch/arm/boot/dts/broadcom/bcm283x-rpi-i2c0mux_0_44.dtsi +@@ -0,0 +1,4 @@ ++&i2c0mux { ++ pinctrl-0 = <&i2c0_gpio0>; ++ pinctrl-1 = <&i2c0_gpio44>; ++}; +diff --git a/arch/arm/boot/dts/broadcom/bcm283x.dtsi b/arch/arm/boot/dts/broadcom/bcm283x.dtsi +index 2ca8a2505a4d..8ac38cdb9ffc 100644 +--- a/arch/arm/boot/dts/broadcom/bcm283x.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm283x.dtsi +@@ -415,7 +415,7 @@ pwm: pwm@7e20c000 { + reg = <0x7e20c000 0x28>; + clocks = <&clocks BCM2835_CLOCK_PWM>; + assigned-clocks = <&clocks BCM2835_CLOCK_PWM>; +- assigned-clock-rates = <10000000>; ++ assigned-clock-rates = <50000000>; + #pwm-cells = <3>; + status = "disabled"; + }; +diff --git a/arch/arm/boot/dts/broadcom/rp1.dtsi b/arch/arm/boot/dts/broadcom/rp1.dtsi +new file mode 100644 +index 000000000000..551a02a955a1 +--- /dev/null ++++ b/arch/arm/boot/dts/broadcom/rp1.dtsi +@@ -0,0 +1,1306 @@ ++#include <dt-bindings/clock/rp1.h> ++#include <dt-bindings/interrupt-controller/irq.h> ++#include <dt-bindings/mfd/rp1.h> ++ ++&rp1_target { ++ rp1: rp1 { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ #interrupt-cells = <2>; ++ interrupt-controller; ++ interrupt-parent = <&rp1>; ++ ++ // ranges and dma-ranges must be provided by the includer ++ ++ rp1_clocks: clocks@18000 { ++ compatible = "raspberrypi,rp1-clocks"; ++ #clock-cells = <1>; ++ reg = <0xc0 0x40018000 0x0 0x10038>; ++ clocks = <&clk_xosc>; ++ ++ assigned-clocks = <&rp1_clocks RP1_PLL_SYS_CORE>, ++ <&rp1_clocks RP1_PLL_AUDIO_CORE>, ++ // RP1_PLL_VIDEO_CORE and dividers are now managed by VEC,DPI drivers ++ <&rp1_clocks RP1_PLL_SYS>, ++ <&rp1_clocks RP1_PLL_SYS_SEC>, ++ <&rp1_clocks RP1_PLL_AUDIO>, ++ <&rp1_clocks RP1_PLL_AUDIO_SEC>, ++ <&rp1_clocks RP1_CLK_SYS>, ++ <&rp1_clocks RP1_PLL_SYS_PRI_PH>, ++ // RP1_CLK_SLOW_SYS is used for the frequency counter (FC0) ++ <&rp1_clocks RP1_CLK_SLOW_SYS>, ++ <&rp1_clocks RP1_CLK_SDIO_TIMER>, ++ <&rp1_clocks RP1_CLK_SDIO_ALT_SRC>, ++ <&rp1_clocks RP1_CLK_ETH_TSU>; ++ ++ assigned-clock-rates = <1000000000>, // RP1_PLL_SYS_CORE ++ <1536000000>, // RP1_PLL_AUDIO_CORE ++ <200000000>, // RP1_PLL_SYS ++ <125000000>, // RP1_PLL_SYS_SEC ++ <61440000>, // RP1_PLL_AUDIO ++ <192000000>, // RP1_PLL_AUDIO_SEC ++ <200000000>, // RP1_CLK_SYS ++ <100000000>, // RP1_PLL_SYS_PRI_PH ++ // Must match the XOSC frequency ++ <50000000>, // RP1_CLK_SLOW_SYS ++ <1000000>, // RP1_CLK_SDIO_TIMER ++ <200000000>, // RP1_CLK_SDIO_ALT_SRC ++ <50000000>; // RP1_CLK_ETH_TSU ++ }; ++ ++ rp1_uart0: serial@30000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x40030000 0x0 0x100>; ++ interrupts = <RP1_INT_UART0 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ dmas = <&rp1_dma RP1_DMA_UART0_TX>, ++ <&rp1_dma RP1_DMA_UART0_RX>; ++ dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_uart1: serial@34000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x40034000 0x0 0x100>; ++ interrupts = <RP1_INT_UART1 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ // dmas = <&rp1_dma RP1_DMA_UART1_TX>, ++ // <&rp1_dma RP1_DMA_UART1_RX>; ++ // dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_uart2: serial@38000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x40038000 0x0 0x100>; ++ interrupts = <RP1_INT_UART2 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ // dmas = <&rp1_dma RP1_DMA_UART2_TX>, ++ // <&rp1_dma RP1_DMA_UART2_RX>; ++ // dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_uart3: serial@3c000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x4003c000 0x0 0x100>; ++ interrupts = <RP1_INT_UART3 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ // dmas = <&rp1_dma RP1_DMA_UART3_TX>, ++ // <&rp1_dma RP1_DMA_UART3_RX>; ++ // dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_uart4: serial@40000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x40040000 0x0 0x100>; ++ interrupts = <RP1_INT_UART4 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ // dmas = <&rp1_dma RP1_DMA_UART4_TX>, ++ // <&rp1_dma RP1_DMA_UART4_RX>; ++ // dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_uart5: serial@44000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x40044000 0x0 0x100>; ++ interrupts = <RP1_INT_UART5 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ // dmas = <&rp1_dma RP1_DMA_UART5_TX>, ++ // <&rp1_dma RP1_DMA_UART5_RX>; ++ // dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_spi8: spi@4c000 { ++ reg = <0xc0 0x4004c000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = <RP1_INT_SPI8 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI8_TX>, ++ <&rp1_dma RP1_DMA_SPI8_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_spi0: spi@50000 { ++ reg = <0xc0 0x40050000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = <RP1_INT_SPI0 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI0_TX>, ++ <&rp1_dma RP1_DMA_SPI0_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_spi1: spi@54000 { ++ reg = <0xc0 0x40054000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = <RP1_INT_SPI1 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI1_TX>, ++ <&rp1_dma RP1_DMA_SPI1_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_spi2: spi@58000 { ++ reg = <0xc0 0x40058000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = <RP1_INT_SPI2 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI2_TX>, ++ <&rp1_dma RP1_DMA_SPI2_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_spi3: spi@5c000 { ++ reg = <0xc0 0x4005c000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = <RP1_INT_SPI3 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI3_TX>, ++ <&rp1_dma RP1_DMA_SPI3_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ // SPI4 is a target/slave interface ++ rp1_spi4: spi@60000 { ++ reg = <0xc0 0x40060000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = <RP1_INT_SPI4 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <0>; ++ #size-cells = <0>; ++ num-cs = <1>; ++ spi-slave; ++ dmas = <&rp1_dma RP1_DMA_SPI4_TX>, ++ <&rp1_dma RP1_DMA_SPI4_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ ++ slave { ++ compatible = "spidev"; ++ spi-max-frequency = <1000000>; ++ }; ++ }; ++ ++ rp1_spi5: spi@64000 { ++ reg = <0xc0 0x40064000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = <RP1_INT_SPI5 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI5_TX>, ++ <&rp1_dma RP1_DMA_SPI5_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_spi6: spi@68000 { ++ reg = <0xc0 0x40068000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = <RP1_INT_SPI6 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI6_TX>, ++ <&rp1_dma RP1_DMA_SPI6_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ // SPI7 is a target/slave interface ++ rp1_spi7: spi@6c000 { ++ reg = <0xc0 0x4006c000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = <RP1_INT_SPI7 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <0>; ++ #size-cells = <0>; ++ num-cs = <1>; ++ spi-slave; ++ dmas = <&rp1_dma RP1_DMA_SPI7_TX>, ++ <&rp1_dma RP1_DMA_SPI7_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ ++ slave { ++ compatible = "spidev"; ++ spi-max-frequency = <1000000>; ++ }; ++ }; ++ ++ rp1_i2c0: i2c@70000 { ++ reg = <0xc0 0x40070000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = <RP1_INT_I2C0 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ i2c-scl-rising-time-ns = <65>; ++ i2c-scl-falling-time-ns = <100>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c1: i2c@74000 { ++ reg = <0xc0 0x40074000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = <RP1_INT_I2C1 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ i2c-scl-rising-time-ns = <65>; ++ i2c-scl-falling-time-ns = <100>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c2: i2c@78000 { ++ reg = <0xc0 0x40078000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = <RP1_INT_I2C2 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ i2c-scl-rising-time-ns = <65>; ++ i2c-scl-falling-time-ns = <100>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c3: i2c@7c000 { ++ reg = <0xc0 0x4007c000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = <RP1_INT_I2C3 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ i2c-scl-rising-time-ns = <65>; ++ i2c-scl-falling-time-ns = <100>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c4: i2c@80000 { ++ reg = <0xc0 0x40080000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = <RP1_INT_I2C4 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ i2c-scl-rising-time-ns = <65>; ++ i2c-scl-falling-time-ns = <100>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c5: i2c@84000 { ++ reg = <0xc0 0x40084000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = <RP1_INT_I2C5 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ i2c-scl-rising-time-ns = <65>; ++ i2c-scl-falling-time-ns = <100>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c6: i2c@88000 { ++ reg = <0xc0 0x40088000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = <RP1_INT_I2C6 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ i2c-scl-rising-time-ns = <65>; ++ i2c-scl-falling-time-ns = <100>; ++ status = "disabled"; ++ }; ++ ++ rp1_pwm0: pwm@98000 { ++ compatible = "raspberrypi,rp1-pwm"; ++ reg = <0xc0 0x40098000 0x0 0x100>; ++ #pwm-cells = <3>; ++ clocks = <&rp1_clocks RP1_CLK_PWM0>; ++ assigned-clocks = <&rp1_clocks RP1_CLK_PWM0>; ++ assigned-clock-rates = <50000000>; ++ status = "disabled"; ++ }; ++ ++ rp1_pwm1: pwm@9c000 { ++ compatible = "raspberrypi,rp1-pwm"; ++ reg = <0xc0 0x4009c000 0x0 0x100>; ++ #pwm-cells = <3>; ++ clocks = <&rp1_clocks RP1_CLK_PWM1>; ++ assigned-clocks = <&rp1_clocks RP1_CLK_PWM1>; ++ assigned-clock-rates = <50000000>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2s0: i2s@a0000 { ++ reg = <0xc0 0x400a0000 0x0 0x1000>; ++ compatible = "snps,designware-i2s"; ++ // Providing an interrupt disables DMA ++ // interrupts = <RP1_INT_I2S0 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_I2S>; ++ clock-names = "i2sclk"; ++ #sound-dai-cells = <0>; ++ dmas = <&rp1_dma RP1_DMA_I2S0_TX>,<&rp1_dma RP1_DMA_I2S0_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_i2s1: i2s@a4000 { ++ reg = <0xc0 0x400a4000 0x0 0x1000>; ++ compatible = "snps,designware-i2s"; ++ // Providing an interrupt disables DMA ++ // interrupts = <RP1_INT_I2S1 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_I2S>; ++ clock-names = "i2sclk"; ++ #sound-dai-cells = <0>; ++ dmas = <&rp1_dma RP1_DMA_I2S1_TX>,<&rp1_dma RP1_DMA_I2S1_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_i2s2: i2s@a8000 { ++ reg = <0xc0 0x400a8000 0x0 0x1000>; ++ compatible = "snps,designware-i2s"; ++ // Providing an interrupt disables DMA ++ // interrupts = <RP1_INT_I2S2 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_I2S>; ++ status = "disabled"; ++ }; ++ ++ rp1_sdio_clk0: sdio_clk0@b0004 { ++ compatible = "raspberrypi,rp1-sdio-clk"; ++ reg = <0xc0 0x400b0004 0x0 0x1c>; ++ clocks = <&sdio_src &sdhci_core>; ++ clock-names = "src", "base"; ++ #clock-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ rp1_sdio_clk1: sdio_clk1@b4004 { ++ compatible = "raspberrypi,rp1-sdio-clk"; ++ reg = <0xc0 0x400b4004 0x0 0x1c>; ++ clocks = <&sdio_src &sdhci_core>; ++ clock-names = "src", "base"; ++ #clock-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ rp1_adc: adc@c8000 { ++ compatible = "raspberrypi,rp1-adc"; ++ reg = <0xc0 0x400c8000 0x0 0x4000>; ++ clocks = <&rp1_clocks RP1_CLK_ADC>; ++ clock-names = "adcclk"; ++ #clock-cells = <0>; ++ vref-supply = <&rp1_vdd_3v3>; ++ status = "disabled"; ++ }; ++ ++ rp1_gpio: gpio@d0000 { ++ reg = <0xc0 0x400d0000 0x0 0xc000>, ++ <0xc0 0x400e0000 0x0 0xc000>, ++ <0xc0 0x400f0000 0x0 0xc000>; ++ compatible = "raspberrypi,rp1-gpio"; ++ interrupts = <RP1_INT_IO_BANK0 IRQ_TYPE_LEVEL_HIGH>, ++ <RP1_INT_IO_BANK1 IRQ_TYPE_LEVEL_HIGH>, ++ <RP1_INT_IO_BANK2 IRQ_TYPE_LEVEL_HIGH>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ ++ rp1_uart0_14_15: rp1_uart0_14_15 { ++ pin_txd { ++ function = "uart0"; ++ pins = "gpio14"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart0"; ++ pins = "gpio15"; ++ bias-pull-up; ++ }; ++ }; ++ rp1_uart0_ctsrts_16_17: rp1_uart0_ctsrts_16_17 { ++ pin_cts { ++ function = "uart0"; ++ pins = "gpio16"; ++ bias-pull-up; ++ }; ++ pin_rts { ++ function = "uart0"; ++ pins = "gpio17"; ++ bias-disable; ++ }; ++ }; ++ rp1_uart1_0_1: rp1_uart1_0_1 { ++ pin_txd { ++ function = "uart1"; ++ pins = "gpio0"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart1"; ++ pins = "gpio1"; ++ bias-pull-up; ++ }; ++ }; ++ rp1_uart1_ctsrts_2_3: rp1_uart1_ctsrts_2_3 { ++ pin_cts { ++ function = "uart1"; ++ pins = "gpio2"; ++ bias-pull-up; ++ }; ++ pin_rts { ++ function = "uart1"; ++ pins = "gpio3"; ++ bias-disable; ++ }; ++ }; ++ rp1_uart2_4_5: rp1_uart2_4_5 { ++ pin_txd { ++ function = "uart2"; ++ pins = "gpio4"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart2"; ++ pins = "gpio5"; ++ bias-pull-up; ++ }; ++ }; ++ rp1_uart2_ctsrts_6_7: rp1_uart2_ctsrts_6_7 { ++ pin_cts { ++ function = "uart2"; ++ pins = "gpio6"; ++ bias-pull-up; ++ }; ++ pin_rts { ++ function = "uart2"; ++ pins = "gpio7"; ++ bias-disable; ++ }; ++ }; ++ rp1_uart3_8_9: rp1_uart3_8_9 { ++ pin_txd { ++ function = "uart3"; ++ pins = "gpio8"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart3"; ++ pins = "gpio9"; ++ bias-pull-up; ++ }; ++ }; ++ rp1_uart3_ctsrts_10_11: rp1_uart3_ctsrts_10_11 { ++ pin_cts { ++ function = "uart3"; ++ pins = "gpio10"; ++ bias-pull-up; ++ }; ++ pin_rts { ++ function = "uart3"; ++ pins = "gpio11"; ++ bias-disable; ++ }; ++ }; ++ rp1_uart4_12_13: rp1_uart4_12_13 { ++ pin_txd { ++ function = "uart4"; ++ pins = "gpio12"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart4"; ++ pins = "gpio13"; ++ bias-pull-up; ++ }; ++ }; ++ rp1_uart4_ctsrts_14_15: rp1_uart4_ctsrts_14_15 { ++ pin_cts { ++ function = "uart4"; ++ pins = "gpio14"; ++ bias-pull-up; ++ }; ++ pin_rts { ++ function = "uart4"; ++ pins = "gpio15"; ++ bias-disable; ++ }; ++ }; ++ ++ rp1_sdio0_22_27: rp1_sdio0_22_27 { ++ pin_clk { ++ function = "sd0"; ++ pins = "gpio22"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ pin_cmd { ++ function = "sd0"; ++ pins = "gpio23"; ++ bias-pull-up; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ pins_dat { ++ function = "sd0"; ++ pins = "gpio24", "gpio25", "gpio26", "gpio27"; ++ bias-pull-up; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ }; ++ ++ rp1_sdio1_28_33: rp1_sdio1_28_33 { ++ pin_clk { ++ function = "sd1"; ++ pins = "gpio28"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ pin_cmd { ++ function = "sd1"; ++ pins = "gpio29"; ++ bias-pull-up; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ pins_dat { ++ function = "sd1"; ++ pins = "gpio30", "gpio31", "gpio32", "gpio33"; ++ bias-pull-up; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ }; ++ ++ rp1_i2s0_18_21: rp1_i2s0_18_21 { ++ function = "i2s0"; ++ pins = "gpio18", "gpio19", "gpio20", "gpio21"; ++ bias-disable; ++ }; ++ ++ rp1_i2s1_18_21: rp1_i2s1_18_21 { ++ function = "i2s1"; ++ pins = "gpio18", "gpio19", "gpio20", "gpio21"; ++ bias-disable; ++ }; ++ ++ rp1_i2c4_34_35: rp1_i2c4_34_35 { ++ function = "i2c4"; ++ pins = "gpio34", "gpio35"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c6_38_39: rp1_i2c6_38_39 { ++ function = "i2c6"; ++ pins = "gpio38", "gpio39"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c4_40_41: rp1_i2c4_40_41 { ++ function = "i2c4"; ++ pins = "gpio40", "gpio41"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c5_44_45: rp1_i2c5_44_45 { ++ function = "i2c5"; ++ pins = "gpio44", "gpio45"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c0_0_1: rp1_i2c0_0_1 { ++ function = "i2c0"; ++ pins = "gpio0", "gpio1"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c0_8_9: rp1_i2c0_8_9 { ++ function = "i2c0"; ++ pins = "gpio8", "gpio9"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c1_2_3: rp1_i2c1_2_3 { ++ function = "i2c1"; ++ pins = "gpio2", "gpio3"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c1_10_11: rp1_i2c1_10_11 { ++ function = "i2c1"; ++ pins = "gpio10", "gpio11"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c2_4_5: rp1_i2c2_4_5 { ++ function = "i2c2"; ++ pins = "gpio4", "gpio5"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c2_12_13: rp1_i2c2_12_13 { ++ function = "i2c2"; ++ pins = "gpio12", "gpio13"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c3_6_7: rp1_i2c3_6_7 { ++ function = "i2c3"; ++ pins = "gpio6", "gpio7"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c3_14_15: rp1_i2c3_14_15 { ++ function = "i2c3"; ++ pins = "gpio14", "gpio15"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c3_22_23: rp1_i2c3_22_23 { ++ function = "i2c3"; ++ pins = "gpio22", "gpio23"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ ++ // DPI mappings with HSYNC,VSYNC but without PIXCLK,DE ++ rp1_dpi_16bit_gpio2: rp1_dpi_16bit_gpio2 { /* Mode 2, not fully supported by RP1 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", "gpio4", "gpio5", ++ "gpio6", "gpio7", "gpio8", "gpio9", ++ "gpio10", "gpio11", "gpio12", "gpio13", ++ "gpio14", "gpio15", "gpio16", "gpio17", ++ "gpio18", "gpio19"; ++ bias-disable; ++ }; ++ rp1_dpi_16bit_cpadhi_gpio2: rp1_dpi_16bit_cpadhi_gpio2 { /* Mode 3 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", "gpio4", "gpio5", ++ "gpio6", "gpio7", "gpio8", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio20", "gpio21", "gpio22", "gpio23", ++ "gpio24"; ++ bias-disable; ++ }; ++ rp1_dpi_16bit_pad666_gpio2: rp1_dpi_16bit_pad666_gpio2 { /* Mode 4 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", ++ "gpio5", "gpio6", "gpio7", "gpio8", ++ "gpio9", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio21", "gpio22", "gpio23", "gpio24", ++ "gpio25"; ++ bias-disable; ++ }; ++ rp1_dpi_18bit_gpio2: rp1_dpi_18bit_gpio2 { /* Mode 5, not fully supported by RP1 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", "gpio4", "gpio5", ++ "gpio6", "gpio7", "gpio8", "gpio9", ++ "gpio10", "gpio11", "gpio12", "gpio13", ++ "gpio14", "gpio15", "gpio16", "gpio17", ++ "gpio18", "gpio19", "gpio20", "gpio21"; ++ bias-disable; ++ }; ++ rp1_dpi_18bit_cpadhi_gpio2: rp1_dpi_18bit_cpadhi_gpio2 { /* Mode 6 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", "gpio4", "gpio5", ++ "gpio6", "gpio7", "gpio8", "gpio9", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio20", "gpio21", "gpio22", "gpio23", ++ "gpio24", "gpio25"; ++ bias-disable; ++ }; ++ rp1_dpi_24bit_gpio2: rp1_dpi_24bit_gpio2 { /* Mode 7 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", "gpio4", "gpio5", ++ "gpio6", "gpio7", "gpio8", "gpio9", ++ "gpio10", "gpio11", "gpio12", "gpio13", ++ "gpio14", "gpio15", "gpio16", "gpio17", ++ "gpio18", "gpio19", "gpio20", "gpio21", ++ "gpio22", "gpio23", "gpio24", "gpio25", ++ "gpio26", "gpio27"; ++ bias-disable; ++ }; ++ rp1_dpi_hvsync: rp1_dpi_hvsync { /* Sync only, for use with int VDAC */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3"; ++ bias-disable; ++ }; ++ ++ // More DPI mappings, including PIXCLK,DE on GPIOs 0,1 ++ rp1_dpi_16bit_gpio0: rp1_dpi_16bit_gpio0 { /* Mode 2, not fully supported by RP1 */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio4", "gpio5", "gpio6", "gpio7", ++ "gpio8", "gpio9", "gpio10", "gpio11", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", "gpio18", "gpio19"; ++ bias-disable; ++ }; ++ rp1_dpi_16bit_cpadhi_gpio0: rp1_dpi_16bit_cpadhi_gpio0 { /* Mode 3 */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio4", "gpio5", "gpio6", "gpio7", ++ "gpio8", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio20", "gpio21", "gpio22", "gpio23", ++ "gpio24"; ++ bias-disable; ++ }; ++ rp1_dpi_16bit_pad666_gpio0: rp1_dpi_16bit_pad666_gpio0 { /* Mode 4 */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio5", "gpio6", "gpio7", "gpio8", ++ "gpio9", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio21", "gpio22", "gpio23", "gpio24", ++ "gpio25"; ++ bias-disable; ++ }; ++ rp1_dpi_18bit_gpio0: rp1_dpi_18bit_gpio0 { /* Mode 5, not fully supported by RP1 */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio4", "gpio5", "gpio6", "gpio7", ++ "gpio8", "gpio9", "gpio10", "gpio11", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", "gpio18", "gpio19", ++ "gpio20", "gpio21"; ++ bias-disable; ++ }; ++ rp1_dpi_18bit_cpadhi_gpio0: rp1_dpi_18bit_cpadhi_gpio0 { /* Mode 6 */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio4", "gpio5", "gpio6", "gpio7", ++ "gpio8", "gpio9", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio20", "gpio21", "gpio22", "gpio23", ++ "gpio24", "gpio25"; ++ bias-disable; ++ }; ++ rp1_dpi_24bit_gpio0: rp1_dpi_24bit_gpio0 { /* Mode 7 -- All GPIOs used! */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio4", "gpio5", "gpio6", "gpio7", ++ "gpio8", "gpio9", "gpio10", "gpio11", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", "gpio18", "gpio19", ++ "gpio20", "gpio21", "gpio22", "gpio23", ++ "gpio24", "gpio25", "gpio26", "gpio27"; ++ bias-disable; ++ }; ++ ++ rp1_gpclksrc0_gpio4: rp1_gpclksrc0_gpio4 { ++ function = "gpclk0"; ++ pins = "gpio4"; ++ bias-disable; ++ }; ++ ++ rp1_gpclksrc0_gpio20: rp1_gpclksrc0_gpio20 { ++ function = "gpclk0"; ++ pins = "gpio20"; ++ bias-disable; ++ }; ++ ++ rp1_gpclksrc1_gpio5: rp1_gpclksrc1_gpio5 { ++ function = "gpclk1"; ++ pins = "gpio5"; ++ bias-disable; ++ }; ++ ++ rp1_gpclksrc1_gpio18: rp1_gpclksrc1_gpio18 { ++ function = "gpclk1"; ++ pins = "gpio18"; ++ bias-disable; ++ }; ++ ++ rp1_gpclksrc1_gpio21: rp1_gpclksrc1_gpio21 { ++ function = "gpclk1"; ++ pins = "gpio21"; ++ bias-disable; ++ }; ++ ++ rp1_pwm1_gpio45: rp1_pwm1_gpio45 { ++ function = "pwm1"; ++ pins = "gpio45"; ++ bias-pull-down; ++ }; ++ ++ rp1_spi0_gpio9: rp1_spi0_gpio9 { ++ function = "spi0"; ++ pins = "gpio9", "gpio10", "gpio11"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi0_cs_gpio7: rp1_spi0_cs_gpio7 { ++ function = "spi0"; ++ pins = "gpio7", "gpio8"; ++ bias-pull-up; ++ }; ++ ++ rp1_spi1_gpio19: rp1_spi1_gpio19 { ++ function = "spi1"; ++ pins = "gpio19", "gpio20", "gpio21"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi2_gpio1: rp1_spi2_gpio1 { ++ function = "spi2"; ++ pins = "gpio1", "gpio2", "gpio3"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi3_gpio5: rp1_spi3_gpio5 { ++ function = "spi3"; ++ pins = "gpio5", "gpio6", "gpio7"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi4_gpio9: rp1_spi4_gpio9 { ++ function = "spi4"; ++ pins = "gpio9", "gpio10", "gpio11"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi5_gpio13: rp1_spi5_gpio13 { ++ function = "spi5"; ++ pins = "gpio13", "gpio14", "gpio15"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi8_gpio49: rp1_spi8_gpio49 { ++ function = "spi8"; ++ pins = "gpio49", "gpio50", "gpio51"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi8_cs_gpio52: rp1_spi8_cs_gpio52 { ++ function = "spi0"; ++ pins = "gpio52", "gpio53"; ++ bias-pull-up; ++ }; ++ }; ++ ++ rp1_eth: ethernet@100000 { ++ reg = <0xc0 0x40100000 0x0 0x4000>; ++ compatible = "cdns,macb"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ interrupts = <RP1_INT_ETH IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&macb_pclk &macb_hclk &rp1_clocks RP1_CLK_ETH_TSU>; ++ clock-names = "pclk", "hclk", "tsu_clk"; ++ phy-mode = "rgmii-id"; ++ cdns,aw2w-max-pipe = /bits/ 8 <8>; ++ cdns,ar2r-max-pipe = /bits/ 8 <8>; ++ cdns,use-aw2b-fill; ++ local-mac-address = 00 00 00 00 00 00; ++ status = "disabled"; ++ }; ++ ++ rp1_csi0: csi@110000 { ++ compatible = "raspberrypi,rp1-cfe"; ++ reg = <0xc0 0x40110000 0x0 0x100>, // CSI2 DMA address ++ <0xc0 0x40114000 0x0 0x100>, // PHY/CSI Host address ++ <0xc0 0x40120000 0x0 0x100>, // MIPI CFG address ++ <0xc0 0x40124000 0x0 0x1000>; // PiSP FE address ++ ++ // interrupts must match rp1_pisp_fe setup ++ interrupts = <RP1_INT_MIPI0 IRQ_TYPE_LEVEL_HIGH>; ++ ++ clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>; ++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>; ++ assigned-clock-rates = <25000000>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ rp1_csi1: csi@128000 { ++ compatible = "raspberrypi,rp1-cfe"; ++ reg = <0xc0 0x40128000 0x0 0x100>, // CSI2 DMA address ++ <0xc0 0x4012c000 0x0 0x100>, // PHY/CSI Host address ++ <0xc0 0x40138000 0x0 0x100>, // MIPI CFG address ++ <0xc0 0x4013c000 0x0 0x1000>; // PiSP FE address ++ ++ // interrupts must match rp1_pisp_fe setup ++ interrupts = <RP1_INT_MIPI1 IRQ_TYPE_LEVEL_HIGH>; ++ ++ clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>; ++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>; ++ assigned-clock-rates = <25000000>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ rp1_mmc0: mmc@180000 { ++ reg = <0xc0 0x40180000 0x0 0x100>; ++ compatible = "raspberrypi,rp1-dwcmshc"; ++ interrupts = <RP1_INT_SDIO0 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS &sdhci_core ++ &rp1_clocks RP1_CLK_SDIO_TIMER ++ &rp1_sdio_clk0>; ++ clock-names = "bus", "core", "timeout", "sdio"; ++ /* Bank 0 VDDIO is fixed */ ++ no-1-8-v; ++ bus-width = <4>; ++ vmmc-supply = <&rp1_vdd_3v3>; ++ broken-cd; ++ status = "disabled"; ++ }; ++ ++ rp1_mmc1: mmc@184000 { ++ reg = <0xc0 0x40184000 0x0 0x100>; ++ compatible = "raspberrypi,rp1-dwcmshc"; ++ interrupts = <RP1_INT_SDIO1 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&rp1_clocks RP1_CLK_SYS &sdhci_core ++ &rp1_clocks RP1_CLK_SDIO_TIMER ++ &rp1_sdio_clk1>; ++ clock-names = "bus", "core", "timeout", "sdio"; ++ bus-width = <4>; ++ vmmc-supply = <&rp1_vdd_3v3>; ++ /* Nerf SDR speeds */ ++ sdhci-caps-mask = <0x3 0x0>; ++ broken-cd; ++ status = "disabled"; ++ }; ++ ++ rp1_dma: dma@188000 { ++ reg = <0xc0 0x40188000 0x0 0x1000>; ++ compatible = "snps,axi-dma-1.01a"; ++ interrupts = <RP1_INT_DMA IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&sdhci_core &rp1_clocks RP1_CLK_SYS>; ++ clock-names = "core-clk", "cfgr-clk"; ++ ++ #dma-cells = <1>; ++ dma-channels = <8>; ++ snps,dma-masters = <1>; ++ snps,dma-targets = <64>; ++ snps,data-width = <4>; // (8 << 4) == 128 bits ++ snps,block-size = <0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000>; ++ snps,priority = <0 1 2 3 4 5 6 7>; ++ snps,axi-max-burst-len = <8>; ++ status = "disabled"; ++ }; ++ ++ rp1_usb0: usb@200000 { ++ reg = <0xc0 0x40200000 0x0 0x100000>; ++ compatible = "snps,dwc3"; ++ dr_mode = "host"; ++ usb3-lpm-capable; ++ snps,axi-pipe-limit = /bits/ 8 <8>; ++ snps,dis_rxdet_inp3_quirk; ++ snps,parkmode-disable-ss-quirk; ++ snps,parkmode-disable-hs-quirk; ++ snps,parkmode-disable-fsls-quirk; ++ snps,tx-max-burst-prd = <8>; ++ snps,tx-thr-num-pkt-prd = <2>; ++ interrupts = <RP1_INT_USBHOST0_0 IRQ_TYPE_EDGE_RISING>; ++ status = "disabled"; ++ }; ++ ++ rp1_usb1: usb@300000 { ++ reg = <0xc0 0x40300000 0x0 0x100000>; ++ compatible = "snps,dwc3"; ++ dr_mode = "host"; ++ usb3-lpm-capable; ++ snps,axi-pipe-limit = /bits/ 8 <8>; ++ snps,dis_rxdet_inp3_quirk; ++ snps,parkmode-disable-ss-quirk; ++ snps,parkmode-disable-hs-quirk; ++ snps,parkmode-disable-fsls-quirk; ++ snps,tx-max-burst-prd = <8>; ++ snps,tx-thr-num-pkt-prd = <2>; ++ interrupts = <RP1_INT_USBHOST1_0 IRQ_TYPE_EDGE_RISING>; ++ status = "disabled"; ++ }; ++ ++ rp1_dsi0: dsi@110000 { ++ compatible = "raspberrypi,rp1dsi"; ++ status = "disabled"; ++ reg = <0xc0 0x40118000 0x0 0x1000>, // MIPI0 DSI DMA (ArgonDPI) ++ <0xc0 0x4011c000 0x0 0x1000>, // MIPI0 DSI Host (SNPS) ++ <0xc0 0x40120000 0x0 0x1000>; // MIPI0 CFG ++ ++ interrupts = <RP1_INT_MIPI0 IRQ_TYPE_LEVEL_HIGH>; ++ ++ clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>, // required, config bus clock ++ <&rp1_clocks RP1_CLK_MIPI0_DPI>, // required, pixel clock ++ <&clksrc_mipi0_dsi_byteclk>, // internal, parent for divide ++ <&clk_xosc>; // hardwired to DSI "refclk" ++ clock-names = "cfgclk", "dpiclk", "byteclk", "refclk"; ++ ++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>, ++ <&rp1_clocks RP1_CLK_MIPI0_DPI>; ++ assigned-clock-rates = <25000000>; ++ assigned-clock-parents = <0>, <&clksrc_mipi0_dsi_byteclk>; ++ }; ++ ++ rp1_dsi1: dsi@128000 { ++ compatible = "raspberrypi,rp1dsi"; ++ status = "disabled"; ++ reg = <0xc0 0x40130000 0x0 0x1000>, // MIPI1 DSI DMA (ArgonDPI) ++ <0xc0 0x40134000 0x0 0x1000>, // MIPI1 DSI Host (SNPS) ++ <0xc0 0x40138000 0x0 0x1000>; // MIPI1 CFG ++ ++ interrupts = <RP1_INT_MIPI1 IRQ_TYPE_LEVEL_HIGH>; ++ ++ clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>, // required, config bus clock ++ <&rp1_clocks RP1_CLK_MIPI1_DPI>, // required, pixel clock ++ <&clksrc_mipi1_dsi_byteclk>, // internal, parent for divide ++ <&clk_xosc>; // hardwired to DSI "refclk" ++ clock-names = "cfgclk", "dpiclk", "byteclk", "refclk"; ++ ++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>, ++ <&rp1_clocks RP1_CLK_MIPI1_DPI>; ++ assigned-clock-rates = <25000000>; ++ assigned-clock-parents = <0>, <&clksrc_mipi1_dsi_byteclk>; ++ }; ++ ++ /* VEC and DPI both need to control PLL_VIDEO and cannot work together; */ ++ /* config.txt should enable one or other using dtparam=vec or an overlay. */ ++ rp1_vec: vec@144000 { ++ compatible = "raspberrypi,rp1vec"; ++ status = "disabled"; ++ reg = <0xc0 0x40144000 0x0 0x1000>, // VIDEO_OUT_VEC ++ <0xc0 0x40140000 0x0 0x1000>; // VIDEO_OUT_CFG ++ ++ interrupts = <RP1_INT_VIDEO_OUT IRQ_TYPE_LEVEL_HIGH>; ++ ++ clocks = <&rp1_clocks RP1_CLK_VEC>; ++ ++ assigned-clocks = <&rp1_clocks RP1_PLL_VIDEO_CORE>, ++ <&rp1_clocks RP1_PLL_VIDEO_SEC>, ++ <&rp1_clocks RP1_CLK_VEC>; ++ assigned-clock-rates = <1188000000>, ++ <108000000>, ++ <108000000>; ++ assigned-clock-parents = <0>, ++ <&rp1_clocks RP1_PLL_VIDEO_CORE>, ++ <&rp1_clocks RP1_PLL_VIDEO_SEC>; ++ }; ++ ++ rp1_dpi: dpi@148000 { ++ compatible = "raspberrypi,rp1dpi"; ++ status = "disabled"; ++ reg = <0xc0 0x40148000 0x0 0x1000>, // VIDEO_OUT DPI ++ <0xc0 0x40140000 0x0 0x1000>; // VIDEO_OUT_CFG ++ ++ interrupts = <RP1_INT_VIDEO_OUT IRQ_TYPE_LEVEL_HIGH>; ++ ++ clocks = <&rp1_clocks RP1_CLK_DPI>, // DPI pixel clock ++ <&rp1_clocks RP1_PLL_VIDEO>, // PLL primary divider, and ++ <&rp1_clocks RP1_PLL_VIDEO_CORE>; // VCO, which we also control ++ clock-names = "dpiclk", "plldiv", "pllcore"; ++ ++ assigned-clocks = <&rp1_clocks RP1_CLK_DPI>; ++ assigned-clock-parents = <&rp1_clocks RP1_PLL_VIDEO>; ++ }; ++ }; ++}; ++ ++&clocks { ++ clk_xosc: clk_xosc { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "xosc"; ++ clock-frequency = <50000000>; ++ }; ++ macb_pclk: macb_pclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "pclk"; ++ clock-frequency = <200000000>; ++ }; ++ macb_hclk: macb_hclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "hclk"; ++ clock-frequency = <200000000>; ++ }; ++ sdio_src: sdio_src { ++ // 400 MHz on FPGA. PLL sys VCO on asic ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "src"; ++ clock-frequency = <1000000000>; ++ }; ++ sdhci_core: sdhci_core { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "core"; ++ clock-frequency = <50000000>; ++ }; ++ clksrc_mipi0_dsi_byteclk: clksrc_mipi0_dsi_byteclk { ++ // This clock is synthesized by MIPI0 D-PHY, when DSI is running. ++ // Its frequency is not known a priori (until a panel driver attaches) ++ // so assign a made-up frequency of 72MHz so it can be divided for DPI. ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "clksrc_mipi0_dsi_byteclk"; ++ clock-frequency = <72000000>; ++ }; ++ clksrc_mipi1_dsi_byteclk: clksrc_mipi1_dsi_byteclk { ++ // This clock is synthesized by MIPI1 D-PHY, when DSI is running. ++ // Its frequency is not known a priori (until a panel driver attaches) ++ // so assign a made-up frequency of 72MHz so it can be divided for DPI. ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "clksrc_mipi1_dsi_byteclk"; ++ clock-frequency = <72000000>; ++ }; ++ /* GPIO derived clock sources. Each GPIO with a GPCLK function ++ * can drive its output from the respective GPCLK ++ * generator, and provide a clock source to other internal ++ * dividers. Add dummy sources here so that they can be overridden ++ * with overlays. ++ */ ++ clksrc_gp0: clksrc_gp0 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ #clock-cells = <0>; ++ clock-div = <1>; ++ clock-mult = <1>; ++ clocks = <&rp1_clocks RP1_CLK_GP0>; ++ clock-output-names = "clksrc_gp0"; ++ }; ++ clksrc_gp1: clksrc_gp1 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ #clock-cells = <0>; ++ clock-div = <1>; ++ clock-mult = <1>; ++ clocks = <&rp1_clocks RP1_CLK_GP1>; ++ clock-output-names = "clksrc_gp1"; ++ }; ++ clksrc_gp2: clksrc_gp2 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ clock-div = <1>; ++ clock-mult = <1>; ++ #clock-cells = <0>; ++ clocks = <&rp1_clocks RP1_CLK_GP2>; ++ clock-output-names = "clksrc_gp2"; ++ }; ++ clksrc_gp3: clksrc_gp3 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ clock-div = <1>; ++ clock-mult = <1>; ++ #clock-cells = <0>; ++ clocks = <&rp1_clocks RP1_CLK_GP3>; ++ clock-output-names = "clksrc_gp3"; ++ }; ++ clksrc_gp4: clksrc_gp4 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ #clock-cells = <0>; ++ clock-div = <1>; ++ clock-mult = <1>; ++ clocks = <&rp1_clocks RP1_CLK_GP4>; ++ clock-output-names = "clksrc_gp4"; ++ }; ++ clksrc_gp5: clksrc_gp5 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ #clock-cells = <0>; ++ clock-div = <1>; ++ clock-mult = <1>; ++ clocks = <&rp1_clocks RP1_CLK_GP5>; ++ clock-output-names = "clksrc_gp5"; ++ }; ++}; ++ ++/ { ++ rp1_vdd_3v3: rp1_vdd_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "vdd-3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile +new file mode 100644 +index 000000000000..bdd02b8c6f0f +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -0,0 +1,333 @@ ++# Overlays for the Raspberry Pi platform ++ ++dtb-$(CONFIG_ARCH_BCM2835) += overlay_map.dtb hat_map.dtb ++ ++dtbo-$(CONFIG_ARCH_BCM2835) += \ ++ act-led.dtbo \ ++ adafruit-st7735r.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 \ ++ arducam-64mp.dtbo \ ++ arducam-pivariety.dtbo \ ++ at86rf233.dtbo \ ++ audioinjector-addons.dtbo \ ++ audioinjector-bare-i2s.dtbo \ ++ audioinjector-isolated-soundcard.dtbo \ ++ audioinjector-ultra.dtbo \ ++ audioinjector-wm8731-audio.dtbo \ ++ audiosense-pi.dtbo \ ++ audremap.dtbo \ ++ balena-fin.dtbo \ ++ bcm2712d0.dtbo \ ++ camera-mux-2port.dtbo \ ++ camera-mux-4port.dtbo \ ++ cap1106.dtbo \ ++ chipdip-dac.dtbo \ ++ cirrus-wm5102.dtbo \ ++ cm-swap-i2c0.dtbo \ ++ cma.dtbo \ ++ crystalfontz-cfa050_pi_m.dtbo \ ++ cutiepi-panel.dtbo \ ++ dacberry400.dtbo \ ++ dht11.dtbo \ ++ dionaudio-kiwi.dtbo \ ++ dionaudio-loco.dtbo \ ++ dionaudio-loco-v2.dtbo \ ++ disable-bt.dtbo \ ++ disable-bt-pi5.dtbo \ ++ disable-emmc2.dtbo \ ++ disable-wifi.dtbo \ ++ disable-wifi-pi5.dtbo \ ++ dpi18.dtbo \ ++ dpi18cpadhi.dtbo \ ++ dpi24.dtbo \ ++ draws.dtbo \ ++ dwc-otg.dtbo \ ++ dwc2.dtbo \ ++ edt-ft5406.dtbo \ ++ enc28j60.dtbo \ ++ enc28j60-spi2.dtbo \ ++ exc3000.dtbo \ ++ fbtft.dtbo \ ++ fe-pi-audio.dtbo \ ++ fsm-demo.dtbo \ ++ gc9a01.dtbo \ ++ ghost-amp.dtbo \ ++ goodix.dtbo \ ++ googlevoicehat-soundcard.dtbo \ ++ gpio-charger.dtbo \ ++ gpio-fan.dtbo \ ++ gpio-hog.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-amp3.dtbo \ ++ hifiberry-amp4pro.dtbo \ ++ hifiberry-dac.dtbo \ ++ hifiberry-dac8x.dtbo \ ++ hifiberry-dacplus.dtbo \ ++ hifiberry-dacplus-pro.dtbo \ ++ hifiberry-dacplus-std.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-fan.dtbo \ ++ i2c-gpio.dtbo \ ++ i2c-mux.dtbo \ ++ i2c-pwm-pca9685a.dtbo \ ++ i2c-rtc.dtbo \ ++ i2c-rtc-gpio.dtbo \ ++ i2c-sensor.dtbo \ ++ i2c0.dtbo \ ++ i2c0-pi5.dtbo \ ++ i2c1.dtbo \ ++ i2c1-pi5.dtbo \ ++ i2c2-pi5.dtbo \ ++ i2c3.dtbo \ ++ i2c3-pi5.dtbo \ ++ i2c4.dtbo \ ++ i2c5.dtbo \ ++ i2c6.dtbo \ ++ i2s-dac.dtbo \ ++ i2s-gpio28-31.dtbo \ ++ ilitek251x.dtbo \ ++ imx219.dtbo \ ++ imx258.dtbo \ ++ imx290.dtbo \ ++ imx296.dtbo \ ++ imx327.dtbo \ ++ imx378.dtbo \ ++ imx462.dtbo \ ++ imx477.dtbo \ ++ imx519.dtbo \ ++ imx708.dtbo \ ++ interludeaudio-analog.dtbo \ ++ interludeaudio-digital.dtbo \ ++ iqaudio-codec.dtbo \ ++ iqaudio-dac.dtbo \ ++ iqaudio-dacplus.dtbo \ ++ iqaudio-digi-wm8804-audio.dtbo \ ++ iqs550.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.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-uart0-pi5.dtbo \ ++ midi-uart1.dtbo \ ++ midi-uart1-pi5.dtbo \ ++ midi-uart2.dtbo \ ++ midi-uart2-pi5.dtbo \ ++ midi-uart3.dtbo \ ++ midi-uart3-pi5.dtbo \ ++ midi-uart4.dtbo \ ++ midi-uart4-pi5.dtbo \ ++ midi-uart5.dtbo \ ++ minipitft13.dtbo \ ++ miniuart-bt.dtbo \ ++ mipi-dbi-spi.dtbo \ ++ mlx90640.dtbo \ ++ mmc.dtbo \ ++ mz61581.dtbo \ ++ ov2311.dtbo \ ++ ov5647.dtbo \ ++ ov64a40.dtbo \ ++ ov7251.dtbo \ ++ ov9281.dtbo \ ++ papirus.dtbo \ ++ pca953x.dtbo \ ++ pcf857x.dtbo \ ++ pcie-32bit-dma.dtbo \ ++ pcie-32bit-dma-pi5.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 \ ++ pisound-pi5.dtbo \ ++ pitft22.dtbo \ ++ pitft28-capacitive.dtbo \ ++ pitft28-resistive.dtbo \ ++ pitft35-resistive.dtbo \ ++ pps-gpio.dtbo \ ++ proto-codec.dtbo \ ++ pwm.dtbo \ ++ pwm-2chan.dtbo \ ++ pwm-ir-tx.dtbo \ ++ pwm1.dtbo \ ++ qca7000.dtbo \ ++ qca7000-uart0.dtbo \ ++ ramoops.dtbo \ ++ ramoops-pi4.dtbo \ ++ rotary-encoder.dtbo \ ++ rpi-backlight.dtbo \ ++ rpi-codeczero.dtbo \ ++ rpi-dacplus.dtbo \ ++ rpi-dacpro.dtbo \ ++ rpi-digiampplus.dtbo \ ++ rpi-ft5406.dtbo \ ++ rpi-poe.dtbo \ ++ rpi-poe-plus.dtbo \ ++ rpi-sense.dtbo \ ++ rpi-sense-v2.dtbo \ ++ rpi-tv.dtbo \ ++ rra-digidac1-wm8741-audio.dtbo \ ++ sainsmart18.dtbo \ ++ sc16is750-i2c.dtbo \ ++ sc16is752-i2c.dtbo \ ++ sc16is752-spi0.dtbo \ ++ sc16is752-spi1.dtbo \ ++ sdhost.dtbo \ ++ sdio.dtbo \ ++ sdio-pi5.dtbo \ ++ seeed-can-fd-hat-v1.dtbo \ ++ seeed-can-fd-hat-v2.dtbo \ ++ sh1106-spi.dtbo \ ++ si446x-spi0.dtbo \ ++ smi.dtbo \ ++ smi-dev.dtbo \ ++ smi-nand.dtbo \ ++ spi-gpio35-39.dtbo \ ++ spi-gpio40-45.dtbo \ ++ spi-rtc.dtbo \ ++ spi0-0cs.dtbo \ ++ spi0-1cs.dtbo \ ++ spi0-2cs.dtbo \ ++ spi1-1cs.dtbo \ ++ spi1-2cs.dtbo \ ++ spi1-3cs.dtbo \ ++ spi2-1cs.dtbo \ ++ spi2-1cs-pi5.dtbo \ ++ spi2-2cs.dtbo \ ++ spi2-2cs-pi5.dtbo \ ++ spi2-3cs.dtbo \ ++ spi3-1cs.dtbo \ ++ spi3-1cs-pi5.dtbo \ ++ spi3-2cs.dtbo \ ++ spi3-2cs-pi5.dtbo \ ++ spi4-1cs.dtbo \ ++ spi4-2cs.dtbo \ ++ spi5-1cs.dtbo \ ++ spi5-1cs-pi5.dtbo \ ++ spi5-2cs.dtbo \ ++ spi5-2cs-pi5.dtbo \ ++ spi6-1cs.dtbo \ ++ spi6-2cs.dtbo \ ++ ssd1306.dtbo \ ++ ssd1306-spi.dtbo \ ++ ssd1331-spi.dtbo \ ++ ssd1351-spi.dtbo \ ++ superaudioboard.dtbo \ ++ sx150x.dtbo \ ++ tc358743.dtbo \ ++ tc358743-audio.dtbo \ ++ tinylcd35.dtbo \ ++ tpm-slb9670.dtbo \ ++ tpm-slb9673.dtbo \ ++ uart0.dtbo \ ++ uart0-pi5.dtbo \ ++ uart1.dtbo \ ++ uart1-pi5.dtbo \ ++ uart2.dtbo \ ++ uart2-pi5.dtbo \ ++ uart3.dtbo \ ++ uart3-pi5.dtbo \ ++ uart4.dtbo \ ++ uart4-pi5.dtbo \ ++ uart5.dtbo \ ++ udrc.dtbo \ ++ ugreen-dabboard.dtbo \ ++ upstream.dtbo \ ++ upstream-pi4.dtbo \ ++ vc4-fkms-v3d.dtbo \ ++ vc4-fkms-v3d-pi4.dtbo \ ++ vc4-kms-dpi-generic.dtbo \ ++ vc4-kms-dpi-hyperpixel2r.dtbo \ ++ vc4-kms-dpi-hyperpixel4.dtbo \ ++ vc4-kms-dpi-hyperpixel4sq.dtbo \ ++ vc4-kms-dpi-panel.dtbo \ ++ vc4-kms-dsi-7inch.dtbo \ ++ vc4-kms-dsi-generic.dtbo \ ++ vc4-kms-dsi-ili9881-5inch.dtbo \ ++ vc4-kms-dsi-ili9881-7inch.dtbo \ ++ vc4-kms-dsi-lt070me05000.dtbo \ ++ vc4-kms-dsi-lt070me05000-v2.dtbo \ ++ vc4-kms-dsi-waveshare-panel.dtbo \ ++ vc4-kms-kippah-7inch.dtbo \ ++ vc4-kms-v3d.dtbo \ ++ vc4-kms-v3d-pi4.dtbo \ ++ vc4-kms-v3d-pi5.dtbo \ ++ vc4-kms-vga666.dtbo \ ++ vga666.dtbo \ ++ vl805.dtbo \ ++ w1-gpio.dtbo \ ++ w1-gpio-pi5.dtbo \ ++ w1-gpio-pullup.dtbo \ ++ w1-gpio-pullup-pi5.dtbo \ ++ w5500.dtbo \ ++ watterott-display.dtbo \ ++ waveshare-can-fd-hat-mode-a.dtbo \ ++ waveshare-can-fd-hat-mode-b.dtbo \ ++ wittypi.dtbo \ ++ wm8960-soundcard.dtbo ++ ++targets += dtbs dtbs_install ++targets += $(dtbo-y) ++ ++always-y := $(dtbo-y) ++clean-files := *.dtbo +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +new file mode 100644 +index 000000000000..cca16ab81f9e +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/README +@@ -0,0 +1,5346 @@ ++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. ++ ++ bdaddr Set an alternative Bluetooth address (BDADDR). ++ The value should be a 6-byte hexadecimal value, ++ with or without colon separators, written least- ++ significant-byte first. For example, ++ bdaddr=06:05:04:03:02:01 ++ will set the BDADDR to 01:02:03:04:05:06. ++ ++ button_debounce Set the debounce delay (in ms) on the power/ ++ shutdown button (default 50ms) ++ ++ cam0_reg Enables CAM 0 regulator. ++ Only required on CM1 & 3. ++ ++ cam0_reg_gpio Set GPIO for CAM 0 regulator. ++ Default 31 on CM1, 3, and 4S. ++ Default of GPIO expander 5 on CM4, but override ++ switches to normal GPIO. ++ ++ cam1_reg Enables CAM 1 regulator. ++ Only required on CM1 & 3. ++ ++ cam1_reg_gpio Set GPIO for CAM 1 regulator. ++ Default 3 on CM1, 3, and 4S. ++ Default of GPIO expander 5 on CM4, but override ++ switches to normal GPIO. ++ ++ cooling_fan Enables the Pi 5 cooling fan (enabled ++ automatically by the firmware) ++ ++ drm_fb0_rp1_dpi Assign /dev/fb0 to the RP1 DPI output ++ ++ drm_fb0_rp1_dsi0 Assign /dev/fb0 to the RP1 DSI0 output ++ ++ drm_fb0_rp1_dsi1 Assign /dev/fb0 to the RP1 DSI1 output ++ ++ drm_fb0_vc4 Assign /dev/fb0 to the vc4 outputs ++ ++ drm_fb1_rp1_dpi Assign /dev/fb1 to the RP1 DPI output ++ ++ drm_fb1_rp1_dsi0 Assign /dev/fb1 to the RP1 DSI0 output ++ ++ drm_fb1_rp1_dsi1 Assign /dev/fb1 to the RP1 DSI1 output ++ ++ drm_fb1_vc4 Assign /dev/fb1 to the vc4 outputs ++ ++ drm_fb2_rp1_dpi Assign /dev/fb2 to the RP1 DPI output ++ ++ drm_fb2_rp1_dsi0 Assign /dev/fb2 to the RP1 DSI0 output ++ ++ drm_fb2_rp1_dsi1 Assign /dev/fb2 to the RP1 DSI1 output ++ ++ drm_fb2_vc4 Assign /dev/fb2 to the vc4 outputs ++ ++ eee Enable Energy Efficient Ethernet support for ++ compatible devices (default "on"). See also ++ "tx_lpi_timer". Pi3B+ only. ++ ++ 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/5 (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/5 + + 0=Speed/Activity 1=Speed + 2=Flash activity 3=FDX @@ -10232,40 +16524,108 @@ + 8=Link 9=Activity + + eth_led1 Set mode of LED1 - green on Pi3B+ (default "6"), -+ amber on Pi4 (default "8"). See eth_led0 for ++ amber on Pi4/5 (default "8"). See eth_led0 for + legal values. + + eth_max_speed Set the maximum speed a link is allowed + 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") ++ fan_temp0 Temperature threshold (in millicelcius) for ++ 1st cooling level (default 50000). Pi5 only. ++ fan_temp0_hyst Temperature hysteresis (in millicelcius) for ++ 1st cooling level (default 5000). Pi5 only. ++ fan_temp0_speed Fan PWM setting for 1st cooling level (0-255, ++ default 75). Pi5 only. ++ fan_temp1 Temperature threshold (in millicelcius) for ++ 2nd cooling level (default 60000). Pi5 only. ++ fan_temp1_hyst Temperature hysteresis (in millicelcius) for ++ 2nd cooling level (default 5000). Pi5 only. ++ fan_temp1_speed Fan PWM setting for 2nd cooling level (0-255, ++ default 125). Pi5 only. ++ fan_temp2 Temperature threshold (in millicelcius) for ++ 3rd cooling level (default 67500). Pi5 only. ++ fan_temp2_hyst Temperature hysteresis (in millicelcius) for ++ 3rd cooling level (default 5000). Pi5 only. ++ fan_temp2_speed Fan PWM setting for 3rd cooling level (0-255, ++ default 175). Pi5 only. ++ fan_temp3 Temperature threshold (in millicelcius) for ++ 4th cooling level (default 75000). Pi5 only. ++ fan_temp3_hyst Temperature hysteresis (in millicelcius) for ++ 4th cooling level (default 5000). Pi5 only. ++ fan_temp3_speed Fan PWM setting for 4th cooling level (0-255, ++ default 250). Pi5 only. + -+ i2c_vc Set to "on" to enable the i2c interface -+ usually reserved for the VideoCore processor -+ (default "off") ++ hdmi Set to "off" to disable the HDMI interface ++ (default "on") + + i2c An alias for i2c_arm + ++ i2c_arm Set to "on" to enable the ARM's i2c interface ++ (default "off") ++ + i2c_arm_baudrate Set the baudrate of the ARM's i2c interface + (default "100000") + ++ i2c_baudrate An alias for i2c_arm_baudrate ++ ++ i2c_csi_dsi Set to "on" to enable the i2c_csi_dsi interface ++ ++ i2c_csi_dsi0 Set to "on" to enable the i2c_csi_dsi0 interface ++ ++ i2c_csi_dsi1 Set to "on" to enable the i2c_csi_dsi1 interface ++ ++ i2c_vc Set to "on" to enable the i2c interface ++ usually reserved for the VideoCore processor ++ (default "off") ++ + i2c_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 ++ i2s_dma4 Use to enable 40-bit DMA on the i2s interface ++ (the assigned value doesn't matter) ++ (2711 only) ++ ++ krnbt Set to "off" to disable autoprobing of Bluetooth + driver without need of hciattach/btattach -+ (default "off") ++ (default "on") + + krnbt_baudrate Set the baudrate of the PL011 UART when used + with krnbt=on + ++ nvme Alias for "pciex1" (2712 only) ++ ++ nvmem_cust_rw Allow read/write access to customer otp ++ ++ nvmem_mac_rw Allow read/write access to mac addresses otp ++ ++ nvmem_priv_rw Allow read/write access to customer private otp ++ ++ pcie Set to "off" to disable the PCIe interface ++ (default "on") ++ (2711 only, but not applicable on CM4S) ++ N.B. USB-A ports on 4B are subsequently disabled ++ ++ pcie_tperst_clk_ms Add N milliseconds between PCIe reference clock ++ activation and PERST# deassertion ++ (CM4 and 2712, default "0") ++ ++ pciex1 Set to "on" to enable the external PCIe link ++ (2712 only, default "off") ++ ++ pciex1_gen Sets the PCIe "GEN"/speed for the external PCIe ++ link (2712 only, default "2") ++ ++ pciex1_no_l0s Set to "on" to disable ASPM L0s on the external ++ PCIe link for devices that have broken ++ implementations (2712 only, default "off") ++ ++ pciex1_tperst_clk_ms Alias for pcie_tperst_clk_ms ++ (2712 only, default "0") ++ + spi Set to "on" to enable the spi interfaces + (default "off") + @@ -10276,6 +16636,22 @@ + random Set to "on" to enable the hardware random + number generator (default "on") + ++ rtc Set to "off" to disable the onboard Real Time ++ Clock (2712 only, default "on") ++ ++ rtc_bbat_vchg Set the RTC backup battery charging voltage in ++ microvolts. If set to 0 or not specified, the ++ trickle charger is disabled. ++ (2712 only, default "0") ++ ++ sd Set to "off" to disable the SD card (or eMMC on ++ non-lite SKU of CM4). ++ (default "on") ++ ++ sd_cqe Use to enable Command Queueing on the SD ++ interface for faster Class A2 card performance ++ (Pi 5 only, default "off") ++ + sd_overclock Clock (in MHz) to use when the MMC framework + requests 50MHz + @@ -10296,18 +16672,30 @@ + sdio_overclock Clock (in MHz) to use when the MMC framework + requests 50MHz for the SDIO/WLAN interface. + ++ suspend Make the power button trigger a suspend rather ++ than a power-off (2712 only, default "off") ++ + tx_lpi_timer Set the delay in microseconds between going idle + and entering the low power state (default 600). + Requires EEE to be enabled - see "eee". + + uart0 Set to "off" to disable uart0 (default "on") + ++ uart0_console Move the kernel boot console to UART0 on pins ++ 6, 8 and 10 of the 40-way header (2712 only, ++ default "off") ++ + uart1 Set to "on" or "off" to enable or disable uart1 + (default varies) + + watchdog Set to "on" to enable the hardware watchdog + (default "off") + ++ wifiaddr Set an alternative WiFi MAC address. ++ The value should be a 6-byte hexadecimal value, ++ with or without colon separators, written in the ++ natural (big-endian) order. ++ + act_led_trigger Choose which activity the LED tracks. + Use "heartbeat" for a nice load indicator. + (default "mmc") @@ -10437,6 +16825,16 @@ + cha_gain Set the gain of the Programmable Gain + Amplifier for this channel. (Default 1 sets the + full scale of the channel to 4.096 Volts) ++ i2c0 Choose the I2C0 bus on GPIOs 0&1 ++ i2c_csi_dsi Choose the I2C0 bus on GPIOs 44&45 ++ i2c3 Choose the I2C3 bus (configure with the i2c3 ++ overlay - BCM2711 only) ++ i2c4 Choose the I2C4 bus (configure with the i2c4 ++ overlay - BCM2711 only) ++ i2c5 Choose the I2C5 bus (configure with the i2c5 ++ overlay - BCM2711 only) ++ i2c6 Choose the I2C6 bus (configure with the i2c6 ++ overlay - BCM2711 only) + + Channel parameters can be set for each enabled channel. + A maximum of 4 channels can be enabled (letters a thru d). @@ -10631,6 +17029,38 @@ +Params: <None> + + ++Name: arducam-64mp ++Info: Arducam 64MP camera module. ++ Uses Unicam 1, which is the standard camera connector on most Pi ++ variants. ++Load: dtoverlay=arducam-64mp,<param>=<val> ++Params: rotation Mounting rotation of the camera sensor (0 or ++ 180, default 0) ++ orientation Sensor orientation (0 = front, 1 = rear, ++ 2 = external, default external) ++ media-controller Configure use of Media Controller API for ++ configuring the sensor (default on) ++ cam0 Adopt the default configuration for CAM0 on a ++ Compute Module (CSI0, i2c_vc, and cam0_reg). ++ vcm Select lens driver state. Default is enabled, ++ but vcm=off will disable. ++ ++ ++Name: arducam-pivariety ++Info: Arducam Pivariety camera module. ++ Uses Unicam 1, which is the standard camera connector on most Pi ++ variants. ++Load: dtoverlay=arducam-pivariety,<param>=<val> ++Params: rotation Mounting rotation of the camera sensor (0 or ++ 180, default 0) ++ orientation Sensor orientation (0 = front, 1 = rear, ++ 2 = external, default external) ++ media-controller Configure use of Media Controller API for ++ configuring the sensor (default on) ++ cam0 Adopt the default configuration for CAM0 on a ++ Compute Module (CSI0, i2c_vc, and cam0_reg). ++ ++ +Name: at86rf233 +Info: Configures the Atmel AT86RF233 802.15.4 low-power WPAN transceiver, + connected to spi0.0 @@ -10650,6 +17080,12 @@ + is paused or stopped (default off) + + ++Name: audioinjector-bare-i2s ++Info: Configures the audioinjector.net audio bare i2s soundcard ++Load: dtoverlay=audioinjector-bare-i2s ++Params: <None> ++ ++ +Name: audioinjector-isolated-soundcard +Info: Configures the audioinjector.net isolated soundcard +Load: dtoverlay=audioinjector-isolated-soundcard @@ -10681,10 +17117,14 @@ +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) ++ enable_jack Don't switch off the audio jack output. Does ++ nothing on BCM2711 (default off) + pins_12_13 Select GPIOs 12 & 13 (default) + pins_18_19 Select GPIOs 18 & 19 ++ pins_40_41 Select GPIOs 40 & 41 (not available on CM4, used ++ for other purposes) ++ pins_40_45 Select GPIOs 40 & 45 (don't use on BCM2711 - the ++ pins are on different controllers) + + +Name: balena-fin @@ -10694,11 +17134,125 @@ +Params: <None> + + ++Name: bcm2712d0 ++Info: Overlay encapsulating the BCM2712 C0->D0 differences ++Load: dtoverlay=bcm2712d0 ++Params: <None> ++ ++ +Name: bmp085_i2c-sensor +Info: This overlay is now deprecated - see i2c-sensor +Load: <Deprecated> + + ++Name: camera-mux-2port ++Info: Configures a 2 port camera multiplexer ++ Note that currently ALL IMX290 modules share a common clock, therefore ++ all modules will need to have the same clock frequency. ++Load: dtoverlay=camera-mux-2port,<param>=<val> ++Params: cam0-arducam-64mp Select Arducam64MP for camera on port 0 ++ cam0-imx219 Select IMX219 for camera on port 0 ++ cam0-imx258 Select IMX258 for camera on port 0 ++ cam0-imx290 Select IMX290 for camera on port 0 ++ cam0-imx477 Select IMX477 for camera on port 0 ++ cam0-imx519 Select IMX519 for camera on port 0 ++ cam0-imx708 Select IMX708 for camera on port 0 ++ cam0-ov2311 Select OV2311 for camera on port 0 ++ cam0-ov5647 Select OV5647 for camera on port 0 ++ cam0-ov64a40 Select OV64A40 for camera on port 0 ++ cam0-ov7251 Select OV7251 for camera on port 0 ++ cam0-ov9281 Select OV9281 for camera on port 0 ++ cam0-imx290-clk-freq Set clock frequency for an IMX290 on port 0 ++ cam1-arducam-64mp Select Arducam64MP for camera on port 1 ++ cam1-imx219 Select IMX219 for camera on port 1 ++ cam1-imx258 Select IMX258 for camera on port 1 ++ cam1-imx290 Select IMX290 for camera on port 1 ++ cam1-imx477 Select IMX477 for camera on port 1 ++ cam1-imx519 Select IMX519 for camera on port 1 ++ cam1-imx708 Select IMX708 for camera on port 1 ++ cam1-ov2311 Select OV2311 for camera on port 1 ++ cam1-ov5647 Select OV5647 for camera on port 1 ++ cam1-ov64a40 Select OV64A40 for camera on port 1 ++ cam1-ov7251 Select OV7251 for camera on port 1 ++ cam1-ov9281 Select OV9281 for camera on port 1 ++ cam1-imx290-clk-freq Set clock frequency for an IMX290 on port 1 ++ cam0-sync-source Set camera on port 0 as vsync source ++ cam0-sync-sink Set camera on port 0 as vsync sink ++ cam1-sync-source Set camera on port 1 as vsync source ++ cam1-sync-sink Set camera on port 1 as vsync sink ++ ++ cam0 Connect the mux to CAM0 port (default is CAM1) ++ ++ ++Name: camera-mux-4port ++Info: Configures a 4 port camera multiplexer ++ Note that currently ALL IMX290 modules share a common clock, therefore ++ all modules will need to have the same clock frequency. ++Load: dtoverlay=camera-mux-4port,<param>=<val> ++Params: cam0-arducam-64mp Select Arducam64MP for camera on port 0 ++ cam0-imx219 Select IMX219 for camera on port 0 ++ cam0-imx258 Select IMX258 for camera on port 0 ++ cam0-imx290 Select IMX290 for camera on port 0 ++ cam0-imx477 Select IMX477 for camera on port 0 ++ cam0-imx519 Select IMX519 for camera on port 0 ++ cam0-imx708 Select IMX708 for camera on port 0 ++ cam0-ov2311 Select OV2311 for camera on port 0 ++ cam0-ov5647 Select OV5647 for camera on port 0 ++ cam0-ov64a40 Select OV64A40 for camera on port 0 ++ cam0-ov7251 Select OV7251 for camera on port 0 ++ cam0-ov9281 Select OV9281 for camera on port 0 ++ cam0-imx290-clk-freq Set clock frequency for an IMX290 on port 0 ++ cam1-arducam-64mp Select Arducam64MP for camera on port 1 ++ cam1-imx219 Select IMX219 for camera on port 1 ++ cam1-imx258 Select IMX258 for camera on port 1 ++ cam1-imx290 Select IMX290 for camera on port 1 ++ cam1-imx477 Select IMX477 for camera on port 1 ++ cam1-imx519 Select IMX519 for camera on port 1 ++ cam1-imx708 Select IMX708 for camera on port 1 ++ cam1-ov2311 Select OV2311 for camera on port 1 ++ cam1-ov5647 Select OV5647 for camera on port 1 ++ cam1-ov64a40 Select OV64A40 for camera on port 1 ++ cam1-ov7251 Select OV7251 for camera on port 1 ++ cam1-ov9281 Select OV9281 for camera on port 1 ++ cam1-imx290-clk-freq Set clock frequency for an IMX290 on port 1 ++ cam2-arducam-64mp Select Arducam64MP for camera on port 2 ++ cam2-imx219 Select IMX219 for camera on port 2 ++ cam2-imx258 Select IMX258 for camera on port 2 ++ cam2-imx290 Select IMX290 for camera on port 2 ++ cam2-imx477 Select IMX477 for camera on port 2 ++ cam2-imx519 Select IMX519 for camera on port 2 ++ cam2-imx708 Select IMX708 for camera on port 2 ++ cam2-ov2311 Select OV2311 for camera on port 2 ++ cam2-ov5647 Select OV5647 for camera on port 2 ++ cam2-ov64a40 Select OV64A40 for camera on port 2 ++ cam2-ov7251 Select OV7251 for camera on port 2 ++ cam2-ov9281 Select OV9281 for camera on port 2 ++ cam2-imx290-clk-freq Set clock frequency for an IMX290 on port 2 ++ cam3-arducam-64mp Select Arducam64MP for camera on port 3 ++ cam3-imx219 Select IMX219 for camera on port 3 ++ cam3-imx258 Select IMX258 for camera on port 3 ++ cam3-imx290 Select IMX290 for camera on port 3 ++ cam3-imx477 Select IMX477 for camera on port 3 ++ cam3-imx519 Select IMX519 for camera on port 3 ++ cam3-imx708 Select IMX708 for camera on port 3 ++ cam3-ov2311 Select OV2311 for camera on port 3 ++ cam3-ov5647 Select OV5647 for camera on port 3 ++ cam3-ov64a40 Select OV64A40 for camera on port 3 ++ cam3-ov7251 Select OV7251 for camera on port 3 ++ cam3-ov9281 Select OV9281 for camera on port 3 ++ cam3-imx290-clk-freq Set clock frequency for an IMX290 on port 3 ++ cam0-sync-source Set camera on port 0 as vsync source ++ cam0-sync-sink Set camera on port 0 as vsync sink ++ cam1-sync-source Set camera on port 1 as vsync source ++ cam1-sync-sink Set camera on port 1 as vsync sink ++ cam2-sync-source Set camera on port 2 as vsync source ++ cam2-sync-sink Set camera on port 2 as vsync sink ++ cam3-sync-source Set camera on port 3 as vsync source ++ cam3-sync-sink Set camera on port 3 as vsync sink ++ ++ cam0 Connect the mux to CAM0 port (default is CAM1) ++ ++ +Name: cap1106 +Info: Enables the ability to use the cap1106 touch sensor as a keyboard +Load: dtoverlay=cap1106,<param>=<val> @@ -10711,6 +17265,28 @@ +Params: <None> + + ++Name: cirrus-wm5102 ++Info: Configures the Cirrus Logic Audio Card ++Load: dtoverlay=cirrus-wm5102 ++Params: <None> ++ ++ ++Name: cm-swap-i2c0 ++Info: Largely for Compute Modules 1&3 where the original instructions for ++ adding a camera used GPIOs 0&1 for CAM1 and 28&29 for CAM0, whilst all ++ other platforms use 28&29 (or 44&45) for CAM1. ++ The default assignment through using this overlay is for ++ i2c0 to use 28&29, and i2c10 (aka i2c_csi_dsi) to use 28&29, but the ++ overrides allow this to be changed. ++Load: dtoverlay=cm-swap-i2c0,<param>=<val> ++Params: i2c0-gpio0 Use GPIOs 0&1 for i2c0 ++ i2c0-gpio28 Use GPIOs 28&29 for i2c0 (default) ++ i2c0-gpio44 Use GPIOs 44&45 for i2c0 ++ i2c10-gpio0 Use GPIOs 0&1 for i2c0 (default) ++ i2c10-gpio28 Use GPIOs 28&29 for i2c0 ++ i2c10-gpio44 Use GPIOs 44&45 for i2c0 ++ ++ +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. @@ -10728,12 +17304,27 @@ + cma-default Use upstream's default value + + ++Name: crystalfontz-cfa050_pi_m ++Info: Configures the Crystalfontz CFA050-PI-M series of Raspberry Pi CM4 ++ based modules using the CFA7201280A0_050Tx 7" TFT LCD displays, ++ with or without capacitive touch screen. ++ Requires use of vc4-kms-v3d. ++Load: dtoverlay=crystalfontz-cfa050_pi_m,<param>=<val> ++Params: captouch Enable capacitive touch display ++ ++ +Name: cutiepi-panel +Info: 8" TFT LCD display and touch panel used by cutiepi.io +Load: dtoverlay=cutiepi-panel +Params: <None> + + ++Name: dacberry400 ++Info: Configures the dacberry400 add on soundcard ++Load: dtoverlay=dacberry400 ++Params: <None> ++ ++ +Name: dht11 +Info: Overlay for the DHT11/DHT21/DHT22 humidity/temperature sensors + Also sometimes found with the part number(s) AM230x. @@ -10742,6 +17333,12 @@ + (default 4) + + ++Name: dionaudio-kiwi ++Info: Configures the Dion Audio KIWI STREAMER ++Load: dtoverlay=dionaudio-kiwi ++Params: <None> ++ ++ +Name: dionaudio-loco +Info: Configures the Dion Audio LOCO DAC-AMP +Load: dtoverlay=dionaudio-loco @@ -10768,20 +17365,34 @@ + + +Name: disable-bt -+Info: Disable onboard Bluetooth on Pi 3B, 3B+, 3A+, 4B and Zero W, restoring -+ UART0/ttyAMA0 over GPIOs 14 & 15. -+ N.B. To disable the systemd service that initialises the modem so it -+ doesn't use the UART, use 'sudo systemctl disable hciuart'. ++Info: Disable onboard Bluetooth on Bluetooth-capable Raspberry Pis. On Pis ++ prior to Pi 5 this restores UART0/ttyAMA0 over GPIOs 14 & 15. +Load: dtoverlay=disable-bt +Params: <None> + + ++Name: disable-bt-pi5 ++Info: See disable-bt ++ ++ ++Name: disable-emmc2 ++Info: Disable EMMC2 controller on BCM2711. ++ The allows the onboard EMMC storage on Compute Module 4 to be disabled ++ e.g. if a fault has occurred. ++Load: dtoverlay=disable-emmc2 ++Params: <None> ++ ++ +Name: disable-wifi -+Info: Disable onboard WLAN on Pi 3B, 3B+, 3A+, 4B and Zero W. ++Info: Disable onboard WLAN on WiFi-capable Raspberry Pis. +Load: dtoverlay=disable-wifi +Params: <None> + + ++Name: disable-wifi-pi5 ++Info: See disable-wifi ++ ++ +Name: dpi18 +Info: Overlay for a generic 18-bit DPI display + This uses GPIOs 0-21 (so no I2C, uart etc.), and activates the output @@ -10881,9 +17492,11 @@ + + +Name: edt-ft5406 -+Info: Overlay for the EDT FT5406 touchscreen on the CSI/DSI I2C interface. ++Info: Overlay for the EDT FT5406 touchscreen. + This works with the Raspberry Pi 7" touchscreen when not being polled + by the firmware. ++ By default the overlay uses the i2c_csi_dsi I2C interface, but this ++ can be overridden + You MUST use either "disable_touchscreen=1" or "ignore_lcd=1" in + config.txt to stop the firmware polling the touchscreen. +Load: dtoverlay=edt-ft5406,<param>=<val> @@ -10892,6 +17505,19 @@ + invx Touchscreen inverted x axis + invy Touchscreen inverted y axis + swapxy Touchscreen swapped x y axis ++ i2c0 Choose the I2C0 bus on GPIOs 0&1 ++ i2c1 Choose the I2C1 bus on GPIOs 2&3 ++ i2c3 Choose the I2C3 bus (configure with the i2c3 ++ overlay - BCM2711 only) ++ i2c4 Choose the I2C4 bus (configure with the i2c4 ++ overlay - BCM2711 only) ++ i2c5 Choose the I2C5 bus (configure with the i2c5 ++ overlay - BCM2711 only) ++ i2c6 Choose the I2C6 bus (configure with the i2c6 ++ overlay - BCM2711 only) ++ addr Sets the address for the touch controller. Note ++ that the device must be configured to use the ++ specified address. + + +Name: enc28j60 @@ -11060,6 +17686,26 @@ +Params: fsm_debug Enable debug logging (default off) + + ++Name: gc9a01 ++Info: Enables GalaxyCore's GC9A01 single chip driver based displays on ++ SPI0 as fb1, using GPIOs DC=25, RST=27 and BL=18 (physical ++ GPIO header pins 22, 13 and 12 respectively) in addition to the ++ SPI0 pins DIN=10, CLK=11 and CS=8 (physical GPIO header pins 19, ++ 23 and 24 respectively). ++Load: dtoverlay=gc9a01,<param>=<val> ++Params: speed Display SPI bus speed ++ ++ rotate Display rotation {0,90,180,270} ++ ++ width Width of the display ++ ++ height Height of the display ++ ++ fps Delay between frame updates ++ ++ debug Debug output level {0-7} ++ ++ +Name: ghost-amp +Info: An overlay for the Ghost amplifier. +Load: dtoverlay=ghost-amp,<param>=<val> @@ -11081,12 +17727,40 @@ +Params: <None> + + ++Name: gpio-charger ++Info: This is a generic overlay for detecting charger with GPIO. ++Load: dtoverlay=gpio-charger,<param>=<val> ++Params: gpio GPIO pin to trigger on (default 4) ++ active_low When this is 1 (active low), a falling ++ edge generates a charging event and a ++ rising edge generates a discharging event. ++ When this is 0 (active high), this is ++ reversed. The default is 0 (active high) ++ gpio_pull Desired pull-up/down state (off, down, up) ++ Default is "down". ++ type Set a charger type for the pin. (Default: mains) ++ ++ +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) ++ hyst Temperature delta (in millicelcius) below ++ temp at which the fan will drop to minrpm ++ (default 10000) ++ ++ ++Name: gpio-hog ++Info: Activate a "hog" for a GPIO - request that the kernel configures it as ++ an output, driven low or high as indicated by the presence or absence ++ of the active_low parameter. Note that a hogged GPIO is not available ++ to other drivers or for gpioset/gpioget. ++Load: dtoverlay=gpio-hog,<param>=<val> ++Params: gpio GPIO pin to hog (default 26) ++ active_low If set, the hog drives the GPIO low (defaults ++ to off - the GPIO is driven high) + + +Name: gpio-ir @@ -11373,7 +18047,7 @@ + responsibility of the user to ensure that + the Digital volume control is set to a value + that does not result in clipping/distortion!) -+ slave Force DAC+ Pro into slave mode, using Pi as ++ slave Force AMP100 into slave mode, using Pi as + master for bit clock and frame clock. + leds_off If set to 'true' the onboard indicator LEDs + are switched off at all times. @@ -11384,12 +18058,52 @@ + Will be overwritten by ALSA user settings. + + ++Name: hifiberry-amp3 ++Info: Configures the HifiBerry Amp3 audio card ++Load: dtoverlay=hifiberry-amp3 ++Params: <None> ++ ++ ++Name: hifiberry-amp4pro ++Info: Configures the HifiBerry AMP4 Pro audio card ++Load: dtoverlay=hifiberry-amp4pro,<param>=<val> ++Params: 24db_digital_gain Allow gain to be applied via the TAS5756 ++ Digital volume control. Enable with ++ "dtoverlay=hifiberry-amp4pro,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 the amp 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 it 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-dac8x ++Info: Configures the HifiBerry DAC8X audio cards (only on Pi5) ++Load: dtoverlay=hifiberry-dac8x ++Params: <None> ++ ++ +Name: hifiberry-dacplus +Info: Configures the HifiBerry DAC+ audio card +Load: dtoverlay=hifiberry-dacplus,<param>=<val> @@ -11407,12 +18121,54 @@ + responsibility of the user to ensure that + the Digital volume control is set to a value + that does not result in clipping/distortion!) -+ slave Force DAC+ Pro into slave mode, using Pi as ++ slave Force DAC+ into slave mode, using Pi as + master for bit clock and frame clock. + leds_off If set to 'true' the onboard indicator LEDs + are switched off at all times. + + ++Name: hifiberry-dacplus-pro ++Info: Configures the HifiBerry DAC+ PRO audio card (onboard clocks) ++Load: dtoverlay=hifiberry-dacplus-pro,<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!) ++ leds_off If set to 'true' the onboard indicator LEDs ++ are switched off at all times. ++ ++ ++Name: hifiberry-dacplus-std ++Info: Configures the HifiBerry DAC+ standard audio card (no onboard clocks) ++Load: dtoverlay=hifiberry-dacplus-std,<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!) ++ 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> @@ -11430,8 +18186,6 @@ + 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. + @@ -11478,7 +18232,7 @@ + + +Name: hifiberry-digi-pro -+Info: Configures the HifiBerry Digi+ Pro audio card ++Info: Configures the HifiBerry Digi+ Pro and Digi2 Pro audio card +Load: dtoverlay=hifiberry-digi-pro +Params: <None> + @@ -11558,6 +18312,51 @@ +Params: <None> + + ++Name: i2c-fan ++Info: Adds support for a number of I2C fan controllers ++Load: dtoverlay=i2c-fan,<param>=<val> ++Params: addr Sets the address for the fan controller. Note ++ that the device must be configured to use the ++ specified address. ++ ++ i2c0 Choose the I2C0 bus on GPIOs 0&1 ++ ++ i2c_csi_dsi Choose the I2C0 bus on GPIOs 44&45 ++ ++ i2c3 Choose the I2C3 bus (configure with the i2c3 ++ overlay - BCM2711 only) ++ ++ i2c4 Choose the I2C4 bus (configure with the i2c4 ++ overlay - BCM2711 only) ++ ++ i2c5 Choose the I2C5 bus (configure with the i2c5 ++ overlay - BCM2711 only) ++ ++ i2c6 Choose the I2C6 bus (configure with the i2c6 ++ overlay - BCM2711 only) ++ ++ minpwm PWM setting for the fan when the SoC is below ++ mintemp (range 0-255. default 0) ++ maxpwm PWM setting for the fan when the SoC is above ++ maxtemp (range 0-255. default 255) ++ midtemp Temperature (in millicelcius) at which the fan ++ begins to speed up (default 50000) ++ ++ midtemp_hyst Temperature delta (in millicelcius) below ++ mintemp at which the fan will drop to minrpm ++ (default 2000) ++ ++ maxtemp Temperature (in millicelcius) at which the fan ++ will be held at maxrpm (default 70000) ++ ++ maxtemp_hyst Temperature delta (in millicelcius) below ++ maxtemp at which the fan begins to slow down ++ (default 2000) ++ ++ emc2301 Select the Microchip EMC230x controller family ++ - EMC2301, EMC2302, EMC2303, EMC2305. ++ ++ +Name: i2c-gpio +Info: Adds support for software i2c controller on gpio pins +Load: dtoverlay=i2c-gpio,<param>=<val> @@ -11587,6 +18386,28 @@ + + addr Change I2C address of the device (default 0x70) + ++ base Set an explicit base value for the channel bus ++ numbers ++ ++ i2c0 Choose the I2C0 bus on GPIOs 0&1 ++ ++ i2c_csi_dsi Choose the I2C0 bus on GPIOs 44&45 ++ ++ i2c3 Choose the I2C3 bus (configure with the i2c3 ++ overlay - BCM2711 only) ++ ++ i2c4 Choose the I2C3 bus (configure with the i2c3 ++ overlay - BCM2711 only) ++ ++ i2c5 Choose the I2C5 bus (configure with the i2c4 ++ overlay - BCM2711 only) ++ ++ i2c6 Choose the I2C6 bus (configure with the i2c6 ++ overlay - BCM2711 only) ++ ++ disconnect_on_idle Force the mux to disconnect all child buses ++ after every transaction. ++ + + The i2c-mux-pca9548a overlay has been deleted. See i2c-mux. + @@ -11595,6 +18416,16 @@ +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) ++ i2c0 Choose the I2C0 bus on GPIOs 0&1 ++ i2c_csi_dsi Choose the I2C0 bus on GPIOs 44&45 ++ i2c3 Choose the I2C3 bus (configure with the i2c3 ++ overlay - BCM2711 only) ++ i2c4 Choose the I2C3 bus (configure with the i2c3 ++ overlay - BCM2711 only) ++ i2c5 Choose the I2C5 bus (configure with the i2c4 ++ overlay - BCM2711 only) ++ i2c6 Choose the I2C6 bus (configure with the i2c6 ++ overlay - BCM2711 only) + + +Name: i2c-rtc @@ -11624,6 +18455,8 @@ + + pcf2129 Select the PCF2129 device + ++ pcf2131 Select the PCF2131 device ++ + pcf85063 Select the PCF85063 device + + pcf85063a Select the PCF85063A device @@ -11638,6 +18471,10 @@ + + rv3028 Select the Micro Crystal RV3028 device + ++ rv3032 Select the Micro Crystal RV3032 device ++ ++ rv8803 Select the Micro Crystal RV8803 device ++ + sd3078 Select the ZXW Shenzhen whwave SD3078 device + + s35390a Select the ABLIC S35390A device @@ -11646,6 +18483,18 @@ + + i2c_csi_dsi Choose the I2C0 bus on GPIOs 44&45 + ++ i2c3 Choose the I2C3 bus (configure with the i2c3 ++ overlay - BCM2711 only) ++ ++ i2c4 Choose the I2C3 bus (configure with the i2c3 ++ overlay - BCM2711 only) ++ ++ i2c5 Choose the I2C5 bus (configure with the i2c4 ++ overlay - BCM2711 only) ++ ++ i2c6 Choose the I2C6 bus (configure with the i2c6 ++ overlay - BCM2711 only) ++ + addr Sets the address for the RTC. Note that the + device must be configured to use the specified + address. @@ -11657,13 +18506,21 @@ + "schottky" (ABx80x and RV1805 only) + + trickle-resistor-ohms Resistor value for trickle charge (DS1339, -+ ABx80x, RV1805, RV3028) ++ ABx80x, BQ32000, RV1805, RV3028, RV3032) ++ ++ trickle-voltage-mv Charge pump voltage for trickle charge (RV3032) + + wakeup-source Specify that the RTC can be used as a wakeup + source + + backup-switchover-mode Backup power supply switch mode. Must be 0 for -+ off or 1 for Vdd < VBackup (RV3028 only) ++ "Switchover disabled", 1 for "Direct Switching" ++ (if Vdd < VBackup), 2 for "Standby ++ Mode" (if Vdd < Vbackup, ++ does not draw current) or 3 for ++ "Level Switching" (if Vdd < Vbackup ++ and Vdd < Vddsw and Vbackup > Vddsw) ++ (RV3028, RV3032) + + +Name: i2c-rtc-gpio @@ -11694,6 +18551,8 @@ + + pcf2129 Select the PCF2129 device + ++ pcf2131 Select the PCF2131 device ++ + pcf85063 Select the PCF85063 device + + pcf85063a Select the PCF85063A device @@ -11708,6 +18567,10 @@ + + rv3028 Select the Micro Crystal RV3028 device + ++ rv3032 Select the Micro Crystal RV3032 device ++ ++ rv8803 Select the Micro Crystal RV8803 device ++ + sd3078 Select the ZXW Shenzhen whwave SD3078 device + + s35390a Select the ABLIC S35390A device @@ -11723,13 +18586,21 @@ + "schottky" (ABx80x and RV1805 only) + + trickle-resistor-ohms Resistor value for trickle charge (DS1339, -+ ABx80x, RV1805, RV3028) ++ ABx80x, BQ32000, RV1805, RV3028, RV3032) ++ ++ trickle-voltage-mv Charge pump voltage for trickle charge (RV3032) + + wakeup-source Specify that the RTC can be used as a wakeup + source + + backup-switchover-mode Backup power supply switch mode. Must be 0 for -+ off or 1 for Vdd < VBackup (RV3028 only) ++ "Switchover disabled", 1 for "Direct Switching" ++ (if Vdd < VBackup), 2 for "Standby ++ Mode" (if Vdd < Vbackup, ++ does not draw current) or 3 for ++ "Level Switching" (if Vdd < Vbackup ++ and Vdd < Vddsw and Vbackup > Vddsw) ++ (RV3028, RV3032) + + i2c_gpio_sda GPIO used for I2C data (default "23") + @@ -11743,9 +18614,17 @@ +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 ++Params: addr Set the address for the ADT7410, BH1750, BME280, ++ BME680, BMP280, BMP380, CCS811, DS1621, HDC100X, ++ JC42, LM75, MCP980x, MPU6050, MPU9250, MS5637, ++ MS5803, MS5805, MS5837, MS8607, SHT3x or TMP102 ++ ++ adt7410 Select the Analog Devices ADT7410 and ADT7420 ++ temperature sensors ++ Valid address 0x48-0x4b, default 0x48 ++ ++ aht10 Select the Aosong AHT10 temperature and humidity ++ sensor + + bh1750 Select the Rohm BH1750 ambient light sensor + Valid addresses 0x23 or 0x5c, default 0x23 @@ -11763,6 +18642,12 @@ + bmp280 Select the Bosch Sensortronic BMP280 + Valid addresses 0x76-0x77, default 0x76 + ++ bmp380 Select the Bosch Sensortronic BMP380 ++ Valid addresses 0x76-0x77, default 0x76 ++ ++ bno055 Select the Bosch Sensortronic BNO055 IMU ++ Valid address 0x28-0x29, default 0x29 ++ + ccs811 Select the AMS CCS811 digital gas sensor + Valid addresses 0x5a-0x5b, default 0x5b + @@ -11774,8 +18659,17 @@ + + htu21 Select the HTU21 temperature and humidity sensor + -+ int_pin Set the GPIO to use for interrupts (max30102 -+ only) ++ int_pin Set the GPIO to use for interrupts (max30102, ++ mpu6050 and mpu9250 only) ++ ++ jc42 Select any of the many JEDEC JC42.4-compliant ++ temperature sensors, including: ++ ADT7408, AT30TS00, CAT34TS02, CAT6095, ++ MAX6604, MCP9804, MCP9805, MCP9808, ++ MCP98242, MCP98243, MCP98244, MCP9843, ++ SE97, SE98, STTS424(E), STTS2002, STTS3000, ++ TSE2002, TSE2004, TS3000, and TS3001. ++ The default address is 0x18. + + lm75 Select the Maxim LM75 temperature sensor + Valid addresses 0x48-0x4f, default 0x4f @@ -11788,8 +18682,47 @@ + max30102 Select the Maxim Integrated MAX30102 heart-rate + and blood-oxygen sensor + -+ sht3x Select the Sensiron SHT3x temperature and -+ humidity sensor. Valid addresses 0x44-0x45, ++ mcp980x Select the Maxim MCP980x range of temperature ++ sensors (i.e. MCP9800, MCP9801, MCP9802 and ++ MCP9803). N.B. For MCP9804, MCP9805 and MCP9808, ++ use the "jc42" option. ++ Valid addresses are 0x18-0x1f (default 0x18) ++ ++ mpu6050 Select the InvenSense MPU6050 IMU. Valid ++ valid addresses are 0x68 and 0x69 (default 0x68) ++ ++ mpu9250 Select the InvenSense MPU9250 IMU. Valid ++ valid addresses are 0x68 and 0x69 (default 0x68) ++ ++ ms5637 Select the Measurement Specialities MS5637 ++ pressure and temperature sensor. ++ ++ ms5803 Select the Measurement Specialities MS5803 ++ pressure and temperature sensor. ++ ++ ms5805 Select the Measurement Specialities MS5805 ++ pressure and temperature sensor. ++ ++ ms5837 Select the Measurement Specialities MS5837 ++ pressure and temperature sensor. ++ ++ ms8607 Select the Measurement Specialities MS8607 ++ pressure and temperature sensor. ++ ++ no_timeout Disable the SMBUS timeout. N.B. Only supported ++ by some jc42 devices - using with an ++ incompatible device can stop it from being ++ activated. ++ ++ reset_pin GPIO to be used to reset the device (bno055 ++ only, disabled by default) ++ ++ sht3x Select the Sensirion SHT3x temperature and ++ humidity sensors. Valid addresses 0x44-0x45, ++ default 0x44 ++ ++ sht4x Select the Sensirion SHT4x temperature and ++ humidity sensors. Valid addresses 0x44-0x45, + default 0x44 + + si7020 Select the Silicon Labs Si7013/20/21 humidity/ @@ -11810,6 +18743,22 @@ + veml6070 Select the Vishay VEML6070 ultraviolet light + sensor + ++ i2c0 Choose the I2C0 bus on GPIOs 0&1 ++ ++ i2c_csi_dsi Choose the I2C0 bus on GPIOs 44&45 ++ ++ i2c3 Choose the I2C3 bus (configure with the i2c3 ++ overlay - BCM2711 only) ++ ++ i2c4 Choose the I2C3 bus (configure with the i2c3 ++ overlay - BCM2711 only) ++ ++ i2c5 Choose the I2C5 bus (configure with the i2c4 ++ overlay - BCM2711 only) ++ ++ i2c6 Choose the I2C6 bus (configure with the i2c6 ++ overlay - BCM2711 only) ++ + +Name: i2c0 +Info: Change i2c0 pin usage. Not all pin combinations are usable on all @@ -11836,6 +18785,15 @@ +Load: <Deprecated> + + ++Name: i2c0-pi5 ++Info: Enable i2c0 (Pi 5 only) ++Load: dtoverlay=i2c0-pi5,<param>=<val> ++Params: pins_0_1 Use GPIOs 0 and 1 (default) ++ pins_8_9 Use GPIOs 8 and 9 ++ baudrate Set the baudrate for the interface (default ++ "100000") ++ ++ +Name: i2c1 +Info: Change i2c1 pin usage. Not all pin combinations are usable on all + platforms - platforms other then Compute Modules can only use this @@ -11852,6 +18810,24 @@ +Load: <Deprecated> + + ++Name: i2c1-pi5 ++Info: Enable i2c1 (Pi 5 only) ++Load: dtoverlay=i2c1-pi5,<param>=<val> ++Params: pins_2_3 Use GPIOs 2 and 3 (default) ++ pins_10_11 Use GPIOs 10 and 11 ++ baudrate Set the baudrate for the interface (default ++ "100000") ++ ++ ++Name: i2c2-pi5 ++Info: Enable i2c2 (Pi 5 only) ++Load: dtoverlay=i2c2-pi5,<param>=<val> ++Params: pins_4_5 Use GPIOs 4 and 5 (default) ++ pins_12_13 Use GPIOs 12 and 13 ++ baudrate Set the baudrate for the interface (default ++ "100000") ++ ++ +Name: i2c3 +Info: Enable the i2c3 bus. BCM2711 only. +Load: dtoverlay=i2c3,<param> @@ -11861,6 +18837,16 @@ + "100000") + + ++Name: i2c3-pi5 ++Info: Enable i2c3 (Pi 5 only) ++Load: dtoverlay=i2c3-pi5,<param>=<val> ++Params: pins_6_7 Use GPIOs 6 and 7 (default) ++ pins_14_15 Use GPIOs 14 and 15 ++ pins_22_23 Use GPIOs 22 and 23 ++ baudrate Set the baudrate for the interface (default ++ "100000") ++ ++ +Name: i2c4 +Info: Enable the i2c4 bus. BCM2711 only. +Load: dtoverlay=i2c4,<param> @@ -11888,6 +18874,12 @@ + "100000") + + ++Name: i2s-dac ++Info: Configures any passive I2S DAC soundcard. ++Load: dtoverlay=i2s-dac ++Params: <None> ++ ++ +Name: i2s-gpio28-31 +Info: move I2S function block to GPIO 28 to 31 +Load: dtoverlay=i2s-gpio28-31 @@ -11918,13 +18910,31 @@ + configuring the sensor (default on) + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). ++ vcm Configure a VCM focus drive on the sensor. ++ ++ ++Name: imx258 ++Info: Sony IMX258 camera module. ++ Uses Unicam 1, which is the standard camera connector on most Pi ++ variants. ++Load: dtoverlay=imx258,<param>=<val> ++Params: rotation Mounting rotation of the camera sensor (0 or ++ 180, default 180) ++ orientation Sensor orientation (0 = front, 1 = rear, ++ 2 = external, default external) ++ media-controller Configure use of Media Controller API for ++ configuring the sensor (default on) ++ cam0 Adopt the default configuration for CAM0 on a ++ Compute Module (CSI0, i2c_vc, and cam0_reg). ++ vcm Configure a VCM focus drive on the sensor. ++ 4lane Enable 4 CSI2 lanes. This requires a Compute ++ Module (1, 3, or 4). + + +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. ++ variants. +Load: dtoverlay=imx290,<param> +Params: 4lane Enable 4 CSI2 lanes. This requires a Compute + Module (1, 3, or 4). @@ -11944,6 +18954,49 @@ + Compute Module (CSI0, i2c_vc, and cam0_reg). + + ++Name: imx296 ++Info: Sony IMX296 camera module. ++ Uses Unicam 1, which is the standard camera connector on most Pi ++ variants. ++Load: dtoverlay=imx296,<param>=<val> ++Params: rotation Mounting rotation of the camera sensor (0 or ++ 180, default 180) ++ orientation Sensor orientation (0 = front, 1 = rear, ++ 2 = external, default external) ++ media-controller Configure use of Media Controller API for ++ configuring the sensor (default on) ++ cam0 Adopt the default configuration for CAM0 on a ++ Compute Module (CSI0, i2c_vc, and cam0_reg). ++ clock-frequency Sets the clock frequency to match that used on ++ the board, which should be one of 54000000 ++ (the default), 37125000 or 74250000. ++ always-on Leave the regulator powered up, to stop the ++ camera clamping I/Os such as XTRIG to 0V. ++ ++ ++Name: imx327 ++Info: Sony IMX327 camera module. ++ Uses Unicam 1, which is the standard camera connector on most Pi ++ variants. ++Load: dtoverlay=imx327,<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. ++ orientation Sensor orientation (0 = front, 1 = rear, ++ 2 = external, default external) ++ rotation Mounting rotation of the camera sensor (0 or ++ 180, default 0) ++ media-controller Configure use of Media Controller API for ++ configuring the sensor (default on) ++ cam0 Adopt the default configuration for CAM0 on a ++ Compute Module (CSI0, i2c_vc, and cam0_reg). ++ ++ +Name: imx378 +Info: Sony IMX378 camera module. + Uses Unicam 1, which is the standard camera connector on most Pi @@ -11957,6 +19010,33 @@ + configuring the sensor (default on) + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). ++ always-on Leave the regulator powered up, to stop the ++ camera clamping I/Os such as XVS to 0V. ++ sync-source Configure as vsync source ++ sync-sink Configure as vsync sink ++ ++ ++Name: imx462 ++Info: Sony IMX462 camera module. ++ Uses Unicam 1, which is the standard camera connector on most Pi ++ variants. ++Load: dtoverlay=imx462,<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. ++ orientation Sensor orientation (0 = front, 1 = rear, ++ 2 = external, default external) ++ rotation Mounting rotation of the camera sensor (0 or ++ 180, default 0) ++ media-controller Configure use of Media Controller API for ++ configuring the sensor (default on) ++ cam0 Adopt the default configuration for CAM0 on a ++ Compute Module (CSI0, i2c_vc, and cam0_reg). + + +Name: imx477 @@ -11972,6 +19052,10 @@ + configuring the sensor (default on) + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). ++ always-on Leave the regulator powered up, to stop the ++ camera clamping I/Os such as XVS to 0V. ++ sync-source Configure as vsync source ++ sync-sink Configure as vsync sink + + +Name: imx519 @@ -11987,6 +19071,39 @@ + configuring the sensor (default on) + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). ++ vcm Select lens driver state. Default is enabled, ++ but vcm=off will disable. ++ ++ ++Name: imx708 ++Info: Sony IMX708 camera module. ++ Uses Unicam 1, which is the standard camera connector on most Pi ++ variants. ++Load: dtoverlay=imx708,<param>=<val> ++Params: rotation Mounting rotation of the camera sensor (0 or ++ 180, default 180) ++ orientation Sensor orientation (0 = front, 1 = rear, ++ 2 = external, default external) ++ vcm Select lens driver state. Default is enabled, ++ but vcm=off will disable. ++ media-controller Configure use of Media Controller API for ++ configuring the sensor (default on) ++ cam0 Adopt the default configuration for CAM0 on a ++ Compute Module (CSI0, i2c_vc, and cam0_reg). ++ link-frequency Allowable link frequency values to use in Hz: ++ 450000000 (default), 447000000, 453000000. ++ ++ ++Name: interludeaudio-analog ++Info: Configures Interlude Audio Analog Hat audio card ++Load: dtoverlay=interludeaudio-analog,<param>=<val> ++Params: gpiopin GPIO pin for codec reset ++ ++ ++Name: interludeaudio-digital ++Info: Configures Interlude Audio Digital Hat audio card ++Load: dtoverlay=interludeaudio-digital ++Params: <None> + + +Name: iqaudio-codec @@ -12046,6 +19163,19 @@ + dai stream name. + + ++Name: iqs550 ++Info: Enables I2C connected Azoteq IQS550 trackpad/touchscreen controller ++ using GPIO 4 (pin 7 on GPIO header) for interrupt. ++Load: dtoverlay=iqs550,<param>=<val> ++Params: interrupt GPIO used for interrupt (default 4) ++ reset GPIO used for reset (optional) ++ 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: irs1125 +Info: Infineon irs1125 TOF camera module. + Uses Unicam 1, which is the standard camera connector on most Pi @@ -12061,9 +19191,11 @@ +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>. ++Params: spi<n>-<m> Enable flash device on SPI<n>, CS#<m> ++ fastr Add fast read capability to the flash device ++ speed Maximum SPI frequency (Hz) ++ flash-spi<n>-<m> Same as spi<n>-<m> (deprecated) ++ flash-fastr-spi<n>-<m> Same as spi<n>->m>,fastr (deprecated) + + +Name: justboom-both @@ -12205,6 +19337,16 @@ + + mcp23008 Configure an MCP23008 instead. + noints Disable the interrupt GPIO line. ++ i2c0 Choose the I2C0 bus on GPIOs 0&1 ++ i2c_csi_dsi Choose the I2C0 bus on GPIOs 44&45 ++ i2c3 Choose the I2C3 bus (configure with the i2c3 ++ overlay - BCM2711 only) ++ i2c4 Choose the I2C4 bus (configure with the i2c4 ++ overlay - BCM2711 only) ++ i2c5 Choose the I2C5 bus (configure with the i2c5 ++ overlay - BCM2711 only) ++ i2c6 Choose the I2C6 bus (configure with the i2c6 ++ overlay - BCM2711 only) + + +Name: mcp23s17 @@ -12331,18 +19473,6 @@ + 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") + @@ -12360,6 +19490,10 @@ +Params: <None> + + ++Name: midi-uart0-pi5 ++Info: See midi-uart0 (this is the Pi 5 version) ++ ++ +Name: midi-uart1 +Info: Configures UART1 (ttyS0) so that a requested 38.4kbaud actually gets + 31.25kbaud, the frequency required for MIDI @@ -12367,29 +19501,45 @@ +Params: <None> + + ++Name: midi-uart1-pi5 ++Info: See midi-uart1 (this is the Pi 5 version) ++ ++ +Name: midi-uart2 -+Info: Configures UART2 (ttyAMA1) so that a requested 38.4kbaud actually gets ++Info: Configures UART2 (ttyAMA2) so that a requested 38.4kbaud actually gets + 31.25kbaud, the frequency required for MIDI +Load: dtoverlay=midi-uart2 +Params: <None> + + ++Name: midi-uart2-pi5 ++Info: See midi-uart2 (this is the Pi 5 version) ++ ++ +Name: midi-uart3 -+Info: Configures UART3 (ttyAMA2) so that a requested 38.4kbaud actually gets ++Info: Configures UART3 (ttyAMA3) so that a requested 38.4kbaud actually gets + 31.25kbaud, the frequency required for MIDI +Load: dtoverlay=midi-uart3 +Params: <None> + + ++Name: midi-uart3-pi5 ++Info: See midi-uart3 (this is the Pi 5 version) ++ ++ +Name: midi-uart4 -+Info: Configures UART4 (ttyAMA3) so that a requested 38.4kbaud actually gets ++Info: Configures UART4 (ttyAMA4) so that a requested 38.4kbaud actually gets + 31.25kbaud, the frequency required for MIDI +Load: dtoverlay=midi-uart4 +Params: <None> + + ++Name: midi-uart4-pi5 ++Info: See midi-uart4 (this is the Pi 5 version) ++ ++ +Name: midi-uart5 -+Info: Configures UART5 (ttyAMA4) so that a requested 38.4kbaud actually gets ++Info: Configures UART5 (ttyAMA5) so that a requested 38.4kbaud actually gets + 31.25kbaud, the frequency required for MIDI +Load: dtoverlay=midi-uart5 +Params: <None> @@ -12407,20 +19557,82 @@ + + +Name: miniuart-bt -+Info: Switch the onboard Bluetooth function on Pi 3B, 3B+, 3A+, 4B and Zero W ++Info: Switch the onboard Bluetooth function of a BT-equipped Raspberry Pi + 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. ++ 15. Note that this option uses a lower baudrate, and should only be used ++ with low-bandwidth peripherals. +Load: dtoverlay=miniuart-bt,<param>=<val> -+Params: krnbt Set to "on" to enable autoprobing of Bluetooth ++Params: krnbt Set to "off" to disable autoprobing of Bluetooth + driver without need of hciattach/btattach + + ++Name: mipi-dbi-spi ++Info: Overlay for SPI-connected MIPI DBI displays using the panel-mipi-dbi ++ driver. The driver will load a file /lib/firmware/panel.bin containing ++ the initialisation commands. ++ ++ Example: ++ dtoverlay=mipi-dbi-spi,spi0-0,speed=70000000 ++ dtparam=width=320,height=240 ++ dtparam=reset-gpio=23,dc-gpio=24 ++ dtparam=backlight-gpio=18 ++ ++ Compared to fbtft panel-mipi-dbi runs pixel data at spi-max-frequency ++ and init commands at 10MHz. This makes it possible to push the envelope ++ without messing up the controller configuration due to command ++ transmission errors. ++ ++ 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. ++ ++ See https://github.com/notro/panel-mipi-dbi/wiki for more info. ++ ++Load: dtoverlay=mipi-dbi-spi,<param>=<val> ++Params: ++ compatible Set the compatible string to load a different ++ firmware file. Both the panel compatible value ++ used to load the firmware file and the value ++ used to load the driver has to be set having a ++ NUL (\0) separator between them. ++ Example: ++ dtparam=compatible=mypanel\0panel-mipi-dbi-spi ++ spi<n>-<m> Configure device at spi<n>, cs<m> ++ (boolean, required) ++ speed SPI bus speed in Hz (default 32000000) ++ cpha Shifted SPI clock phase (CPHA) mode ++ cpol Inverse SPI clock polarity (CPOL) mode ++ write-only Controller is not readable ++ (ie. MISO is not wired up). ++ ++ width Panel width in pixels (required) ++ height Panel height in pixels (required) ++ width-mm Panel width in mm ++ height-mm Panel height in mm ++ x-offset Panel x-offset in controller RAM ++ y-offset Panel y-offset in controller RAM ++ ++ clock-frequency Panel clock frequency in Hz ++ (optional, just informational). ++ ++ reset-gpio GPIO pin to be used for RESET ++ dc-gpio GPIO pin to be used for D/C ++ ++ backlight-gpio GPIO pin to be used for backlight control ++ (default of none). ++ backlight-pwm PWM channel to be used for backlight control ++ (default of none). NB Disables audio headphone ++ output as that also uses PWM. ++ backlight-pwm-chan Choose channel on &pwm node for backlight ++ control (default 0). ++ backlight-pwm-gpio GPIO pin to be used for the PWM backlight. See ++ pwm-2chan for valid options (default 18). ++ backlight-pwm-func Pin function of GPIO used for the PWM backlight. ++ See pwm-2chan for valid options (default 2). ++ backlight-def-brightness ++ Set the default brightness. Normal range 1-16. ++ (default 16). ++ ++ +Name: mlx90640 +Info: Overlay for i2c connected mlx90640 thermal camera +Load: dtoverlay=mlx90640 @@ -12435,10 +19647,10 @@ + + +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) ++Info: This overlay has been deprecated - use "dtoverlay=i2c-sensor,mpu6050" ++ instead. Note that "int_pin" is the new name for the "interrupt" ++ parameter. ++Load: <Deprecated> + + +Name: mz61581 @@ -12457,6 +19669,21 @@ + xohms Touchpanel sensitivity (X-plate resistance) + + ++Name: ov2311 ++Info: Omnivision OV2311 camera module. ++ Uses Unicam 1, which is the standard camera connector on most Pi ++ variants. ++Load: dtoverlay=ov2311,<param>=<val> ++Params: rotation Mounting rotation of the camera sensor (0 or ++ 180, default 0) ++ orientation Sensor orientation (0 = front, 1 = rear, ++ 2 = external, default external) ++ media-controller Configure use of Media Controller API for ++ configuring the sensor (default on) ++ cam0 Adopt the default configuration for CAM0 on a ++ Compute Module (CSI0, i2c_vc, and cam0_reg). ++ ++ +Name: ov5647 +Info: Omnivision OV5647 camera module. + Uses Unicam 1, which is the standard camera connector on most Pi @@ -12470,6 +19697,26 @@ + configuring the sensor (default on) + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). ++ vcm Configure a VCM focus drive on the sensor. ++ ++ ++Name: ov64a40 ++Info: Arducam OV64A40 camera module. ++ Uses Unicam 1, which is the standard camera connector on most Pi ++ variants. ++Load: dtoverlay=ov64a40,<param>=<val> ++Params: rotation Mounting rotation of the camera sensor (0 or ++ 180, default 0) ++ orientation Sensor orientation (0 = front, 1 = rear, ++ 2 = external, default external) ++ media-controller Configure use of Media Controller API for ++ configuring the sensor (default on) ++ cam0 Adopt the default configuration for CAM0 on a ++ Compute Module (CSI0, i2c_vc, and cam0_reg). ++ vcm Select lens driver state. Default is enabled, ++ but vcm=off will disable. ++ link-frequency Allowable link frequency values to use in Hz: ++ 456000000 (default), 360000000 + + +Name: ov7251 @@ -12531,9 +19778,9 @@ + 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) ++ pcal6416 Select the NXP PCAL6416 (16 bit) ++ pcal6524 Select the NXP PCAL6524 (24 bit) ++ pcal9555a Select the NXP PCAL9555A (16 bit) + max7310 Select the Maxim MAX7310 (8 bit) + max7312 Select the Maxim MAX7312 (16 bit) + max7313 Select the Maxim MAX7313 (16 bit) @@ -12549,6 +19796,17 @@ + xra1202 Select the Exar XRA1202 (8 bit) + + ++Name: pcf857x ++Info: NXP PCF857x family of I2C GPIO expanders. ++Load: dtoverlay=pcf857x,<param>=<val> ++Params: addr I2C address of expander. Default ++ depends on model selected. ++ pcf8574 Select the NXP PCF8574 (8 bit) ++ pcf8574a Select the NXP PCF8574A (8 bit) ++ pcf8575 Select the NXP PCF8575 (16 bit) ++ pca8574 Select the NXP PCA8574 (8 bit) ++ ++ +Name: pcie-32bit-dma +Info: Force PCIe config to support 32bit DMA addresses at the expense of + having to bounce buffers. @@ -12556,6 +19814,12 @@ +Params: <None> + + ++Name: pcie-32bit-dma-pi5 ++Info: Force PCIe config to support 32bit DMA addresses at the expense of ++ having to bounce buffers (on the Pi 5). ++Load: dtoverlay=pcie-32bit-dma-pi5 ++Params: <None> ++ + The pcf2127-rtc overlay has been deleted. See i2c-rtc. + + @@ -12647,6 +19911,9 @@ + + xohms Touchpanel sensitivity (X-plate resistance) + ++ drm Select the DRM/KMS driver instead of the FBTFT ++ one ++ + +Name: piscreen2r +Info: PiScreen 2 with resistive TP display by OzzMaker.com @@ -12663,11 +19930,17 @@ + + +Name: pisound -+Info: Configures the Blokas Labs pisound card ++Info: Configures the Blokas Labs Pisound card +Load: dtoverlay=pisound +Params: <None> + + ++Name: pisound-pi5 ++Info: Pi 5 specific overlay override for Blokas Labs Pisound card, see pisound ++Load: dtoverlay=pisound-pi5 ++Params: <None> ++ ++ +Name: pitft22 +Info: Adafruit PiTFT 2.2" screen +Load: dtoverlay=pitft22,<param>=<val> @@ -12679,6 +19952,10 @@ + + debug Debug output level {0-7} + ++ drm Force the use of the mi0283qt DRM driver (by ++ default the ili9340 framebuffer driver will ++ be used in preference if available) ++ + +Name: pitft28-capacitive +Info: Adafruit PiTFT 2.8" capacitive touch screen @@ -12691,6 +19968,10 @@ + + debug Debug output level {0-7} + ++ drm Force the use of the mi0283qt DRM driver (by ++ default the ili9340 framebuffer driver will ++ be used in preference if available) ++ + touch-sizex Touchscreen size x (default 240) + + touch-sizey Touchscreen size y (default 320) @@ -12713,6 +19994,16 @@ + + debug Debug output level {0-7} + ++ drm Force the use of the mi0283qt DRM driver (by ++ default the ili9340 framebuffer driver will ++ be used in preference if available) ++ ++ touch-invx Touchscreen inverted x axis ++ ++ touch-invy Touchscreen inverted y axis ++ ++ touch-swapxy Touchscreen swapped x y axis ++ + +Name: pitft35-resistive +Info: Adafruit PiTFT 3.5" resistive touch screen @@ -12725,6 +20016,16 @@ + + debug Debug output level {0-7} + ++ drm Force the use of the hx8357d DRM driver (by ++ default the fb_hx8357d framebuffer driver will ++ be used in preference if available) ++ ++ touch-invx Touchscreen inverted x axis ++ ++ touch-invy Touchscreen inverted y axis ++ ++ touch-swapxy Touchscreen swapped x y axis ++ + +Name: pps-gpio +Info: Configures the pps-gpio (pulse-per-second time signal via GPIO). @@ -12735,6 +20036,14 @@ + off) + capture_clear Generate clear events on the trailing edge + (default off) ++ pull Desired pull-up/down state (off, down, up) ++ Default is "off". ++ ++ ++Name: proto-codec ++Info: Configures the PROTO Audio Codec card ++Load: dtoverlay=proto-codec ++Params: <None> + + +Name: pwm @@ -12790,6 +20099,24 @@ + func Pin function (default 2 = Alt5) + + ++Name: pwm1 ++Info: Configures one or two PWM channel on PWM1 (BCM2711 only) ++ N.B.: ++ 1) The onboard analogue audio output uses both PWM channels. ++ 2) So be careful mixing audio and PWM. ++ Note that even when only one pin is enabled, both channels are available ++ from the PWM driver, so be careful to use the correct one. ++Load: dtoverlay=pwm1,<param>=<val> ++Params: clock PWM clock frequency (informational) ++ pins_40 Enable channel 0 (PWM1_0) on GPIO 40 ++ pins_41 Enable channel 1 (PWM1_1) on GPIO 41 ++ pins_40_41 Enable channels 0 (PWM1_0) and 1 (PW1_1) on ++ GPIOs 40 and 41 (default) ++ pull_up Enable pull-ups on the PWM pins (default) ++ pull_down Enable pull-downs on the PWM pins ++ pull_off Disable pulls on the PWM pins ++ ++ +Name: qca7000 +Info: in-tech's Evaluation Board for PLC Stamp micro + This uses spi0 and a separate GPIO interrupt to connect the QCA7000. @@ -12809,6 +20136,35 @@ + "115200") + + ++Name: ramoops ++Info: Enable the preservation of crash logs across a reboot. With ++ systemd-pstore enabled (as it is on Raspberry Pi OS) the crash logs ++ are moved to /var/lib/systemd/pstore/ on reboot. ++Load: dtoverlay=ramoops,<param>=<val> ++Params: base-addr Where to place the capture buffer (default ++ 0x0b000000) ++ total-size How much memory to allocate altogether (in ++ bytes - default 64kB) ++ record-size How much space to use for each capture, i.e. ++ total-size / record-size = number of captures ++ (default 16kB) ++ console-size Size of non-panic dmesg captures (default 0) ++ ++ ++Name: ramoops-pi4 ++Info: The version of the ramoops overlay for the Pi 4 family. It should be ++ loaded automatically if dtoverlay=ramoops is specified on a Pi 4. ++Load: dtoverlay=ramoops-pi4,<param>=<val> ++Params: base-addr Where to place the capture buffer (default ++ 0x0b000000) ++ total-size How much memory to allocate altogether (in ++ bytes - default 64kB) ++ record-size How much space to use for each capture, i.e. ++ total-size / record-size = number of captures ++ (default 16kB) ++ console-size Size of non-panic dmesg captures (default 0) ++ ++ +Name: rotary-encoder +Info: Overlay for GPIO connected rotary encoder. +Load: dtoverlay=rotary-encoder,<param>=<val> @@ -12848,34 +20204,95 @@ + + +Name: rpi-cirrus-wm5102 -+Info: Configures the Cirrus Logic Audio Card -+Load: dtoverlay=rpi-cirrus-wm5102 ++Info: This overlay has been renamed to cirrus-wm5102 ++Load: <Deprecated> ++ ++ ++Name: rpi-codeczero ++Info: Configures the Raspberry Pi Codec Zero sound card ++Load: dtoverlay=rpi-codeczero +Params: <None> + + +Name: rpi-dac -+Info: Configures the RPi DAC audio card -+Load: dtoverlay=rpi-dac -+Params: <None> ++Info: This overlay has been renamed to i2s-dac. ++Load: <Deprecated> ++ ++ ++Name: rpi-dacplus ++Info: Configures the Raspberry Pi DAC+ card ++Load: dtoverlay=rpi-dacplus,<param>=<val> ++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec ++ digital volume control. Enable by adding ++ "dtparam=24db_digital_gain" to config.txt ++ before any "dtoverlay" lines. ++ 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: rpi-dacpro ++Info: Configures the Raspberry Pi DAC Pro sound card ++Load: dtoverlay=rpi-dacpro,<param>=<val> ++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec ++ digital volume control. Enable by adding ++ "dtparam=24db_digital_gain" to config.txt ++ before any "dtoverlay" lines. ++ 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: rpi-digiampplus ++Info: Configures the Raspberry Pi DigiAMP+ sound card ++Load: dtoverlay=rpi-digiampplus,<param>=<val> ++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec ++ digital volume control. Enable by adding ++ "dtparam=24db_digital_gain" to config.txt ++ before any "dtoverlay" lines. ++ 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 DigiAMP+ when ++ starting/stopping audio playback (default "on"). ++ unmute_amp If specified, unmute the DigiAMP+ amp once when ++ the DAC driver module loads (default "off"). + + +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} ++Info: This overlay has been renamed to watterott-display ++Load: <Deprecated> + + +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-size-y Touchscreen Y resolution (default 480); + touchscreen-inverted-x Invert touchscreen X coordinates (default 0); + touchscreen-inverted-y Invert touchscreen Y coordinates (default 0); + touchscreen-swapped-x-y Swap X and Y cordinates (default 0); @@ -12900,6 +20317,8 @@ + speeds up (default 55000) + poe_fan_temp3_hyst Temperature delta (in millicelcius) at which + the fan slows down (default 5000) ++ i2c Control the fan via Linux I2C drivers instead of ++ the firmware. + + +Name: rpi-poe-plus @@ -12921,12 +20340,13 @@ + speeds up (default 55000) + poe_fan_temp3_hyst Temperature delta (in millicelcius) at which + the fan slows down (default 5000) ++ i2c Control the fan via Linux I2C drivers instead of ++ the firmware. + + +Name: rpi-proto -+Info: Configures the RPi Proto audio card -+Load: dtoverlay=rpi-proto -+Params: <None> ++Info: This overlay has been renamed to proto-codec. ++Load: <Deprecated> + + +Name: rpi-sense @@ -12935,6 +20355,12 @@ +Params: <None> + + ++Name: rpi-sense-v2 ++Info: Raspberry Pi Sense HAT v2 ++Load: dtoverlay=rpi-sense-v2 ++Params: <None> ++ ++ +Name: rpi-tv +Info: Raspberry Pi TV HAT +Load: dtoverlay=rpi-tv @@ -12942,10 +20368,9 @@ + + +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> ++Info: This overlay has been deprecated and deleted as the V4L2 stateless ++ video decoder driver is enabled by default. ++Load: <Deprecated> + + +Name: rra-digidac1-wm8741-audio @@ -13054,6 +20479,13 @@ +Load: <Deprecated> + + ++Name: sdio-pi5 ++Info: Selects the rp1_mmc0 interface and enables it on GPIOs 22-27. ++ Pi 5 only. ++Load: dtoverlay=sdio-pi5 ++Params: <None> ++ ++ +Name: sdtweak +Info: This overlay is now deprecated. Use the sd_* dtparams in the + base DTB, e.g. "dtoverlay=sdtweak,poll_once" becomes @@ -13188,105 +20620,131 @@ +Info: Enables spi1 with a single chip select (CS) line and associated spidev + dev node. The gpio pin number for the CS line and spidev device node + creation are configurable. -+ N.B.: spi1 is only accessible on devices with a 40pin header, eg: -+ A+, B+, Zero and PI2 B; as well as the Compute Module. ++ N.B.: spi1 is not accessible on old Pis without a 40-pin header. +Load: dtoverlay=spi1-1cs,<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 ++ cs0_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev1.0 (default -+ is 'okay' or enabled). ++ is 'on' or enabled). + + +Name: spi1-2cs +Info: Enables spi1 with two chip select (CS) lines and associated spidev + dev nodes. The gpio pin numbers for the CS lines and spidev device node + creation are configurable. -+ N.B.: spi1 is only accessible on devices with a 40pin header, eg: -+ A+, B+, Zero and PI2 B; as well as the Compute Module. ++ N.B.: spi1 is not accessible on old Pis without a 40-pin header. +Load: dtoverlay=spi1-2cs,<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 ++ cs0_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev1.0 (default -+ is 'okay' or enabled). -+ cs1_spidev Set to 'disabled' to stop the creation of a ++ is 'on' or enabled). ++ cs1_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev1.1 (default -+ is 'okay' or enabled). ++ is 'on' or enabled). + + +Name: spi1-3cs +Info: Enables spi1 with three chip select (CS) lines and associated spidev + dev nodes. The gpio pin numbers for the CS lines and spidev device node + creation are configurable. -+ N.B.: spi1 is only accessible on devices with a 40pin header, eg: -+ A+, B+, Zero and PI2 B; as well as the Compute Module. ++ N.B.: spi1 is not accessible on old Pis without a 40-pin header. +Load: dtoverlay=spi1-3cs,<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 ++ cs0_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev1.0 (default -+ is 'okay' or enabled). -+ cs1_spidev Set to 'disabled' to stop the creation of a ++ is 'on' or enabled). ++ cs1_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev1.1 (default -+ is 'okay' or enabled). -+ cs2_spidev Set to 'disabled' to stop the creation of a ++ is 'on' or enabled). ++ cs2_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev1.2 (default -+ is 'okay' or enabled). ++ is 'on' or enabled). + + +Name: spi2-1cs -+Info: Enables spi2 with a single chip select (CS) line and associated spidev -+ dev node. The gpio pin number for the CS line and spidev device node -+ creation are configurable. -+ N.B.: spi2 is only accessible with the Compute Module. ++Info: Enables spi2 on GPIOs 40-42 with a single chip select (CS) line and ++ associated spidev dev node. The gpio pin number for the CS line and ++ spidev device node creation are configurable. spi2-2cs-pi5 is ++ substituted on a Pi 5. ++ N.B.: spi2 is only accessible with the Compute Module or Pi 5. +Load: dtoverlay=spi2-1cs,<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 ++ cs0_spidev Set to 'off' to stop the creation of a ++ userspace device node /dev/spidev2.0 (default ++ is 'on' or enabled). ++ ++ ++Name: spi2-1cs-pi5 ++Info: Enables spi2 on GPIOs 1-3 with a single chip select (CS) line and ++ associated spidev dev node. The gpio pin number for the CS line and ++ spidev device node creation are configurable. Pi 5 only. ++Load: dtoverlay=spi2-1cs-pi5,<param>=<val> ++Params: cs0_pin GPIO pin for CS0 (default 0). ++ cs0_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev2.0 (default -+ is 'okay' or enabled). ++ is 'on' or enabled). + + +Name: spi2-2cs -+Info: Enables spi2 with two chip select (CS) lines and associated spidev -+ dev nodes. The gpio pin numbers for the CS lines and spidev device node -+ creation are configurable. -+ N.B.: spi2 is only accessible with the Compute Module. ++Info: Enables spi2 on GPIOs 40-42 with two chip select (CS) lines and ++ associated spidev dev nodes. The gpio pin numbers for the CS lines and ++ spidev device node creation are configurable. spi2-2cs-pi5 is ++ substituted on a Pi 5. ++ N.B.: spi2 is only accessible with the Compute Module or Pi 5. +Load: dtoverlay=spi2-2cs,<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 ++ cs0_spidev Set to 'off' to stop the creation of a ++ userspace device node /dev/spidev2.0 (default ++ is 'on' or enabled). ++ cs1_spidev Set to 'off' to stop the creation of a ++ userspace device node /dev/spidev2.1 (default ++ is 'on' or enabled). ++ ++ ++Name: spi2-2cs-pi5 ++Info: Enables spi2 on GPIOs 1-3 with two chip select (CS) lines and ++ associated spidev dev nodes. The gpio pin numbers for the CS lines and ++ spidev device node creation are configurable. Pi 5 only. ++Load: dtoverlay=spi2-2cs-pi5,<param>=<val> ++Params: cs0_pin GPIO pin for CS0 (default 0). ++ cs1_pin GPIO pin for CS1 (default 24). ++ cs0_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev2.0 (default -+ is 'okay' or enabled). -+ cs1_spidev Set to 'disabled' to stop the creation of a ++ is 'on' or enabled). ++ cs1_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev2.1 (default -+ is 'okay' or enabled). ++ is 'on' or enabled). + + +Name: spi2-3cs -+Info: Enables spi2 with three chip select (CS) lines and associated spidev -+ dev nodes. The gpio pin numbers for the CS lines and spidev device node -+ creation are configurable. -+ N.B.: spi2 is only accessible with the Compute Module. ++Info: Enables spi2 on GPIOs 40-42 with three chip select (CS) lines and ++ associated spidev dev nodes. The gpio pin numbers for the CS lines and ++ spidev device node creation are configurable. ++ N.B.: spi2 is only accessible with the Compute Module or Pi 5. +Load: dtoverlay=spi2-3cs,<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 ++ cs0_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev2.0 (default -+ is 'okay' or enabled). -+ cs1_spidev Set to 'disabled' to stop the creation of a ++ is 'on' or enabled). ++ cs1_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev2.1 (default -+ is 'okay' or enabled). -+ cs2_spidev Set to 'disabled' to stop the creation of a ++ is 'on' or enabled). ++ cs2_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev2.2 (default -+ is 'okay' or enabled). ++ is 'on' or enabled). + + +Name: spi3-1cs -+Info: Enables spi3 with a single chip select (CS) line and associated spidev -+ dev node. The gpio pin number for the CS line and spidev device node -+ creation are configurable. BCM2711 only. ++Info: Enables spi3 on GPIOs 1-3 with a single chip select (CS) line and ++ associated spidev dev node. The gpio pin number for the CS line and ++ spidev device node creation are configurable. BCM2711 only, ++ spi3-1cs-pi5 is substituted on Pi 5. +Load: dtoverlay=spi3-1cs,<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 @@ -13294,10 +20752,22 @@ + is 'on' or enabled). + + ++Name: spi3-1cs-pi5 ++Info: Enables spi3 on GPIOs 5-7 with a single chip select (CS) line and ++ associated spidev dev node. The gpio pin number for the CS line and ++ spidev device node creation are configurable. Pi 5 only. ++Load: dtoverlay=spi3-1cs-pi5,<param>=<val> ++Params: cs0_pin GPIO pin for CS0 (default 4). ++ cs0_spidev Set to 'off' to prevent the creation of a ++ userspace device node /dev/spidev3.0 (default ++ is 'on' or enabled). ++ ++ +Name: spi3-2cs -+Info: Enables spi3 with two chip select (CS) lines and associated spidev -+ dev nodes. The gpio pin numbers for the CS lines and spidev device node -+ creation are configurable. BCM2711 only. ++Info: Enables spi3 on GPIO2 1-3 with two chip select (CS) lines and ++ associated spidev dev nodes. The gpio pin numbers for the CS lines and ++ spidev device node creation are configurable. BCM2711 only, ++ spi3-2cs-pi5 is substituted on Pi 5. +Load: dtoverlay=spi3-2cs,<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). @@ -13309,10 +20779,25 @@ + is 'on' or enabled). + + ++Name: spi3-2cs-pi5 ++Info: Enables spi3 on GPIOs 5-7 with two chip select (CS) lines and ++ associated spidev dev nodes. The gpio pin numbers for the CS lines and ++ spidev device node creation are configurable. Pi 5 only. ++Load: dtoverlay=spi3-2cs-pi5,<param>=<val> ++Params: cs0_pin GPIO pin for CS0 (default 4). ++ cs1_pin GPIO pin for CS1 (default 25). ++ cs0_spidev Set to 'off' to prevent the creation of a ++ userspace device node /dev/spidev3.0 (default ++ is 'on' or enabled). ++ cs1_spidev Set to 'off' to prevent the creation of a ++ userspace device node /dev/spidev3.1 (default ++ is 'on' or enabled). ++ ++ +Name: spi4-1cs -+Info: Enables spi4 with a single chip select (CS) line and associated spidev -+ dev node. The gpio pin number for the CS line and spidev device node -+ creation are configurable. BCM2711 only. ++Info: Enables spi4 on GPIOs 5-7 with a single chip select (CS) line and ++ associated spidev dev node. The gpio pin number for the CS line and ++ spidev device node creation are configurable. BCM2711 only. +Load: dtoverlay=spi4-1cs,<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 @@ -13321,9 +20806,9 @@ + + +Name: spi4-2cs -+Info: Enables spi4 with two chip select (CS) lines and associated spidev -+ dev nodes. The gpio pin numbers for the CS lines and spidev device node -+ creation are configurable. BCM2711 only. ++Info: Enables spi4 on GPIOs 5-6 with two chip select (CS) lines and ++ associated spidev dev nodes. The gpio pin numbers for the CS lines and ++ spidev device node creation are configurable. BCM2711 only. +Load: dtoverlay=spi4-2cs,<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). @@ -13336,23 +20821,27 @@ + + +Name: spi5-1cs -+Info: Enables spi5 with a single chip select (CS) line and associated spidev -+ dev node. The gpio pin numbers for the CS lines and spidev device node -+ creation are configurable. BCM2711 only. ++Info: Enables spi5 on GPIOs 13-15 with a single chip select (CS) line and ++ associated spidev dev node. The gpio pin numbers for the CS lines and ++ spidev device node creation are configurable. BCM2711 and Pi 5. +Load: dtoverlay=spi5-1cs,<param>=<val> -+Params: cs0_pin GPIO pin for CS0 (default 12 - BCM SPI5_CE0). ++Params: cs0_pin GPIO pin for CS0 (default 12). + cs0_spidev Set to 'off' to prevent the creation of a + userspace device node /dev/spidev5.0 (default + is 'on' or enabled). + + ++Name: spi5-1cs-pi5 ++Info: See spi5-1cs ++ ++ +Name: spi5-2cs -+Info: Enables spi5 with two chip select (CS) lines and associated spidev -+ dev nodes. The gpio pin numbers for the CS lines and spidev device node -+ creation are configurable. BCM2711 only. ++Info: Enables spi5 on GPIOs 13-15 with two chip select (CS) lines and ++ associated spidev dev nodes. The gpio pin numbers for the CS lines and ++ spidev device node creation are configurable. BCM2711 and Pi 5. +Load: dtoverlay=spi5-2cs,<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). ++Params: cs0_pin GPIO pin for CS0 (default 12). ++ cs1_pin GPIO pin for CS1 (default 26). + cs0_spidev Set to 'off' to prevent the creation of a + userspace device node /dev/spidev5.0 (default + is 'on' or enabled). @@ -13361,6 +20850,10 @@ + is 'on' or enabled). + + ++Name: spi5-2cs-pi5 ++Info: See spi5-2cs ++ ++ +Name: spi6-1cs +Info: Enables spi6 with a single chip select (CS) line and associated spidev + dev node. The gpio pin number for the CS line and spidev device node @@ -13428,6 +20921,8 @@ + 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) ++ inverted Set this if display is inverted and mirrored. ++ (default=not set) + + +Name: ssd1331-spi @@ -13542,6 +21037,14 @@ +Params: <None> + + ++Name: tpm-slb9673 ++Info: Enables support for Infineon SLB9673 Trusted Platform Module add-on ++ boards, which can be used as a secure key storage and hwrng ++ via the I2C protocol. ++Load: dtoverlay=tpm-slb9673 ++Params: <None> ++ ++ +Name: uart0 +Info: Change the pin usage of uart0 +Load: dtoverlay=uart0,<param>=<val> @@ -13553,6 +21056,12 @@ + 7(Alt3) for 32&33, 6(Alt2) for 36&37 + + ++Name: uart0-pi5 ++Info: Enable uart 0 on GPIOs 14-15. Pi 5 only. ++Load: dtoverlay=uart0-pi5,<param> ++Params: ctsrts Enable CTS/RTS on GPIOs 16-17 (default off) ++ ++ +Name: uart1 +Info: Change the pin usage of uart1 +Load: dtoverlay=uart1,<param>=<val> @@ -13561,24 +21070,48 @@ + rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15) + + ++Name: uart1-pi5 ++Info: Enable uart 1 on GPIOs 0-1. Pi 5 only. ++Load: dtoverlay=uart1-pi5,<param> ++Params: ctsrts Enable CTS/RTS on GPIOs 2-3 (default off) ++ ++ +Name: uart2 +Info: Enable uart 2 on GPIOs 0-3. BCM2711 only. +Load: dtoverlay=uart2,<param> +Params: ctsrts Enable CTS/RTS on GPIOs 2-3 (default off) + + ++Name: uart2-pi5 ++Info: Enable uart 2 on GPIOs 4-5. Pi 5 only. ++Load: dtoverlay=uart2-pi5,<param> ++Params: ctsrts Enable CTS/RTS on GPIOs 6-7 (default off) ++ ++ +Name: uart3 +Info: Enable uart 3 on GPIOs 4-7. BCM2711 only. +Load: dtoverlay=uart3,<param> +Params: ctsrts Enable CTS/RTS on GPIOs 6-7 (default off) + + ++Name: uart3-pi5 ++Info: Enable uart 3 on GPIOs 8-9. Pi 5 only. ++Load: dtoverlay=uart3-pi5,<param> ++Params: ctsrts Enable CTS/RTS on GPIOs 10-11 (default off) ++ ++ +Name: uart4 +Info: Enable uart 4 on GPIOs 8-11. BCM2711 only. +Load: dtoverlay=uart4,<param> +Params: ctsrts Enable CTS/RTS on GPIOs 10-11 (default off) + + ++Name: uart4-pi5 ++Info: Enable uart 4 on GPIOs 12-13. Pi 5 only. ++Load: dtoverlay=uart4-pi5,<param> ++Params: ctsrts Enable CTS/RTS on GPIOs 14-15 (default off) ++ ++ +Name: uart5 +Info: Enable uart 5 on GPIOs 12-15. BCM2711 only. +Load: dtoverlay=uart5,<param> @@ -13681,8 +21214,14 @@ + width-mm Define the screen width in mm + height-mm Define the screen height in mm + rgb565 Change to RGB565 output on GPIOs 0-19 ++ rgb565-padhi Change to RGB565 output on GPIOs 0-8, 12-17, and ++ 20-24 ++ bgr666 Change to BGR666 output on GPIOs 0-21. ++ bgr666-padhi Change to BGR666 output on GPIOs 0-9, 12-17, and ++ 20-25 + rgb666-padhi Change to RGB666 output on GPIOs 0-9, 12-17, and + 20-25 ++ bgr888 Change to BGR888 output on GPIOs 0-27 + rgb888 Change to RGB888 output on GPIOs 0-27 + bus-format Override the bus format for a MEDIA_BUS_FMT_* + value. NB also overridden by rgbXXX overrides. @@ -13708,6 +21247,39 @@ + rotate Display rotation {0,90,180,270} (default 0) + + ++Name: vc4-kms-dpi-hyperpixel2r ++Info: Enable the KMS drivers for the Pimoroni HyperPixel2 Round DPI display. ++ Requires vc4-kms-v3d to be loaded. ++Load: dtoverlay=vc4-kms-dpi-hyperpixel2r,<param>=<val> ++Params: disable-touch Disables the touch controller ++ touchscreen-inverted-x Inverts X direction of touch controller ++ touchscreen-inverted-y Inverts Y direction of touch controller ++ touchscreen-swapped-x-y Swaps X & Y axes of touch controller ++ rotate Display rotation {0,90,180,270} (default 0) ++ ++ ++Name: vc4-kms-dpi-hyperpixel4 ++Info: Enable the KMS drivers for the Pimoroni HyperPixel4 DPI display. ++ Requires vc4-kms-v3d to be loaded. ++Load: dtoverlay=vc4-kms-dpi-hyperpixel4,<param>=<val> ++Params: disable-touch Disables the touch controller ++ touchscreen-inverted-x Inverts X direction of touch controller ++ touchscreen-inverted-y Inverts Y direction of touch controller ++ touchscreen-swapped-x-y Swaps X & Y axes of touch controller ++ rotate Display rotation {0,90,180,270} (default 0) ++ ++ ++Name: vc4-kms-dpi-hyperpixel4sq ++Info: Enable the KMS drivers for the Pimoroni HyperPixel4 Square DPI display. ++ Requires vc4-kms-v3d to be loaded. ++Load: dtoverlay=vc4-kms-dpi-hyperpixel4sq,<param>=<val> ++Params: disable-touch Disables the touch controller ++ touchscreen-inverted-x Inverts X direction of touch controller ++ touchscreen-inverted-y Inverts Y direction of touch controller ++ touchscreen-swapped-x-y Swaps X & Y axes of touch controller ++ rotate Display rotation {0,90,180,270} (default 0) ++ ++ +Name: vc4-kms-dpi-panel +Info: Enable a preconfigured KMS DPI panel. + Requires vc4-kms-v3d to be loaded. @@ -13748,6 +21320,67 @@ + invy Touchscreen inverted y axis + swapxy Touchscreen swapped x y axis + disable_touch Disables the touch screen overlay driver ++ dsi0 Use DSI0 and i2c_csi_dsi0 (rather than ++ the default DSI1 and i2c_csi_dsi). ++ ++ ++Name: vc4-kms-dsi-generic ++Info: Enable a generic DSI display under KMS. ++ Default timings are for a 840x480 RGB888 panel. ++ Requires vc4-kms-v3d to be loaded. ++Load: dtoverlay=vc4-kms-dsi-generic,<param>=<val> ++Params: clock-frequency Display clock frequency (Hz) ++ hactive Horizontal active pixels ++ hfp Horizontal front porch ++ hsync Horizontal sync pulse width ++ hbp Horizontal back porch ++ vactive Vertical active lines ++ vfp Vertical front porch ++ vsync Vertical sync pulse width ++ vbp Vertical back porch ++ width-mm Define the screen width in mm ++ height-mm Define the screen height in mm ++ rgb565 Change to RGB565 output ++ rgb666 Change to RGB666 output ++ rgb666p Change to RGB666 output with pixel packing ++ rgb888 Change to RGB888 output, this is the default ++ one-lane Use one DSI lane for data transmission ++ This is the default ++ two-lane Use two DSI lanes for data transmission ++ three-lane Use three DSI lanes for data transmission ++ Only supported on Pi5 and CM ++ four-lane Use four DSI lanes for data transmission ++ Only supported on Pi5 and CM ++ dsi0 Switch DSI port to DSI0 ++ Only supported on Pi5 and CM ++ ++ ++Name: vc4-kms-dsi-ili9881-5inch ++Info: Enable the Raspberry Pi 5" ILI9881 based touchscreen panel. ++ Requires vc4-kms-v3d to be loaded. ++Load: dtoverlay=vc4-kms-dsi-ili9881-5inch,<param> ++Params: sizex Touchscreen size x (default 720) ++ sizey Touchscreen size y (default 1280) ++ invx Touchscreen inverted x axis ++ invy Touchscreen inverted y axis ++ swapxy Touchscreen swapped x y axis ++ disable_touch Disables the touch screen overlay driver ++ dsi0 Use DSI0 and i2c_csi_dsi0 (rather than ++ the default DSI1 and i2c_csi_dsi). ++ ++ ++Name: vc4-kms-dsi-ili9881-7inch ++Info: Enable the Raspberry Pi 7" ILI9881 based touchscreen panel. ++ Requires vc4-kms-v3d to be loaded. ++Load: dtoverlay=vc4-kms-dsi-ili9881-7inch,<param> ++Params: sizex Touchscreen size x (default 720) ++ sizey Touchscreen size y (default 1280) ++ invx Touchscreen inverted x axis ++ invy Touchscreen inverted y axis ++ swapxy Touchscreen swapped x y axis ++ disable_touch Disables the touch screen overlay driver ++ dsi0 Use DSI0 and i2c_csi_dsi0 (rather than ++ the default DSI1 and i2c_csi_dsi). + + +Name: vc4-kms-dsi-lt070me05000 @@ -13771,6 +21404,37 @@ +Params: <None> + + ++Name: vc4-kms-dsi-waveshare-panel ++Info: Enable a Waveshare DSI touchscreen ++ Includes the Goodix driver for the touchscreen element. ++ The default is for the display to be using the I2C0 option for control. ++ Use the i2c1 override if using the I2C1 wiring with jumper wires from ++ GPIOs 2&3 (pins 3&5). ++ invx/invy/swapxy should be used with caution as the panel specifier will ++ set the default inversions for that panel. Always use them after the ++ panel specifier, and be aware that you may need to set them as =0, not ++ just adding it. ++ Requires vc4-kms-v3d to be loaded. ++Load: dtoverlay=vc4-kms-dsi-waveshare-panel,<param>=<val> ++Params: 2_8_inch 2.8" 480x640 ++ 3_4_inch 3.4" 800x800 round ++ 4_0_inch 4.0" 480x800 ++ 4_0_inchC 4.0" 720x720 ++ 7_0_inchC 7.0" C 1024x600 ++ 7_9_inch 7.9" 400x1280 ++ 8_0_inch 8.0" 1280x800 ++ 10_1_inch 10.1" 1280x800 ++ 11_9_inch 11.9" 320x1480 ++ i2c1 Use i2c-1 with jumper wires from GPIOs 2&3 ++ disable_touch Disable the touch controller ++ rotation Set the panel orientation property ++ invx Touchscreen inverted x axis ++ invy Touchscreen inverted y axis ++ swapxy Touchscreen swapped x y axis ++ dsi0 Use DSI0 and i2c_csi_dsi0 (rather than ++ the default DSI1 and i2c_csi_dsi). ++ ++ +Name: vc4-kms-kippah-7inch +Info: This overlay is now deprecated - see vc4-kms-dpi-panel,kippah-7inch +Load: <Deprecated> @@ -13794,6 +21458,7 @@ + noaudio Disable all HDMI audio (default "off") + composite Enable the composite output (default "off") + N.B. Disables all other outputs on a Pi 4. ++ nohdmi Disable HDMI output + + +Name: vc4-kms-v3d-pi4 @@ -13817,6 +21482,13 @@ + noaudio Disable all HDMI audio (default "off") + composite Enable the composite output (disables all other + outputs) ++ nohdmi Disable both HDMI 0 & 1 outputs ++ nohdmi0 Disable HDMI 0 output ++ nohdmi1 Disable HDMI 1 output ++ ++ ++Name: vc4-kms-v3d-pi5 ++Info: See vc4-kms-v3d-pi4 (this is the Pi 5 version) + + +Name: vc4-kms-vga666 @@ -13853,6 +21525,10 @@ + pullup Now enabled by default (ignored) + + ++Name: w1-gpio-pi5 ++Info: See w1-gpio (this is the Pi 5 version) ++ ++ +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. @@ -13862,6 +21538,10 @@ + pullup Now enabled by default (ignored) + + ++Name: w1-gpio-pullup-pi5 ++Info: See w1-gpio-pullup (this is the Pi 5 version) ++ ++ +Name: w5500 +Info: Overlay for the Wiznet W5500 Ethernet Controller on SPI0 +Load: dtoverlay=w5500,<param>=<val> @@ -13872,6 +21552,60 @@ + cs SPI bus Chip Select (default 0) + + ++Name: watterott-display ++Info: Watterott RPi-Display - 2.8" Touch Display ++ Linux has 2 drivers that support this display and this overlay supports ++ both. ++ ++ Examples: ++ fbtft/fb_ili9341: dtoverlay=watterott-display ++ drm/mi0283qt: dtoverlay=watterott-display,drm,backlight-pwm,rotate=180 ++ ++ Some notable differences with the DRM driver compared to fbtft: ++ - The display is turned on when it's first used and not on driver load ++ as with fbtft. So if nothing uses the display it stays off. ++ - Can run with a higher SPI clock increasing framerate. This is possible ++ since the driver avoids messing up the controller configuration due to ++ transmission errors by running config commands at 10MHz and only pixel ++ data at full speed (occasional pixel glitch might occur). ++ - PWM backlight is supported. ++ ++Load: dtoverlay=watterott-display,<param>=<val> ++Params: speed Display SPI bus speed ++ rotate Display rotation {0,90,180,270} ++ fps Delay between frame updates (fbtft only) ++ debug Debug output level {0-7} (fbtft only) ++ xohms Touchpanel sensitivity (X-plate resistance) ++ swapxy Swap x and y axis ++ backlight Change backlight GPIO pin {e.g. 12, 18} ++ (fbtft only) ++ drm Use DRM/KMS driver mi0283qt instead of fbtft. ++ Set the SPI clock to 70MHz. ++ This has to be the first parameter. ++ backlight-pwm Use pwm for backlight (drm only). NB: Disables ++ audio headphone output as that also uses PWM. ++ ++ ++Name: waveshare-can-fd-hat-mode-a ++Info: Overlay for the Waveshare 2-Channel Isolated CAN FD Expansion HAT ++ for Raspberry Pi, Multi Protections. Use this overlay when the ++ HAT is configured in Mode A (Default), with can0 on spi0.0 ++ and can1 on spi1.0. ++ https://www.waveshare.com/2-ch-can-fd-hat.htm ++Load: dtoverlay=waveshare-can-fd-hat-mode-a ++Params: <None> ++ ++ ++Name: waveshare-can-fd-hat-mode-b ++Info: Overlay for the Waveshare 2-Channel Isolated CAN FD Expansion HAT ++ for Raspberry Pi, Multi Protections. Use this overlay when the ++ HAT is configured in Mode B (requires hardware modification), with ++ can0 on spi0.0 and can1 on spi0.1. ++ https://www.waveshare.com/2-ch-can-fd-hat.htm ++Load: dtoverlay=waveshare-can-fd-hat-mode-b ++Params: <None> ++ ++ +Name: wittypi +Info: Configures the wittypi RTC module. +Load: dtoverlay=wittypi,<param>=<val> @@ -13910,10 +21644,10 @@ +http://www.raspberrypi.org/documentation/configuration/device-tree.md diff --git a/arch/arm/boot/dts/overlays/act-led-overlay.dts b/arch/arm/boot/dts/overlays/act-led-overlay.dts new file mode 100644 -index 000000000000..2f4bbb407f89 +index 000000000000..685e354923a0 --- /dev/null +++ b/arch/arm/boot/dts/overlays/act-led-overlay.dts -@@ -0,0 +1,27 @@ +@@ -0,0 +1,28 @@ +/dts-v1/; +/plugin/; + @@ -13930,20 +21664,21 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&act_led>; ++ target = <&led_act>; + frag0: __overlay__ { + gpios = <&gpio 0 0>; + }; + }; + + __overrides__ { -+ gpio = <&frag0>,"gpios:4"; ++ gpio = <&frag0>,"gpios:4", ++ <&frag0>,"status=okay"; + activelow = <&frag0>,"gpios:8"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/adafruit-st7735r-overlay.dts b/arch/arm/boot/dts/overlays/adafruit-st7735r-overlay.dts new file mode 100644 -index 000000000000..bf186811ec5d +index 000000000000..6e69bd7fa031 --- /dev/null +++ b/arch/arm/boot/dts/overlays/adafruit-st7735r-overlay.dts @@ -0,0 +1,83 @@ @@ -14011,7 +21746,7 @@ + spi-max-frequency = <32000000>; + dc-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio 25 GPIO_ACTIVE_HIGH>; -+ rotate = <90>; ++ rotation = <90>; + pinctrl-names = "default"; + pinctrl-0 = <&adafruit_pins>; + backlight = <&af18_backlight>; @@ -14022,7 +21757,7 @@ + __overrides__ { + 128x128 = <&af18>, "compatible=okaya,rh128128t"; + speed = <&af18>,"spi-max-frequency:0"; -+ rotate = <&af18>,"rotate:0"; ++ rotate = <&af18>,"rotation:0"; + dc_pin = <&af18>,"dc-gpios:4", <&adafruit_pins>,"brcm,pins:4"; + reset_pin = <&af18>,"reset-gpios:4", + <&adafruit_pins>,"brcm,pins:0"; @@ -14093,7 +21828,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts b/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts new file mode 100644 -index 000000000000..298488e19156 +index 000000000000..cf6d1ef3bfff --- /dev/null +++ b/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts @@ -0,0 +1,40 @@ @@ -14105,7 +21840,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2c>; ++ target = <&i2c1>; + + __overlay__ { + #address-cells = <1>; @@ -14122,7 +21857,7 @@ + }; + + fragment@1 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -14132,14 +21867,14 @@ + target = <&sound>; + __overlay__ { + compatible = "adi,adau1977-adc"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm/boot/dts/overlays/adau7002-simple-overlay.dts b/arch/arm/boot/dts/overlays/adau7002-simple-overlay.dts new file mode 100644 -index 000000000000..5fed769d2526 +index 000000000000..62e92bd8f952 --- /dev/null +++ b/arch/arm/boot/dts/overlays/adau7002-simple-overlay.dts @@ -0,0 +1,52 @@ @@ -14150,7 +21885,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -14182,7 +21917,7 @@ + "PDM_DAT", "Microphone Jack"; + status = "okay"; + simple-audio-card,cpu { -+ sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + }; + dailink0_slave: simple-audio-card,codec { + sound-dai = <&adau7002_codec>; @@ -14301,10 +22036,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/ads1115-overlay.dts b/arch/arm/boot/dts/overlays/ads1115-overlay.dts new file mode 100644 -index 000000000000..e44ced704ee2 +index 000000000000..64ada16de9c7 --- /dev/null +++ b/arch/arm/boot/dts/overlays/ads1115-overlay.dts -@@ -0,0 +1,103 @@ +@@ -0,0 +1,135 @@ +/* + * TI ADS1115 multi-channel ADC overlay + */ @@ -14316,23 +22051,6 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2c_arm>; -+ __overlay__ { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "okay"; -+ -+ ads1115: ads1115@48 { -+ compatible = "ti,ads1115"; -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ reg = <0x48>; -+ }; -+ }; -+ }; -+ -+ fragment@1 { + target = <&ads1115>; + __dormant__ { + #address-cells = <1>; @@ -14346,7 +22064,7 @@ + }; + }; + -+ fragment@2 { ++ fragment@1 { + target = <&ads1115>; + __dormant__ { + #address-cells = <1>; @@ -14360,7 +22078,7 @@ + }; + }; + -+ fragment@3 { ++ fragment@2 { + target = <&ads1115>; + __dormant__ { + #address-cells = <1>; @@ -14374,7 +22092,7 @@ + }; + }; + -+ fragment@4 { ++ fragment@3 { + target = <&ads1115>; + __dormant__ { + #address-cells = <1>; @@ -14388,29 +22106,78 @@ + }; + }; + ++ fragment@4 { ++ target = <&i2cbus>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ ads1115: ads1115@48 { ++ compatible = "ti,ads1115"; ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x48>; ++ }; ++ }; ++ }; ++ ++ frag100: fragment@100 { ++ target = <&i2c1>; ++ i2cbus: __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@101 { ++ target = <&i2c0if>; ++ __dormant__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@102 { ++ target = <&i2c0mux>; ++ __dormant__ { ++ status = "okay"; ++ }; ++ }; ++ + __overrides__ { + addr = <&ads1115>,"reg:0"; -+ cha_enable = <0>,"=1"; ++ cha_enable = <0>,"=0"; + cha_cfg = <&channel_a>,"reg:0"; + cha_gain = <&channel_a>,"ti,gain:0"; + cha_datarate = <&channel_a>,"ti,datarate:0"; -+ chb_enable = <0>,"=2"; ++ chb_enable = <0>,"=1"; + chb_cfg = <&channel_b>,"reg:0"; + chb_gain = <&channel_b>,"ti,gain:0"; + chb_datarate = <&channel_b>,"ti,datarate:0"; -+ chc_enable = <0>,"=3"; ++ chc_enable = <0>,"=2"; + chc_cfg = <&channel_c>,"reg:0"; + chc_gain = <&channel_c>,"ti,gain:0"; + chc_datarate = <&channel_c>,"ti,datarate:0"; -+ chd_enable = <0>,"=4"; ++ chd_enable = <0>,"=3"; + chd_cfg = <&channel_d>,"reg:0"; + chd_gain = <&channel_d>,"ti,gain:0"; + chd_datarate = <&channel_d>,"ti,datarate:0"; ++ i2c0 = <&frag100>, "target:0=",<&i2c0>; ++ i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, ++ <0>,"+101+102"; ++ i2c3 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c3"; ++ i2c4 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c4"; ++ i2c5 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c5"; ++ i2c6 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c6"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/ads7846-overlay.dts b/arch/arm/boot/dts/overlays/ads7846-overlay.dts new file mode 100644 -index 000000000000..1c5c9b6bb6ff +index 000000000000..211a002c0b34 --- /dev/null +++ b/arch/arm/boot/dts/overlays/ads7846-overlay.dts @@ -0,0 +1,89 @@ @@ -14473,7 +22240,7 @@ + spi-max-frequency = <2000000>; + interrupts = <255 2>; /* high-to-low edge triggered */ + interrupt-parent = <&gpio>; -+ pendown-gpio = <&gpio 255 0>; ++ pendown-gpio = <&gpio 255 1>; + + /* driver defaults */ + ti,x-min = /bits/ 16 <0>; @@ -14627,7 +22394,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts b/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts new file mode 100644 -index 000000000000..82f9b3734fb1 +index 000000000000..d867146bcb8f --- /dev/null +++ b/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts @@ -0,0 +1,49 @@ @@ -14639,7 +22406,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -14671,7 +22438,7 @@ + card_name = "Akkordion"; + dai_name = "IQaudIO DAC"; + dai_stream_name = "IQaudIO DAC HiFi"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; @@ -14682,10 +22449,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts b/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts new file mode 100644 -index 000000000000..873cb2fab52b +index 000000000000..16806945890b --- /dev/null +++ b/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts -@@ -0,0 +1,59 @@ +@@ -0,0 +1,61 @@ +/* + * Definitions for Allo Boss DAC board + */ @@ -14706,8 +22473,8 @@ + }; + }; + -+ fragment@1 { -+ target = <&i2s>; ++ frag1: fragment@1 { ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -14734,7 +22501,7 @@ + target = <&sound>; + boss_dac: __overlay__ { + compatible = "allo,boss-dac"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + mute-gpios = <&gpio 6 1>; + status = "okay"; + }; @@ -14742,12 +22509,14 @@ + + __overrides__ { + 24db_digital_gain = <&boss_dac>,"allo,24db_digital_gain?"; -+ slave = <&boss_dac>,"allo,slave?"; ++ slave = <&boss_dac>,"allo,slave?", ++ <&frag1>,"target:0=",<&i2s_clk_producer>, ++ <&boss_dac>,"i2s-controller:0=",<&i2s_clk_producer>; + }; +}; diff --git a/arch/arm/boot/dts/overlays/allo-boss2-dac-audio-overlay.dts b/arch/arm/boot/dts/overlays/allo-boss2-dac-audio-overlay.dts new file mode 100644 -index 000000000000..a6adfb495eb9 +index 000000000000..feac2b091b36 --- /dev/null +++ b/arch/arm/boot/dts/overlays/allo-boss2-dac-audio-overlay.dts @@ -0,0 +1,57 @@ @@ -14761,7 +22530,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + #sound-dai-cells = <0>; + status = "okay"; @@ -14810,7 +22579,7 @@ + diff --git a/arch/arm/boot/dts/overlays/allo-digione-overlay.dts b/arch/arm/boot/dts/overlays/allo-digione-overlay.dts new file mode 100644 -index 000000000000..ea018ace34d4 +index 000000000000..61c3c2e9fbd8 --- /dev/null +++ b/arch/arm/boot/dts/overlays/allo-digione-overlay.dts @@ -0,0 +1,44 @@ @@ -14822,7 +22591,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -14851,7 +22620,7 @@ + target = <&sound>; + __overlay__ { + compatible = "allo,allo-digione"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + clock44-gpio = <&gpio 5 0>; + clock48-gpio = <&gpio 6 0>; @@ -14860,10 +22629,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts b/arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts new file mode 100644 -index 000000000000..b25fd681f09f +index 000000000000..1ebb6bc6b907 --- /dev/null +++ b/arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts -@@ -0,0 +1,57 @@ +@@ -0,0 +1,58 @@ +/* + * Definitions for Allo Katana DAC boards + */ @@ -14875,7 +22644,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + #sound-dai-cells = <0>; + status = "okay"; @@ -14896,6 +22665,7 @@ + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; ++ clock-frequency = <50000>; + + allo-katana-codec@30 { + #sound-dai-cells = <0>; @@ -14923,7 +22693,7 @@ + diff --git a/arch/arm/boot/dts/overlays/allo-piano-dac-pcm512x-audio-overlay.dts b/arch/arm/boot/dts/overlays/allo-piano-dac-pcm512x-audio-overlay.dts new file mode 100644 -index 000000000000..bfc66da6295a +index 000000000000..1b79ef1df2a1 --- /dev/null +++ b/arch/arm/boot/dts/overlays/allo-piano-dac-pcm512x-audio-overlay.dts @@ -0,0 +1,54 @@ @@ -14945,7 +22715,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -14971,7 +22741,7 @@ + target = <&sound>; + piano_dac: __overlay__ { + compatible = "allo,piano-dac"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; @@ -14983,7 +22753,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/allo-piano-dac-plus-pcm512x-audio-overlay.dts b/arch/arm/boot/dts/overlays/allo-piano-dac-plus-pcm512x-audio-overlay.dts new file mode 100644 -index 000000000000..d47a35def4f7 +index 000000000000..d17c9c10df39 --- /dev/null +++ b/arch/arm/boot/dts/overlays/allo-piano-dac-plus-pcm512x-audio-overlay.dts @@ -0,0 +1,57 @@ @@ -14995,7 +22765,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -15030,7 +22800,7 @@ + piano_dac: __overlay__ { + compatible = "allo,piano-dac-plus"; + audio-codec = <&allo_pcm5122_4c &allo_pcm5122_4d>; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + mute1-gpios = <&gpio 6 1>; + mute2-gpios = <&gpio 25 1>; + status = "okay"; @@ -15257,10 +23027,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/apds9960-overlay.dts b/arch/arm/boot/dts/overlays/apds9960-overlay.dts new file mode 100644 -index 000000000000..c216932278ab +index 000000000000..bb18cca1ac66 --- /dev/null +++ b/arch/arm/boot/dts/overlays/apds9960-overlay.dts -@@ -0,0 +1,57 @@ +@@ -0,0 +1,55 @@ +// Definitions for APDS-9960 ambient light and gesture sensor + +/dts-v1/; @@ -15287,6 +23057,15 @@ + }; + + fragment@2 { ++ target = <&apds9960>; ++ apds9960_irq: __overlay__ { ++ #interrupt-cells = <2>; ++ interrupt-parent = <&gpio>; ++ interrupts = <4 1>; ++ }; ++ }; ++ ++ fragment@3 { + target = <&i2c1>; + __overlay__ { + #address-cells = <1>; @@ -15300,27 +23079,16 @@ + }; + }; + -+ 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"; ++ noints = <0>,"!1!2"; + }; +}; + diff --git a/arch/arm/boot/dts/overlays/applepi-dac-overlay.dts b/arch/arm/boot/dts/overlays/applepi-dac-overlay.dts new file mode 100644 -index 000000000000..4769296ec9d6 +index 000000000000..cb7649d3a613 --- /dev/null +++ b/arch/arm/boot/dts/overlays/applepi-dac-overlay.dts @@ -0,0 +1,57 @@ @@ -15342,7 +23110,7 @@ + format = "i2s"; + + p_cpu_dai: cpu { -+ sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; @@ -15366,7 +23134,7 @@ + }; + + fragment@2 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + #sound-dai-cells = <0>; + status = "okay"; @@ -15381,6 +23149,243 @@ + compile with: + dtc -@ -H epapr -O dtb -o ApplePi-DAC.dtbo -W no-unit_address_vs_reg ApplePi-DAC.dts +*/ +diff --git a/arch/arm/boot/dts/overlays/arducam-64mp-overlay.dts b/arch/arm/boot/dts/overlays/arducam-64mp-overlay.dts +new file mode 100644 +index 000000000000..02f01729a759 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/arducam-64mp-overlay.dts +@@ -0,0 +1,91 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Definitions for Arducam 64MP camera module on VC I2C bus ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2835"; ++ ++ i2c_frag: fragment@0 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ #include "arducam-64mp.dtsi" ++ }; ++ }; ++ ++ csi_frag: fragment@1 { ++ target = <&csi1>; ++ csi: __overlay__ { ++ status = "okay"; ++ brcm,media-controller; ++ ++ port{ ++ csi_ep: endpoint{ ++ remote-endpoint = <&cam_endpoint>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ clk_frag: fragment@3 { ++ target = <&cam1_clk>; ++ __overlay__ { ++ clock-frequency = <24000000>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@5 { ++ target = <&cam_node>; ++ __overlay__ { ++ lens-focus = <&vcm_node>; ++ }; ++ }; ++ ++ __overrides__ { ++ rotation = <&cam_node>,"rotation:0"; ++ orientation = <&cam_node>,"orientation:0"; ++ media-controller = <&csi>,"brcm,media-controller?"; ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&csi_frag>, "target:0=",<&csi0>, ++ <&clk_frag>, "target:0=",<&cam0_clk>, ++ <&cam_node>, "clocks:0=",<&cam0_clk>, ++ <&cam_node>, "VANA-supply:0=",<&cam0_reg>, ++ <&vcm_node>, "VDD-supply:0=", <&cam0_reg>; ++ vcm = <&vcm_node>, "status", ++ <0>, "=5"; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; ++ ++&vcm_node { ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/overlays/arducam-64mp.dtsi b/arch/arm/boot/dts/overlays/arducam-64mp.dtsi +new file mode 100644 +index 000000000000..ed9f2e50c287 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/arducam-64mp.dtsi +@@ -0,0 +1,34 @@ ++// Fragment that configures a Arducam64MP ++ ++cam_node: arducam_64mp@1a { ++ compatible = "arducam,64mp"; ++ reg = <0x1a>; ++ status = "disabled"; ++ ++ clocks = <&cam1_clk>; ++ clock-names = "xclk"; ++ ++ VANA-supply = <&cam1_reg>; /* 2.8v */ ++ VDIG-supply = <&cam_dummy_reg>; /* 1.8v */ ++ VDDL-supply = <&cam_dummy_reg>; /* 1.2v */ ++ ++ rotation = <0>; ++ orientation = <2>; ++ ++ port { ++ cam_endpoint: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = ++ /bits/ 64 <456000000>; ++ }; ++ }; ++}; ++ ++vcm_node: dw9817_arducam64mp@c { ++ compatible = "dongwoon,dw9817-vcm"; ++ reg = <0x0c>; ++ status = "disabled"; ++ VDD-supply = <&cam1_reg>; ++}; +diff --git a/arch/arm/boot/dts/overlays/arducam-pivariety-overlay.dts b/arch/arm/boot/dts/overlays/arducam-pivariety-overlay.dts +new file mode 100644 +index 000000000000..fab27a56db6e +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/arducam-pivariety-overlay.dts +@@ -0,0 +1,94 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Definitions for Arducam Pivariety camera module on VC I2C bus ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2835"; ++ ++ i2c_frag: fragment@0 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ arducam_pivariety: arducam_pivariety@c { ++ compatible = "arducam,arducam-pivariety"; ++ reg = <0x0c>; ++ status = "okay"; ++ ++ clocks = <&cam1_clk>; ++ clock-names = "xclk"; ++ ++ VANA-supply = <&cam1_reg>; /* 2.8v */ ++ VDIG-supply = <&cam_dummy_reg>; /* 1.8v */ ++ VDDL-supply = <&cam_dummy_reg>; /* 1.2v */ ++ ++ rotation = <0>; ++ orientation = <2>; ++ ++ port { ++ arducam_pivariety_0: endpoint { ++ remote-endpoint = <&csi1_ep>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = ++ /bits/ 64 <493500000>; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ csi_frag: fragment@1 { ++ target = <&csi1>; ++ csi: __overlay__ { ++ status = "okay"; ++ brcm,media-controller; ++ ++ port{ ++ csi1_ep: endpoint{ ++ remote-endpoint = <&arducam_pivariety_0>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ clk_frag: fragment@3 { ++ target = <&cam1_clk>; ++ __overlay__ { ++ clock-frequency = <24000000>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ __overrides__ { ++ rotation = <&arducam_pivariety>,"rotation:0"; ++ orientation = <&arducam_pivariety>,"orientation:0"; ++ media-controller = <&csi>,"brcm,media-controller?"; ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&csi_frag>, "target:0=",<&csi0>, ++ <&clk_frag>, "target:0=",<&cam0_clk>, ++ <&arducam_pivariety>, "clocks:0=",<&cam0_clk>, ++ <&arducam_pivariety>, "VANA-supply:0=",<&cam0_reg>; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts new file mode 100644 index 000000000000..5a3f4571ee78 @@ -15446,7 +23451,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts b/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts new file mode 100644 -index 000000000000..57a66eac8e9b +index 000000000000..af72ea0b706a --- /dev/null +++ b/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts @@ -0,0 +1,60 @@ @@ -15458,7 +23463,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -15500,7 +23505,7 @@ + mult-gpios = <&gpio 27 0>, <&gpio 22 0>, <&gpio 23 0>, + <&gpio 24 0>; + reset-gpios = <&gpio 5 0>; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + codec = <&cs42448>; + status = "okay"; + }; @@ -15510,9 +23515,65 @@ + non-stop-clocks = <&snd>, "non-stop-clocks?"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/audioinjector-bare-i2s-overlay.dts b/arch/arm/boot/dts/overlays/audioinjector-bare-i2s-overlay.dts +new file mode 100644 +index 000000000000..a536fbb1a985 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/audioinjector-bare-i2s-overlay.dts +@@ -0,0 +1,50 @@ ++// Definitions for audioinjector.net audio soundcard ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2s_clk_producer>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/"; ++ __overlay__ { ++ codec_bare: codec_bare { ++ compatible = "linux,spdif-dit"; ++ #sound-dai-cells = <0>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&sound>; ++ __overlay__ { ++ compatible = "simple-audio-card"; ++ i2s-controller = <&i2s_clk_producer>; ++ status = "okay"; ++ ++ simple-audio-card,name = "audioinjector-bare"; ++ simple-audio-card,format = "i2s"; ++ ++ simple-audio-card,bitclock-master = <&dailink0_master>; ++ simple-audio-card,frame-master = <&dailink0_master>; ++ ++ dailink0_master: simple-audio-card,cpu { ++ sound-dai = <&i2s_clk_producer>; ++ dai-tdm-slot-num = <2>; ++ dai-tdm-slot-width = <32>; ++ }; ++ ++ snd_codec: simple-audio-card,codec { ++ sound-dai = <&codec_bare>; ++ }; ++ }; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/audioinjector-isolated-soundcard-overlay.dts b/arch/arm/boot/dts/overlays/audioinjector-isolated-soundcard-overlay.dts new file mode 100644 -index 000000000000..63e05cf9665d +index 000000000000..89faed778fcb --- /dev/null +++ b/arch/arm/boot/dts/overlays/audioinjector-isolated-soundcard-overlay.dts @@ -0,0 +1,55 @@ @@ -15524,7 +23585,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -15565,7 +23626,7 @@ + snd: __overlay__ { + compatible = "ai,audioinjector-isolated-soundcard"; + mute-gpios = <&gpio 17 0>; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + codec = <&cs4272>; + status = "okay"; + }; @@ -15573,7 +23634,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/audioinjector-ultra-overlay.dts b/arch/arm/boot/dts/overlays/audioinjector-ultra-overlay.dts new file mode 100644 -index 000000000000..fb4a4678a17a +index 000000000000..ee79441187bd --- /dev/null +++ b/arch/arm/boot/dts/overlays/audioinjector-ultra-overlay.dts @@ -0,0 +1,71 @@ @@ -15585,7 +23646,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -15612,7 +23673,7 @@ + target = <&sound>; + __overlay__ { + compatible = "simple-audio-card"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + + simple-audio-card,name = "audioinjector-ultra"; @@ -15636,7 +23697,7 @@ + simple-audio-card,frame-master = <&sound_master>; + + simple-audio-card,cpu { -+ sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_consumer>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; @@ -15650,7 +23711,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts b/arch/arm/boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts new file mode 100644 -index 000000000000..68f4427d86c3 +index 000000000000..417353b2798e --- /dev/null +++ b/arch/arm/boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts @@ -0,0 +1,39 @@ @@ -15662,7 +23723,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -15688,14 +23749,14 @@ + target = <&sound>; + __overlay__ { + compatible = "ai,audioinjector-pi-soundcard"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts b/arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts new file mode 100644 -index 000000000000..81af26374d92 +index 000000000000..a89d38b2fe19 --- /dev/null +++ b/arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts @@ -0,0 +1,82 @@ @@ -15709,7 +23770,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -15776,17 +23837,17 @@ + target = <&sound>; + __overlay__ { + compatible = "as,audiosense-pi"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm/boot/dts/overlays/audremap-overlay.dts b/arch/arm/boot/dts/overlays/audremap-overlay.dts new file mode 100644 -index 000000000000..7324890ead86 +index 000000000000..95027c5c8f9e --- /dev/null +++ b/arch/arm/boot/dts/overlays/audremap-overlay.dts -@@ -0,0 +1,42 @@ +@@ -0,0 +1,38 @@ +/dts-v1/; +/plugin/; + @@ -15796,42 +23857,38 @@ + fragment@0 { + target = <&audio_pins>; + frag0: __overlay__ { ++ brcm,pins = <12 13>; ++ brcm,function = <4>; /* alt0 alt0 */ + }; + }; + + 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>; ++ target = <&chosen>; + __overlay__ { -+ brcm,disable-headphones = <0>; ++ bootargs = "snd_bcm2835.enable_headphones=1"; + }; + }; + + __overrides__ { + swap_lr = <&frag0>, "swap_lr?"; + enable_jack = <&frag0>, "enable_jack?"; -+ pins_12_13 = <0>,"+1-2"; -+ pins_18_19 = <0>,"-1+2"; ++ pins_12_13 = <&frag0>,"brcm,pins:0=12", ++ <&frag0>,"brcm,pins:4=13", ++ <&frag0>,"brcm,function:0=4"; ++ pins_18_19 = <&frag0>,"brcm,pins:0=18", ++ <&frag0>,"brcm,pins:4=19", ++ <&frag0>,"brcm,function:0=2"; ++ pins_40_41 = <&frag0>,"brcm,pins:0=40", ++ <&frag0>,"brcm,pins:4=41", ++ <&frag0>,"brcm,function:0=4"; ++ pins_40_45 = <&frag0>,"brcm,pins:0=40", ++ <&frag0>,"brcm,pins:4=45", ++ <&frag0>,"brcm,function:0=4"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/balena-fin-overlay.dts b/arch/arm/boot/dts/overlays/balena-fin-overlay.dts new file mode 100644 -index 000000000000..e7ead7cdf5f5 +index 000000000000..8fc22587e69c --- /dev/null +++ b/arch/arm/boot/dts/overlays/balena-fin-overlay.dts @@ -0,0 +1,125 @@ @@ -15857,7 +23914,7 @@ + fragment@1 { + target = <&gpio>; + __overlay__ { -+ sdio_pins: sdio_pins { ++ sdio_pins: sdio_ovl_pins { + brcm,pins = <34 35 36 37 38 39>; + brcm,function = <7>; /* ALT3 = SD1 */ + brcm,pull = <0 2 2 2 2 2>; @@ -15960,6 +24017,1596 @@ + }; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/bcm2712d0-overlay.dts b/arch/arm/boot/dts/overlays/bcm2712d0-overlay.dts +new file mode 100644 +index 000000000000..8f9c6a887064 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/bcm2712d0-overlay.dts +@@ -0,0 +1,75 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/dts-v1/; ++/plugin/; ++ ++#include <dt-bindings/interrupt-controller/irq.h> ++#include <dt-bindings/interrupt-controller/arm-gic.h> ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&gio>; ++ __overlay__ { ++ brcm,gpio-bank-widths = <32 4>; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gio_aon>; ++ __overlay__ { ++ brcm,gpio-bank-widths = <15 6>; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&pinctrl>; ++ __overlay__ { ++ compatible = "brcm,bcm2712d0-pinctrl"; ++ reg = <0x7d504100 0x20>; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&pinctrl_aon>; ++ __overlay__ { ++ compatible = "brcm,bcm2712d0-aon-pinctrl"; ++ reg = <0x7d510700 0x1c>; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&vc4>; ++ __overlay__ { ++ compatible = "brcm,bcm2712d0-vc6"; ++ }; ++ }; ++ ++ fragment@5 { ++ target = <&uart10>; ++ __overlay__ { ++ interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ }; ++ ++ fragment@6 { ++ target = <&spi10>; ++ __overlay__ { ++ dmas = <&dma40 3>, <&dma40 4>; ++ }; ++ }; ++ ++ fragment@7 { ++ target = <&hdmi0>; ++ __overlay__ { ++ dmas = <&dma40 (12|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; ++ }; ++ }; ++ ++ fragment@8 { ++ target = <&hdmi1>; ++ __overlay__ { ++ dmas = <&dma40 (13|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/camera-mux-2port-overlay.dts b/arch/arm/boot/dts/overlays/camera-mux-2port-overlay.dts +new file mode 100644 +index 000000000000..13d86cc693b3 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/camera-mux-2port-overlay.dts +@@ -0,0 +1,545 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Overlay to configure a 2 port camera multiplexer ++// ++// Configuration is based on the Arducam Doubleplexer ++// which uses a PCA9543 I2C multiplexer to handle the ++// I2C, and GPIO 4 to control the MIPI mux, and GPIO 17 ++// to enable the CSI-2 mux output (gpio-hog). ++ ++/dts-v1/; ++/plugin/; ++ ++#include <dt-bindings/gpio/gpio.h> ++ ++/{ ++ compatible = "brcm,bcm2835"; ++ ++ /* Fragments that complete the individual sensor fragments */ ++ /* IMX290 */ ++ fragment@0 { ++ target = <&imx290_0_ep>; ++ __overlay__ { ++ data-lanes = <1 2>; ++ link-frequencies = ++ /bits/ 64 <445500000 297000000>; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&imx290_1_ep>; ++ __overlay__ { ++ data-lanes = <1 2>; ++ link-frequencies = ++ /bits/ 64 <445500000 297000000>; ++ }; ++ }; ++ ++ /* IMX477 */ ++ fragment@10 { ++ target = <&imx477_0>; ++ __overlay__ { ++ compatible = "sony,imx477"; ++ }; ++ }; ++ ++ fragment@11 { ++ target = <&imx477_1>; ++ __overlay__ { ++ compatible = "sony,imx477"; ++ }; ++ }; ++ ++ /* Additional fragments affecting the mux nodes */ ++ fragment@100 { ++ target = <&mux_in0>; ++ __dormant__ { ++ data-lanes = <1>; ++ }; ++ }; ++ fragment@101 { ++ target = <&mux_in0>; ++ __overlay__ { ++ data-lanes = <1 2>; ++ }; ++ }; ++ ++ fragment@102 { ++ target = <&mux_in1>; ++ __dormant__ { ++ data-lanes = <1>; ++ }; ++ }; ++ fragment@103 { ++ target = <&mux_in1>; ++ __overlay__ { ++ data-lanes = <1 2>; ++ }; ++ }; ++ ++ /* Mux define */ ++ i2c_frag: fragment@200 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ pca@70 { ++ reg = <0x70>; ++ compatible = "nxp,pca9543"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ i2c@0 { ++ reg = <0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ #define cam_node arducam_64mp_0 ++ #define cam_endpoint arducam_64mp_0_ep ++ #define vcm_node arducam_64mp_0_vcm ++ #define cam1_clk clk_24mhz ++ #include "arducam-64mp.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node imx219_0 ++ #define cam_endpoint imx219_0_ep ++ #define cam1_clk clk_24mhz ++ #include "imx219.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx477_0 ++ #define cam_endpoint imx477_0_ep ++ #define cam1_clk clk_24mhz ++ #include "imx477_378.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx519_0 ++ #define cam_endpoint imx519_0_ep ++ #define vcm_node imx519_0_vcm ++ #define cam1_clk clk_24mhz ++ #include "imx519.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node imx708_0 ++ #define cam_endpoint imx708_0_ep ++ #define vcm_node imx708_0_vcm ++ #define cam1_clk clk_24mhz ++ #include "imx708.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node ov5647_0 ++ #define cam_endpoint ov5647_0_ep ++ #define cam1_clk clk_25mhz ++ #include "ov5647.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov7251_0 ++ #define cam_endpoint ov7251_0_ep ++ #define cam1_clk clk_24mhz ++ #include "ov7251.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov9281_0 ++ #define cam_endpoint ov9281_0_ep ++ #define cam1_clk clk_24mhz ++ #include "ov9281.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx258_0 ++ #define cam_endpoint imx258_0_ep ++ #define cam1_clk clk_24mhz ++ #include "imx258.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx290_0 ++ #define cam_endpoint imx290_0_ep ++ #define cam1_clk clk_imx290 ++ #include "imx290_327.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov2311_0 ++ #define cam_endpoint ov2311_0_ep ++ #define cam1_clk clk_24mhz ++ #include "ov2311.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov64a40_0 ++ #define cam_endpoint ov64a40_0_ep ++ #define vcm_node ov64a40_0_vcm ++ #define cam1_clk clk_24mhz ++ #include "ov64a40.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ }; ++ ++ i2c@1 { ++ reg = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ #define cam_node arducam_64mp_1 ++ #define cam_endpoint arducam_64mp_1_ep ++ #define vcm_node arducam_64mp_1_vcm ++ #define cam1_clk clk_24mhz ++ #include "arducam-64mp.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node imx219_1 ++ #define cam_endpoint imx219_1_ep ++ #define cam1_clk clk_24mhz ++ #include "imx219.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx477_1 ++ #define cam_endpoint imx477_1_ep ++ #define cam1_clk clk_24mhz ++ #include "imx477_378.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx519_1 ++ #define cam_endpoint imx519_1_ep ++ #define vcm_node imx519_1_vcm ++ #define cam1_clk clk_24mhz ++ #include "imx519.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node imx708_1 ++ #define cam_endpoint imx708_1_ep ++ #define vcm_node imx708_1_vcm ++ #define cam1_clk clk_24mhz ++ #include "imx708.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node ov5647_1 ++ #define cam_endpoint ov5647_1_ep ++ #define cam1_clk clk_25mhz ++ #include "ov5647.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov7251_1 ++ #define cam_endpoint ov7251_1_ep ++ #define cam1_clk clk_24mhz ++ #include "ov7251.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov9281_1 ++ #define cam_endpoint ov9281_1_ep ++ #define cam1_clk clk_24mhz ++ #include "ov9281.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx258_1 ++ #define cam_endpoint imx258_1_ep ++ #define cam1_clk clk_24mhz ++ #include "imx258.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx290_1 ++ #define cam_endpoint imx290_1_ep ++ #define cam1_clk clk_imx290 ++ #include "imx290_327.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov2311_1 ++ #define cam_endpoint ov2311_1_ep ++ #define cam1_clk clk_24mhz ++ #include "ov2311.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov64a40_1 ++ #define cam_endpoint ov64a40_1_ep ++ #define vcm_node ov64a40_1_vcm ++ #define cam1_clk clk_24mhz ++ #include "ov64a40.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ }; ++ }; ++ }; ++ }; ++ ++ csi_frag: fragment@201 { ++ target = <&csi1>; ++ __overlay__ { ++ status = "okay"; ++ ++ brcm,media-controller; ++ ++ port { ++ csi1_ep: endpoint { ++ remote-endpoint = <&mux_out>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@202 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@203 { ++ target-path="/"; ++ __overlay__ { ++ mux: mux-controller { ++ compatible = "gpio-mux"; ++ #mux-control-cells = <0>; ++ ++ mux-gpios = <&gpio 4 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ video-mux { ++ compatible = "video-mux"; ++ mux-controls = <&mux>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ ++ mux_in0: endpoint { ++ clock-lanes = <0>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ ++ mux_in1: endpoint { ++ clock-lanes = <0>; ++ }; ++ }; ++ ++ port@2 { ++ reg = <2>; ++ ++ mux_out: endpoint { ++ remote-endpoint = <&csi1_ep>; ++ clock-lanes = <0>; ++ }; ++ }; ++ }; ++ ++ clk_24mhz: clk_24mhz { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ ++ clock-frequency = <24000000>; ++ status = "okay"; ++ }; ++ ++ clk_25mhz: clk_25mhz { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ ++ clock-frequency = <25000000>; ++ status = "okay"; ++ }; ++ ++ clk_imx290: clk_imx290 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ ++ clock-frequency = <37125000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@204 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@205 { ++ target = <&gpio>; ++ __overlay__ { ++ mipi_sw_oe_hog { ++ gpio-hog; ++ gpios = <17 GPIO_ACTIVE_LOW>; ++ output-high; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ cam0-arducam-64mp = <&mux_in0>, "remote-endpoint:0=",<&arducam_64mp_0_ep>, ++ <&arducam_64mp_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&mux_in0>, "clock-noncontinuous?", ++ <&arducam_64mp_0>, "status=okay", ++ <&arducam_64mp_0_vcm>, "status=okay", ++ <&arducam_64mp_0>,"lens-focus:0=", <&arducam_64mp_0_vcm>; ++ cam0-imx219 = <&mux_in0>, "remote-endpoint:0=",<&imx219_0_ep>, ++ <&imx219_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&mux_in0>, "clock-noncontinuous?", ++ <&imx219_0>, "status=okay"; ++ cam0-imx477 = <&mux_in0>, "remote-endpoint:0=",<&imx477_0_ep>, ++ <&imx477_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&mux_in0>, "clock-noncontinuous?", ++ <&imx477_0>, "status=okay"; ++ cam0-imx519 = <&mux_in0>, "remote-endpoint:0=",<&imx519_0_ep>, ++ <&imx519_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&mux_in0>, "clock-noncontinuous?", ++ <&imx519_0>, "status=okay", ++ <&imx519_0_vcm>, "status=okay", ++ <&imx519_0>,"lens-focus:0=", <&imx519_0_vcm>; ++ cam0-imx708 = <&mux_in0>, "remote-endpoint:0=",<&imx708_0_ep>, ++ <&imx708_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&mux_in0>, "clock-noncontinuous?", ++ <&imx708_0>, "status=okay", ++ <&imx708_0_vcm>, "status=okay", ++ <&imx708_0>,"lens-focus:0=", <&imx708_0_vcm>; ++ cam0-ov5647 = <&mux_in0>, "remote-endpoint:0=",<&ov5647_0_ep>, ++ <&ov5647_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&ov5647_0>, "status=okay"; ++ cam0-ov7251 = <&mux_in0>, "remote-endpoint:0=",<&ov7251_0_ep>, ++ <&ov7251_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&ov7251_0>, "status=okay", ++ <0>,"+100-101"; ++ cam0-ov9281 = <&mux_in0>, "remote-endpoint:0=",<&ov9281_0_ep>, ++ <&ov9281_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&ov9281_0>, "status=okay"; ++ cam0-imx258 = <&mux_in0>, "remote-endpoint:0=",<&imx258_0_ep>, ++ <&imx258_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&imx258_0>, "status=okay"; ++ cam0-imx290 = <&mux_in0>, "remote-endpoint:0=",<&imx290_0_ep>, ++ <&imx290_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&imx290_0>, "status=okay"; ++ cam0-ov2311 = <&mux_in0>, "remote-endpoint:0=",<&ov2311_0_ep>, ++ <&ov2311_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&ov2311_0>, "status=okay"; ++ cam0-ov64a40 = <&mux_in0>, "remote-endpoint:0=",<&ov64a40_0_ep>, ++ <&ov64a40_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&mux_in0>, "clock-noncontinuous?", ++ <&ov64a40_0>, "status=okay", ++ <&ov64a40_0_vcm>, "status=okay", ++ <&ov64a40_0>,"lens-focus:0=", <&ov64a40_0_vcm>; ++ ++ cam1-arducam-64mp = <&mux_in1>, "remote-endpoint:0=",<&arducam_64mp_1_ep>, ++ <&arducam_64mp_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&mux_in1>, "clock-noncontinuous?", ++ <&arducam_64mp_1>, "status=okay", ++ <&arducam_64mp_1_vcm>, "status=okay", ++ <&arducam_64mp_1>,"lens-focus:0=", <&arducam_64mp_1_vcm>; ++ cam1-imx219 = <&mux_in1>, "remote-endpoint:0=",<&imx219_1_ep>, ++ <&imx219_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&mux_in1>, "clock-noncontinuous?", ++ <&imx219_1>, "status=okay"; ++ cam1-imx477 = <&mux_in1>, "remote-endpoint:0=",<&imx477_1_ep>, ++ <&imx477_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&mux_in1>, "clock-noncontinuous?", ++ <&imx477_1>, "status=okay"; ++ cam1-imx519 = <&mux_in1>, "remote-endpoint:0=",<&imx519_1_ep>, ++ <&imx519_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&mux_in1>, "clock-noncontinuous?", ++ <&imx519_1>, "status=okay", ++ <&imx519_1_vcm>, "status=okay", ++ <&imx519_1>,"lens-focus:0=", <&imx519_1_vcm>; ++ cam1-imx708 = <&mux_in1>, "remote-endpoint:0=",<&imx708_1_ep>, ++ <&imx708_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&mux_in1>, "clock-noncontinuous?", ++ <&imx708_1>, "status=okay", ++ <&imx708_1_vcm>, "status=okay", ++ <&imx708_1>,"lens-focus:0=", <&imx708_1_vcm>; ++ cam1-ov5647 = <&mux_in1>, "remote-endpoint:0=",<&ov5647_1_ep>, ++ <&ov5647_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&ov5647_1>, "status=okay"; ++ cam1-ov7251 = <&mux_in1>, "remote-endpoint:0=",<&ov7251_1_ep>, ++ <&ov7251_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&ov7251_1>, "status=okay", ++ <0>,"+102-103"; ++ cam1-ov9281 = <&mux_in1>, "remote-endpoint:0=",<&ov9281_1_ep>, ++ <&ov9281_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&ov9281_1>, "status=okay"; ++ cam1-imx258 = <&mux_in1>, "remote-endpoint:0=",<&imx258_1_ep>, ++ <&imx258_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&imx258_1>, "status=okay"; ++ cam1-imx290 = <&mux_in1>, "remote-endpoint:0=",<&imx290_1_ep>, ++ <&imx290_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&imx290_1>, "status=okay"; ++ cam1-ov2311 = <&mux_in1>, "remote-endpoint:0=",<&ov2311_1_ep>, ++ <&ov2311_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&ov2311_1>, "status=okay"; ++ cam1-ov64a40 = <&mux_in1>, "remote-endpoint:0=",<&ov64a40_1_ep>, ++ <&ov64a40_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&mux_in1>, "clock-noncontinuous?", ++ <&ov64a40_1>, "status=okay", ++ <&ov64a40_1_vcm>, "status=okay", ++ <&ov64a40_1>,"lens-focus:0=", <&ov64a40_1_vcm>; ++ ++ cam0-imx290-clk-freq = <&clk_imx290>,"clock-frequency:0", ++ <&imx290_0>,"clock-frequency:0"; ++ cam1-imx290-clk-freq = <&clk_imx290>,"clock-frequency:0", ++ <&imx290_1>,"clock-frequency:0"; ++ ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&csi_frag>, "target:0=",<&csi0>; ++ ++ cam0-sync-source = <&imx477_0>, "trigger-mode:0=1"; ++ cam0-sync-sink = <&imx477_0>, "trigger-mode:0=2"; ++ cam1-sync-source = <&imx477_1>, "trigger-mode:0=1"; ++ cam1-sync-sink = <&imx477_1>, "trigger-mode:0=2"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/camera-mux-4port-overlay.dts b/arch/arm/boot/dts/overlays/camera-mux-4port-overlay.dts +new file mode 100644 +index 000000000000..c8f8f594cd61 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/camera-mux-4port-overlay.dts +@@ -0,0 +1,952 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++// Overlay to configure a 4 port camera multiplexer ++// ++// Configuration is based on the Arducam 4 channel multiplexer ++// which uses a PCA9543 I2C multiplexer to handle the ++// I2C, and GPIOs 4, 17, and 18 to control the MIPI muxes. ++ ++/dts-v1/; ++/plugin/; ++ ++#include <dt-bindings/gpio/gpio.h> ++ ++/{ ++ compatible = "brcm,bcm2835"; ++ ++ /* Fragments that complete the individual sensor fragments */ ++ /* IMX290 */ ++ fragment@0 { ++ target = <&imx290_0_ep>; ++ __overlay__ { ++ data-lanes = <1 2>; ++ link-frequencies = ++ /bits/ 64 <445500000 297000000>; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&imx290_1_ep>; ++ __overlay__ { ++ data-lanes = <1 2>; ++ link-frequencies = ++ /bits/ 64 <445500000 297000000>; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&imx290_2_ep>; ++ __overlay__ { ++ data-lanes = <1 2>; ++ link-frequencies = ++ /bits/ 64 <445500000 297000000>; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&imx290_3_ep>; ++ __overlay__ { ++ data-lanes = <1 2>; ++ link-frequencies = ++ /bits/ 64 <445500000 297000000>; ++ }; ++ }; ++ ++ /* IMX477 */ ++ fragment@10 { ++ target = <&imx477_0>; ++ __overlay__ { ++ compatible = "sony,imx477"; ++ }; ++ }; ++ ++ fragment@11 { ++ target = <&imx477_1>; ++ __overlay__ { ++ compatible = "sony,imx477"; ++ }; ++ }; ++ ++ fragment@12 { ++ target = <&imx477_2>; ++ __overlay__ { ++ compatible = "sony,imx477"; ++ }; ++ }; ++ ++ fragment@13 { ++ target = <&imx477_3>; ++ __overlay__ { ++ compatible = "sony,imx477"; ++ }; ++ }; ++ ++ /* Additional fragments affecting the mux nodes */ ++ fragment@100 { ++ target = <&mux_in0>; ++ __dormant__ { ++ data-lanes = <1>; ++ }; ++ }; ++ fragment@101 { ++ target = <&mux_in0>; ++ __overlay__ { ++ data-lanes = <1 2>; ++ }; ++ }; ++ ++ fragment@102 { ++ target = <&mux_in1>; ++ __dormant__ { ++ data-lanes = <1>; ++ }; ++ }; ++ fragment@103 { ++ target = <&mux_in1>; ++ __overlay__ { ++ data-lanes = <1 2>; ++ }; ++ }; ++ ++ fragment@104 { ++ target = <&mux_in2>; ++ __dormant__ { ++ data-lanes = <1>; ++ }; ++ }; ++ fragment@105 { ++ target = <&mux_in2>; ++ __overlay__ { ++ data-lanes = <1 2>; ++ }; ++ }; ++ ++ fragment@106 { ++ target = <&mux_in3>; ++ __dormant__ { ++ data-lanes = <1>; ++ }; ++ }; ++ fragment@107 { ++ target = <&mux_in3>; ++ __overlay__ { ++ data-lanes = <1 2>; ++ }; ++ }; ++ ++ /* Mux define */ ++ i2c_frag: fragment@200 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ pca@70 { ++ reg = <0x70>; ++ compatible = "nxp,pca9544"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ i2c@0 { ++ reg = <0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ #define cam_node arducam_64mp_0 ++ #define cam_endpoint arducam_64mp_0_ep ++ #define vcm_node arducam_64mp_0_vcm ++ #define cam1_clk clk_24mhz ++ #include "arducam-64mp.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node imx219_0 ++ #define cam_endpoint imx219_0_ep ++ #define cam1_clk clk_24mhz ++ #include "imx219.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx477_0 ++ #define cam_endpoint imx477_0_ep ++ #define cam1_clk clk_24mhz ++ #include "imx477_378.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx519_0 ++ #define cam_endpoint imx519_0_ep ++ #define vcm_node imx519_0_vcm ++ #define cam1_clk clk_24mhz ++ #include "imx519.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node imx708_0 ++ #define cam_endpoint imx708_0_ep ++ #define vcm_node imx708_0_vcm ++ #define cam1_clk clk_24mhz ++ #include "imx708.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node ov5647_0 ++ #define cam_endpoint ov5647_0_ep ++ #define cam1_clk clk_25mhz ++ #include "ov5647.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov7251_0 ++ #define cam_endpoint ov7251_0_ep ++ #define cam1_clk clk_24mhz ++ #include "ov7251.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov9281_0 ++ #define cam_endpoint ov9281_0_ep ++ #define cam1_clk clk_24mhz ++ #include "ov9281.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx258_0 ++ #define cam_endpoint imx258_0_ep ++ #define cam1_clk clk_24mhz ++ #include "imx258.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx290_0 ++ #define cam_endpoint imx290_0_ep ++ #define cam1_clk clk_imx290 ++ #include "imx290_327.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov2311_0 ++ #define cam_endpoint ov2311_0_ep ++ #define cam1_clk clk_24mhz ++ #include "ov2311.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov64a40_0 ++ #define cam_endpoint ov64a40_0_ep ++ #define vcm_node ov64a40_0_vcm ++ #define cam1_clk clk_24mhz ++ #include "ov64a40.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ }; ++ ++ i2c@1 { ++ reg = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ #define cam_node arducam_64mp_1 ++ #define cam_endpoint arducam_64mp_1_ep ++ #define vcm_node arducam_64mp_1_vcm ++ #define cam1_clk clk_24mhz ++ #include "arducam-64mp.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node imx219_1 ++ #define cam_endpoint imx219_1_ep ++ #define cam1_clk clk_24mhz ++ #include "imx219.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx477_1 ++ #define cam_endpoint imx477_1_ep ++ #define cam1_clk clk_24mhz ++ #include "imx477_378.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx519_1 ++ #define cam_endpoint imx519_1_ep ++ #define vcm_node imx519_1_vcm ++ #define cam1_clk clk_24mhz ++ #include "imx519.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node imx708_1 ++ #define cam_endpoint imx708_1_ep ++ #define vcm_node imx708_1_vcm ++ #define cam1_clk clk_24mhz ++ #include "imx708.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node ov5647_1 ++ #define cam_endpoint ov5647_1_ep ++ #define cam1_clk clk_25mhz ++ #include "ov5647.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov7251_1 ++ #define cam_endpoint ov7251_1_ep ++ #define cam1_clk clk_24mhz ++ #include "ov7251.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov9281_1 ++ #define cam_endpoint ov9281_1_ep ++ #define cam1_clk clk_24mhz ++ #include "ov9281.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx258_1 ++ #define cam_endpoint imx258_1_ep ++ #define cam1_clk clk_24mhz ++ #include "imx258.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx290_1 ++ #define cam_endpoint imx290_1_ep ++ #define cam1_clk clk_imx290 ++ #include "imx290_327.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov2311_1 ++ #define cam_endpoint ov2311_1_ep ++ #define cam1_clk clk_24mhz ++ #include "ov2311.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov64a40_1 ++ #define cam_endpoint ov64a40_1_ep ++ #define vcm_node ov64a40_1_vcm ++ #define cam1_clk clk_24mhz ++ #include "ov64a40.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ }; ++ ++ i2c@2 { ++ reg = <2>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ #define cam_node arducam_64mp_2 ++ #define cam_endpoint arducam_64mp_2_ep ++ #define vcm_node arducam_64mp_2_vcm ++ #define cam1_clk clk_24mhz ++ #include "arducam-64mp.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node imx219_2 ++ #define cam_endpoint imx219_2_ep ++ #define cam1_clk clk_24mhz ++ #include "imx219.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx477_2 ++ #define cam_endpoint imx477_2_ep ++ #define cam1_clk clk_24mhz ++ #include "imx477_378.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx519_2 ++ #define cam_endpoint imx519_2_ep ++ #define vcm_node imx519_2_vcm ++ #define cam1_clk clk_24mhz ++ #include "imx519.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node imx708_2 ++ #define cam_endpoint imx708_2_ep ++ #define vcm_node imx708_2_vcm ++ #define cam1_clk clk_24mhz ++ #include "imx708.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node ov5647_2 ++ #define cam_endpoint ov5647_2_ep ++ #define cam1_clk clk_25mhz ++ #include "ov5647.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov7251_2 ++ #define cam_endpoint ov7251_2_ep ++ #define cam1_clk clk_24mhz ++ #include "ov7251.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov9281_2 ++ #define cam_endpoint ov9281_2_ep ++ #define cam1_clk clk_24mhz ++ #include "ov9281.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx258_2 ++ #define cam_endpoint imx258_2_ep ++ #define cam1_clk clk_24mhz ++ #include "imx258.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx290_2 ++ #define cam_endpoint imx290_2_ep ++ #define cam1_clk clk_imx290 ++ #include "imx290_327.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov2311_2 ++ #define cam_endpoint ov2311_2_ep ++ #define cam1_clk clk_24mhz ++ #include "ov2311.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov64a40_2 ++ #define cam_endpoint ov64a40_2_ep ++ #define vcm_node ov64a40_2_vcm ++ #define cam1_clk clk_24mhz ++ #include "ov64a40.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ }; ++ ++ i2c@3 { ++ reg = <3>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ #define cam_node arducam_64mp_3 ++ #define cam_endpoint arducam_64mp_3_ep ++ #define vcm_node arducam_64mp_3_vcm ++ #define cam1_clk clk_24mhz ++ #include "arducam-64mp.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node imx219_3 ++ #define cam_endpoint imx219_3_ep ++ #define cam1_clk clk_24mhz ++ #include "imx219.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx477_3 ++ #define cam_endpoint imx477_3_ep ++ #define cam1_clk clk_24mhz ++ #include "imx477_378.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx519_3 ++ #define cam_endpoint imx519_3_ep ++ #define vcm_node imx519_3_vcm ++ #define cam1_clk clk_24mhz ++ #include "imx519.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node imx708_3 ++ #define cam_endpoint imx708_3_ep ++ #define vcm_node imx708_3_vcm ++ #define cam1_clk clk_24mhz ++ #include "imx708.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ ++ #define cam_node ov5647_3 ++ #define cam_endpoint ov5647_3_ep ++ #define cam1_clk clk_25mhz ++ #include "ov5647.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov7251_3 ++ #define cam_endpoint ov7251_3_ep ++ #define cam1_clk clk_24mhz ++ #include "ov7251.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov9281_3 ++ #define cam_endpoint ov9281_3_ep ++ #define cam1_clk clk_24mhz ++ #include "ov9281.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx258_3 ++ #define cam_endpoint imx258_3_ep ++ #define cam1_clk clk_24mhz ++ #include "imx258.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node imx290_3 ++ #define cam_endpoint imx290_3_ep ++ #define cam1_clk clk_imx290 ++ #include "imx290_327.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov2311_3 ++ #define cam_endpoint ov2311_3_ep ++ #define cam1_clk clk_24mhz ++ #include "ov2311.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef cam1_clk ++ ++ #define cam_node ov64a40_3 ++ #define cam_endpoint ov64a40_3_ep ++ #define vcm_node ov64a40_3_vcm ++ #define cam1_clk clk_24mhz ++ #include "ov64a40.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk ++ }; ++ }; ++ }; ++ }; ++ ++ csi_frag: fragment@201 { ++ target = <&csi1>; ++ __overlay__ { ++ status = "okay"; ++ ++ brcm,media-controller; ++ ++ port { ++ csi1_ep: endpoint { ++ remote-endpoint = <&mux_out>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@202 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@203 { ++ target-path="/"; ++ __overlay__ { ++ mux: mux-controller { ++ compatible = "gpio-mux"; ++ #mux-control-cells = <0>; ++ ++ /* SEL, En2, En1 */ ++ mux-gpios = <&gpio 4 GPIO_ACTIVE_HIGH>, ++ <&gpio 18 GPIO_ACTIVE_HIGH>, ++ <&gpio 17 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ video-mux { ++ compatible = "video-mux"; ++ mux-controls = <&mux>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ /* GPIO mappings settings for selecting the different ++ * camera connectors are not direct, hence port@ values ++ * are not straight forward. ++ */ ++ port@2 { ++ /* Port A - GPIO 17 = 0, GPIO 18 = 1,GPIO 4 = 0 */ ++ reg = <2>; ++ ++ mux_in0: endpoint { ++ clock-lanes = <0>; ++ }; ++ }; ++ ++ port@3 { ++ /* Port B - GPIO 17 = 0, GPIO 18 = 1,GPIO 4 = 1 */ ++ reg = <3>; ++ ++ mux_in1: endpoint { ++ clock-lanes = <0>; ++ }; ++ }; ++ ++ port@4 { ++ /* Port C - GPIO 17 = 1, GPIO 18 = 0, GPIO 4 = 0 */ ++ reg = <4>; ++ ++ mux_in2: endpoint { ++ clock-lanes = <0>; ++ }; ++ }; ++ ++ port@5 { ++ /* Port D - GPIO 17 = 1, GPIO 18 = 0, GPIO 4 = 1 */ ++ reg = <5>; ++ ++ mux_in3: endpoint { ++ clock-lanes = <0>; ++ }; ++ }; ++ ++ port@6 { ++ /* Output port needs to be the highest port number */ ++ reg = <6>; ++ ++ mux_out: endpoint { ++ remote-endpoint = <&csi1_ep>; ++ clock-lanes = <0>; ++ }; ++ }; ++ }; ++ ++ clk_24mhz: clk_24mhz { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ ++ clock-frequency = <24000000>; ++ status = "okay"; ++ }; ++ ++ clk_25mhz: clk_25mhz { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ ++ clock-frequency = <25000000>; ++ status = "okay"; ++ }; ++ ++ clk_imx290: clk_imx290 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ ++ clock-frequency = <37125000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@204 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ __overrides__ { ++ cam0-arducam-64mp = <&mux_in0>, "remote-endpoint:0=",<&arducam_64mp_0_ep>, ++ <&arducam_64mp_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&mux_in0>, "clock-noncontinuous?", ++ <&arducam_64mp_0>, "status=okay", ++ <&arducam_64mp_0_vcm>, "status=okay", ++ <&arducam_64mp_0>,"lens-focus:0=", <&arducam_64mp_0_vcm>; ++ cam0-imx219 = <&mux_in0>, "remote-endpoint:0=",<&imx219_0_ep>, ++ <&imx219_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&mux_in0>, "clock-noncontinuous?", ++ <&imx219_0>, "status=okay"; ++ cam0-imx477 = <&mux_in0>, "remote-endpoint:0=",<&imx477_0_ep>, ++ <&imx477_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&mux_in0>, "clock-noncontinuous?", ++ <&imx477_0>, "status=okay"; ++ cam0-imx519 = <&mux_in0>, "remote-endpoint:0=",<&imx519_0_ep>, ++ <&imx519_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&mux_in0>, "clock-noncontinuous?", ++ <&imx519_0>, "status=okay", ++ <&imx519_0_vcm>, "status=okay", ++ <&imx519_0>,"lens-focus:0=", <&imx519_0_vcm>; ++ cam0-imx708 = <&mux_in0>, "remote-endpoint:0=",<&imx708_0_ep>, ++ <&imx708_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&mux_in0>, "clock-noncontinuous?", ++ <&imx708_0>, "status=okay", ++ <&imx708_0_vcm>, "status=okay", ++ <&imx708_0>,"lens-focus:0=", <&imx708_0_vcm>; ++ cam0-ov5647 = <&mux_in0>, "remote-endpoint:0=",<&ov5647_0_ep>, ++ <&ov5647_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&ov5647_0>, "status=okay"; ++ cam0-ov7251 = <&mux_in0>, "remote-endpoint:0=",<&ov7251_0_ep>, ++ <&ov7251_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&ov7251_0>, "status=okay", ++ <0>,"+100-101"; ++ cam0-ov9281 = <&mux_in0>, "remote-endpoint:0=",<&ov9281_0_ep>, ++ <&ov9281_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&ov9281_0>, "status=okay"; ++ cam0-imx258 = <&mux_in0>, "remote-endpoint:0=",<&imx258_0_ep>, ++ <&imx258_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&imx258_0>, "status=okay"; ++ cam0-imx290 = <&mux_in0>, "remote-endpoint:0=",<&imx290_0_ep>, ++ <&imx290_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&imx290_0>, "status=okay"; ++ cam0-ov2311 = <&mux_in0>, "remote-endpoint:0=",<&ov2311_0_ep>, ++ <&ov2311_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&ov2311_0>, "status=okay"; ++ cam0-ov64a40 = <&mux_in0>, "remote-endpoint:0=",<&ov64a40_0_ep>, ++ <&ov64a40_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&mux_in0>, "clock-noncontinuous?", ++ <&ov64a40_0>, "status=okay", ++ <&ov64a40_0_vcm>, "status=okay", ++ <&ov64a40_0>,"lens-focus:0=", <&ov64a40_0_vcm>; ++ ++ cam1-arducam-64mp = <&mux_in1>, "remote-endpoint:0=",<&arducam_64mp_1_ep>, ++ <&arducam_64mp_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&mux_in1>, "clock-noncontinuous?", ++ <&arducam_64mp_1>, "status=okay", ++ <&arducam_64mp_1_vcm>, "status=okay", ++ <&arducam_64mp_1>,"lens-focus:0=", <&arducam_64mp_1_vcm>; ++ cam1-imx219 = <&mux_in1>, "remote-endpoint:0=",<&imx219_1_ep>, ++ <&imx219_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&mux_in1>, "clock-noncontinuous?", ++ <&imx219_1>, "status=okay"; ++ cam1-imx477 = <&mux_in1>, "remote-endpoint:0=",<&imx477_1_ep>, ++ <&imx477_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&mux_in1>, "clock-noncontinuous?", ++ <&imx477_1>, "status=okay"; ++ cam1-imx519 = <&mux_in1>, "remote-endpoint:0=",<&imx519_1_ep>, ++ <&imx519_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&mux_in1>, "clock-noncontinuous?", ++ <&imx519_1>, "status=okay", ++ <&imx519_1_vcm>, "status=okay", ++ <&imx519_1>,"lens-focus:0=", <&imx519_1_vcm>; ++ cam1-imx708 = <&mux_in1>, "remote-endpoint:0=",<&imx708_1_ep>, ++ <&imx708_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&mux_in1>, "clock-noncontinuous?", ++ <&imx708_1>, "status=okay", ++ <&imx708_1_vcm>, "status=okay", ++ <&imx708_1>,"lens-focus:0=", <&imx708_1_vcm>; ++ cam1-ov5647 = <&mux_in1>, "remote-endpoint:0=",<&ov5647_1_ep>, ++ <&ov5647_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&ov5647_1>, "status=okay"; ++ cam1-ov7251 = <&mux_in1>, "remote-endpoint:0=",<&ov7251_1_ep>, ++ <&ov7251_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&ov7251_1>, "status=okay", ++ <0>,"+102-103"; ++ cam1-ov9281 = <&mux_in1>, "remote-endpoint:0=",<&ov9281_1_ep>, ++ <&ov9281_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&ov9281_1>, "status=okay"; ++ cam1-imx258 = <&mux_in1>, "remote-endpoint:0=",<&imx258_1_ep>, ++ <&imx258_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&imx258_1>, "status=okay"; ++ cam1-imx290 = <&mux_in1>, "remote-endpoint:0=",<&imx290_1_ep>, ++ <&imx290_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&imx290_1>, "status=okay"; ++ cam1-ov2311 = <&mux_in1>, "remote-endpoint:0=",<&ov2311_1_ep>, ++ <&ov2311_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&ov2311_1>, "status=okay"; ++ cam1-ov64a40 = <&mux_in1>, "remote-endpoint:0=",<&ov64a40_1_ep>, ++ <&ov64a40_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&mux_in1>, "clock-noncontinuous?", ++ <&ov64a40_1>, "status=okay", ++ <&ov64a40_1_vcm>, "status=okay", ++ <&ov64a40_1>,"lens-focus:0=", <&ov64a40_1_vcm>; ++ ++ cam2-arducam-64mp = <&mux_in2>, "remote-endpoint:0=",<&arducam_64mp_2_ep>, ++ <&arducam_64mp_2_ep>, "remote-endpoint:0=",<&mux_in2>, ++ <&mux_in2>, "clock-noncontinuous?", ++ <&arducam_64mp_2>, "status=okay", ++ <&arducam_64mp_2_vcm>, "status=okay", ++ <&arducam_64mp_2>,"lens-focus:0=", <&arducam_64mp_2_vcm>; ++ cam2-imx219 = <&mux_in2>, "remote-endpoint:0=",<&imx219_2_ep>, ++ <&imx219_2_ep>, "remote-endpoint:0=",<&mux_in2>, ++ <&mux_in2>, "clock-noncontinuous?", ++ <&imx219_2>, "status=okay"; ++ cam2-imx477 = <&mux_in2>, "remote-endpoint:0=",<&imx477_2_ep>, ++ <&imx477_2_ep>, "remote-endpoint:0=",<&mux_in2>, ++ <&mux_in2>, "clock-noncontinuous?", ++ <&imx477_2>, "status=okay"; ++ cam2-imx519 = <&mux_in2>, "remote-endpoint:0=",<&imx519_2_ep>, ++ <&imx519_2_ep>, "remote-endpoint:0=",<&mux_in2>, ++ <&mux_in2>, "clock-noncontinuous?", ++ <&imx519_2>, "status=okay", ++ <&imx519_2_vcm>, "status=okay", ++ <&imx519_2>,"lens-focus:0=", <&imx519_2_vcm>; ++ cam2-imx708 = <&mux_in2>, "remote-endpoint:0=",<&imx708_2_ep>, ++ <&imx708_2_ep>, "remote-endpoint:0=",<&mux_in2>, ++ <&mux_in2>, "clock-noncontinuous?", ++ <&imx708_2>, "status=okay", ++ <&imx708_2_vcm>, "status=okay", ++ <&imx708_2>,"lens-focus:0=", <&imx708_2_vcm>; ++ cam2-ov5647 = <&mux_in2>, "remote-endpoint:0=",<&ov5647_2_ep>, ++ <&ov5647_2_ep>, "remote-endpoint:0=",<&mux_in2>, ++ <&ov5647_2>, "status=okay"; ++ cam2-ov7251 = <&mux_in2>, "remote-endpoint:0=",<&ov7251_2_ep>, ++ <&ov7251_2_ep>, "remote-endpoint:0=",<&mux_in2>, ++ <&ov7251_2>, "status=okay", ++ <0>,"+104-105"; ++ cam2-ov9281 = <&mux_in2>, "remote-endpoint:0=",<&ov9281_2_ep>, ++ <&ov9281_2_ep>, "remote-endpoint:0=",<&mux_in2>, ++ <&ov9281_2>, "status=okay"; ++ cam2-imx258 = <&mux_in2>, "remote-endpoint:0=",<&imx258_2_ep>, ++ <&imx258_2>, "status=okay", ++ <&imx258_2>, "remote-endpoint:0=",<&mux_in2>; ++ cam2-imx290 = <&mux_in2>, "remote-endpoint:0=",<&imx290_2_ep>, ++ <&imx290_2_ep>, "remote-endpoint:0=",<&mux_in2>, ++ <&imx290_2>, "status=okay"; ++ cam2-ov2311 = <&mux_in2>, "remote-endpoint:0=",<&ov2311_2_ep>, ++ <&ov2311_2_ep>, "remote-endpoint:0=",<&mux_in2>, ++ <&ov2311_2>, "status=okay"; ++ cam2-ov64a40 = <&mux_in2>, "remote-endpoint:0=",<&ov64a40_2_ep>, ++ <&ov64a40_2_ep>, "remote-endpoint:0=",<&mux_in2>, ++ <&mux_in2>, "clock-noncontinuous?", ++ <&ov64a40_2>, "status=okay", ++ <&ov64a40_2_vcm>, "status=okay", ++ <&ov64a40_2>,"lens-focus:0=", <&ov64a40_2_vcm>; ++ ++ cam3-arducam-64mp = <&mux_in3>, "remote-endpoint:0=",<&arducam_64mp_3_ep>, ++ <&arducam_64mp_3_ep>, "remote-endpoint:0=",<&mux_in3>, ++ <&mux_in3>, "clock-noncontinuous?", ++ <&arducam_64mp_3>, "status=okay", ++ <&arducam_64mp_3_vcm>, "status=okay", ++ <&arducam_64mp_3>,"lens-focus:0=", <&arducam_64mp_3_vcm>; ++ cam3-imx219 = <&mux_in3>, "remote-endpoint:0=",<&imx219_3_ep>, ++ <&imx219_3_ep>, "remote-endpoint:0=",<&mux_in3>, ++ <&mux_in3>, "clock-noncontinuous?", ++ <&imx219_3>, "status=okay"; ++ cam3-imx477 = <&mux_in3>, "remote-endpoint:0=",<&imx477_3_ep>, ++ <&imx477_3_ep>, "remote-endpoint:0=",<&mux_in3>, ++ <&mux_in3>, "clock-noncontinuous?", ++ <&imx477_3>, "status=okay"; ++ cam3-imx519 = <&mux_in3>, "remote-endpoint:0=",<&imx519_3_ep>, ++ <&imx519_3_ep>, "remote-endpoint:0=",<&mux_in3>, ++ <&mux_in3>, "clock-noncontinuous?", ++ <&imx519_3>, "status=okay", ++ <&imx519_3_vcm>, "status=okay", ++ <&imx519_3>,"lens-focus:0=", <&imx519_3_vcm>; ++ cam3-imx708 = <&mux_in3>, "remote-endpoint:0=",<&imx708_3_ep>, ++ <&imx708_3_ep>, "remote-endpoint:0=",<&mux_in3>, ++ <&mux_in3>, "clock-noncontinuous?", ++ <&imx708_3>, "status=okay", ++ <&imx708_3_vcm>, "status=okay", ++ <&imx708_3>,"lens-focus:0=", <&imx708_3_vcm>; ++ cam3-ov5647 = <&mux_in3>, "remote-endpoint:0=",<&ov5647_3_ep>, ++ <&ov5647_3_ep>, "remote-endpoint:0=",<&mux_in3>, ++ <&ov5647_3>, "status=okay"; ++ cam3-ov7251 = <&mux_in3>, "remote-endpoint:0=",<&ov7251_3_ep>, ++ <&ov7251_3_ep>, "remote-endpoint:0=",<&mux_in3>, ++ <&ov7251_3>, "status=okay", ++ <0>,"+106-107"; ++ cam3-ov9281 = <&mux_in3>, "remote-endpoint:0=",<&ov9281_3_ep>, ++ <&ov9281_3_ep>, "remote-endpoint:0=",<&mux_in3>, ++ <&ov9281_3>, "status=okay"; ++ cam3-imx258 = <&mux_in3>, "remote-endpoint:0=",<&imx258_3_ep>, ++ <&imx258_3_ep>, "remote-endpoint:0=",<&mux_in3>, ++ <&imx258_3>, "status=okay"; ++ cam3-imx290 = <&mux_in3>, "remote-endpoint:0=",<&imx290_3_ep>, ++ <&imx290_3_ep>, "remote-endpoint:0=",<&mux_in3>, ++ <&imx290_3>, "status=okay"; ++ cam3-ov2311 = <&mux_in3>, "remote-endpoint:0=",<&ov2311_3_ep>, ++ <&ov2311_3_ep>, "remote-endpoint:0=",<&mux_in3>, ++ <&ov2311_3>, "status=okay"; ++ cam3-ov64a40 = <&mux_in3>, "remote-endpoint:0=",<&ov64a40_3_ep>, ++ <&ov64a40_3_ep>, "remote-endpoint:0=",<&mux_in3>, ++ <&mux_in3>, "clock-noncontinuous?", ++ <&ov64a40_3>, "status=okay", ++ <&ov64a40_3_vcm>, "status=okay", ++ <&ov64a40_3>,"lens-focus:0=", <&ov64a40_3_vcm>; ++ ++ cam0-imx290-clk-freq = <&clk_imx290>,"clock-frequency:0", ++ <&imx290_0>,"clock-frequency:0"; ++ cam1-imx290-clk-freq = <&clk_imx290>,"clock-frequency:0", ++ <&imx290_1>,"clock-frequency:0"; ++ cam2-imx290-clk-freq = <&clk_imx290>,"clock-frequency:0", ++ <&imx290_2>,"clock-frequency:0"; ++ cam3-imx290-clk-freq = <&clk_imx290>,"clock-frequency:0", ++ <&imx290_3>,"clock-frequency:0"; ++ ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&csi_frag>, "target:0=",<&csi0>; ++ ++ cam0-sync-source = <&imx477_0>, "trigger-mode:0=1"; ++ cam0-sync-sink = <&imx477_0>, "trigger-mode:0=2"; ++ cam1-sync-source = <&imx477_1>, "trigger-mode:0=1"; ++ cam1-sync-sink = <&imx477_1>, "trigger-mode:0=2"; ++ cam2-sync-source = <&imx477_2>, "trigger-mode:0=1"; ++ cam2-sync-sink = <&imx477_2>, "trigger-mode:0=2"; ++ cam3-sync-source = <&imx477_3>, "trigger-mode:0=1"; ++ cam3-sync-sink = <&imx477_3>, "trigger-mode:0=2"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/cap1106-overlay.dts b/arch/arm/boot/dts/overlays/cap1106-overlay.dts new file mode 100644 index 000000000000..0a585e725f84 @@ -16020,7 +25667,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/chipdip-dac-overlay.dts b/arch/arm/boot/dts/overlays/chipdip-dac-overlay.dts new file mode 100644 -index 000000000000..09c7417b4707 +index 000000000000..3ef7565a9312 --- /dev/null +++ b/arch/arm/boot/dts/overlays/chipdip-dac-overlay.dts @@ -0,0 +1,46 @@ @@ -16035,7 +25682,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -16058,7 +25705,7 @@ + target = <&sound>; + __overlay__ { + compatible = "chipdip,chipdip-dac"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + sr0-gpios = <&gpio 5 0>; + sr1-gpios = <&gpio 6 0>; + sr2-gpios = <&gpio 12 0>; @@ -16070,6 +25717,217 @@ + }; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/cirrus-wm5102-overlay.dts b/arch/arm/boot/dts/overlays/cirrus-wm5102-overlay.dts +new file mode 100644 +index 000000000000..a82b422ba16e +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/cirrus-wm5102-overlay.dts +@@ -0,0 +1,172 @@ ++// 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_clk_consumer>; ++ __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_clk_consumer>; ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/cm-swap-i2c0-overlay.dts b/arch/arm/boot/dts/overlays/cm-swap-i2c0-overlay.dts +new file mode 100644 +index 000000000000..6b7f599f7611 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/cm-swap-i2c0-overlay.dts +@@ -0,0 +1,27 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Definitions for IMX708 camera module on VC I2C bus ++/dts-v1/; ++/plugin/; ++ ++#include <dt-bindings/gpio/gpio.h> ++ ++/{ ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2c0mux>; ++ i2c0mux_frag: __overlay__ { ++ pinctrl-0 = <&i2c0_gpio28>; ++ pinctrl-1 = <&i2c0_gpio0>; ++ }; ++ }; ++ ++ __overrides__ { ++ i2c0-gpio0 = <&i2c0mux_frag>, "pinctrl-0:0=",<&i2c0_gpio0>; ++ i2c0-gpio28 = <&i2c0mux_frag>, "pinctrl-0:0=",<&i2c0_gpio28>; ++ i2c0-gpio44 = <&i2c0mux_frag>, "pinctrl-0:0=",<&i2c0_gpio44>; ++ i2c10-gpio0 = <&i2c0mux_frag>, "pinctrl-1:0=",<&i2c0_gpio0>; ++ i2c10-gpio28 = <&i2c0mux_frag>, "pinctrl-1:0=",<&i2c0_gpio28>; ++ i2c10-gpio44 = <&i2c0mux_frag>, "pinctrl-1:0=",<&i2c0_gpio44>; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/cma-overlay.dts b/arch/arm/boot/dts/overlays/cma-overlay.dts new file mode 100644 index 000000000000..1d87c599f909 @@ -16112,9 +25970,139 @@ + cma-default = <0>,"-0"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/crystalfontz-cfa050_pi_m-overlay.dts b/arch/arm/boot/dts/overlays/crystalfontz-cfa050_pi_m-overlay.dts +new file mode 100644 +index 000000000000..544036589b66 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/crystalfontz-cfa050_pi_m-overlay.dts +@@ -0,0 +1,124 @@ ++/* ++ * crystalfontz-cfa050_pi_m-overlay.dts ++ * Configures the Crystalfontz CFA050-PI-M series of modules ++ * using CFAF7201280A0-050TC/TN panels with RaspberryPi CM4 DSI1 ++ */ ++/dts-v1/; ++/plugin/; ++/{ ++// RaspberryPi CM4 ++ compatible = "brcm,bcm2835"; ++// PCF8574 I2C GPIO EXPANDER ++ fragment@0 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ pcf8574a: pcf8574a@38 { ++ reg = <0x38>; ++ compatible = "nxp,pcf8574"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ngpios = <8>; ++ gpio-line-names = "TFT_RESET", "TOUCH_RESET", "EXT_P2", "EXT_P3", ++ "EXT_P4", "EXT_P5", "EXT_P6", "EXT_P7"; ++ }; ++ }; ++ }; ++// LM3630a BACKLIGHT LED CONTROLLER ++ fragment@1 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ lm3630a: backlight@36 { ++ reg = <0x36>; ++ compatible = "ti,lm3630a"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ led@0 { ++ reg = <0>; ++ led-sources = <0 1>; ++ label = "lcd-backlight"; ++ default-brightness = <128>; ++ max-brightness = <255>; ++ }; ++ }; ++ }; ++ }; ++// CFAF7201280A0_050Tx TFT DSI PANEL ++ fragment@2 { ++ target = <&dsi1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ port { ++ dsi_out: endpoint { ++ remote-endpoint = <&panel_in>; ++ }; ++ }; ++ dsi_panel: dsi_panel@0 { ++ compatible = "crystalfontz,cfaf7201280a0_050tx"; ++ reg = <0>; ++ reset-gpios = <&pcf8574a 0 1>; ++ backlight = <&lm3630a>; ++ fps = <60>; ++ port { ++ panel_in: endpoint { ++ remote-endpoint = <&dsi_out>; ++ }; ++ }; ++ }; ++ }; ++ }; ++// rPI GPIO INPUT FOR TOUCH IC IRQ ++ fragment@3 { ++ target = <&gpio>; ++ __dormant__ { ++ gt928intpins: gt928intpins { ++ brcm,pins = <26>; ++ brcm,function = <0>; ++ brcm,pull = <1>; ++ }; ++ }; ++ }; ++// GT928 TOUCH CONTROLLER IC ++ fragment@4 { ++ target = <&i2c_csi_dsi>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ gt928@5d { ++ compatible = "goodix,gt928"; ++ reg = <0x5d>; ++ interrupt-parent = <&gpio>; ++ interrupts = <26 2>; ++ irq-gpios = <&gpio 26 0>; ++ reset-gpios = <&pcf8574a 1 1>; ++ touchscreen-inverted-x; ++ touchscreen-inverted-y; ++ }; ++ }; ++ }; ++// PCF85063A RTC on I2C ++ fragment@5 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ pcf85063a@51 { ++ compatible = "nxp,pcf85063a"; ++ reg = <0x51>; ++ }; ++ }; ++ }; ++// CAPACITIVE TOUCH OPTION FOR TFT PANEL ++ __overrides__ { ++ captouch = <0>,"+3+4"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/cutiepi-panel-overlay.dts b/arch/arm/boot/dts/overlays/cutiepi-panel-overlay.dts new file mode 100644 -index 000000000000..6f9694e81d6a +index 000000000000..d14c3698eb75 --- /dev/null +++ b/arch/arm/boot/dts/overlays/cutiepi-panel-overlay.dts @@ -0,0 +1,117 @@ @@ -16180,7 +26168,7 @@ + compatible = "pwm-backlight"; + brightness-levels = <0 6 8 12 16 24 32 40 48 64 96 128 160 192 224 255>; + default-brightness-level = <6>; -+ pwms = <&pwm 0 200000>; ++ pwms = <&pwm 0 200000 0>; + power-supply = <&vdd_3v3_reg>; + status = "okay"; + }; @@ -16235,12 +26223,89 @@ + }; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/dacberry400-overlay.dts b/arch/arm/boot/dts/overlays/dacberry400-overlay.dts +new file mode 100644 +index 000000000000..c9ac11db20de +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/dacberry400-overlay.dts +@@ -0,0 +1,71 @@ ++// Definitions for DACberry400 ++/dts-v1/; ++/plugin/; ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2s_clk_producer>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/"; ++ __overlay__ { ++ codec_1v8_reg: codec-1v8-reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "tlv320aic3104_1v8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&gpio>; ++ __overlay__ { ++ codec_rst: codec-rst { ++ brcm,pins = <26>; ++ brcm,function = <1>; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&i2c1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ tlv320aic3104@18 { ++ #sound-dai-cells = <0>; ++ reg = <0x18>; ++ ++ compatible = "ti,tlv320aic3x"; ++ AVDD-supply = <&vdd_3v3_reg>; ++ DRVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&codec_1v8_reg>; ++ IOVDD-supply = <&codec_1v8_reg>; ++ ++ gpio-controller; ++ reset-gpios = <&gpio 26 1>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&sound>; ++ __overlay__ { ++ compatible = "osaelectronics,dacberry400"; ++ i2s-controller = <&i2s_clk_producer>; ++ status = "okay"; ++ }; ++ }; ++}; ++ ++ diff --git a/arch/arm/boot/dts/overlays/dht11-overlay.dts b/arch/arm/boot/dts/overlays/dht11-overlay.dts new file mode 100644 -index 000000000000..6feeeb402493 +index 000000000000..8b0fc6b7a3cb --- /dev/null +++ b/arch/arm/boot/dts/overlays/dht11-overlay.dts -@@ -0,0 +1,41 @@ +@@ -0,0 +1,48 @@ +/* + * Overlay for the DHT11/21/22 humidity/temperature sensor modules. + */ @@ -16253,13 +26318,19 @@ + fragment@0 { + target-path = "/"; + __overlay__ { -+ -+ dht11: dht11@0 { ++ dht11: dht11@4 { + compatible = "dht11"; + pinctrl-names = "default"; + pinctrl-0 = <&dht11_pins>; + gpios = <&gpio 4 0>; + status = "okay"; ++ #io-channel-cells = <1>; ++ }; ++ ++ iio: iio-hwmon@4 { ++ compatible = "iio-hwmon"; ++ status = "okay"; ++ io-channels = <&dht11 0>, <&dht11 1>; + }; + }; + }; @@ -16267,7 +26338,7 @@ + fragment@1 { + target = <&gpio>; + __overlay__ { -+ dht11_pins: dht11_pins@0 { ++ dht11_pins: dht11_pins@4 { + brcm,pins = <4>; + brcm,function = <0>; // in + brcm,pull = <0>; // off @@ -16279,12 +26350,58 @@ + gpiopin = <&dht11_pins>,"brcm,pins:0", + <&dht11_pins>, "reg:0", + <&dht11>,"gpios:4", -+ <&dht11>,"reg:0"; ++ <&dht11>,"reg:0", ++ <&iio>,"reg:0"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/dionaudio-kiwi-overlay.dts b/arch/arm/boot/dts/overlays/dionaudio-kiwi-overlay.dts +new file mode 100644 +index 000000000000..ab0144cd17dc +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/dionaudio-kiwi-overlay.dts +@@ -0,0 +1,39 @@ ++// Definitions for Dion Audio KIWI streamer ++ ++/* ++ * PCM1794 DAC (in hardware mode). ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2s_clk_producer>; ++ __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 = "dionaudio,dionaudio-kiwi"; ++ i2s-controller = <&i2s_clk_producer>; ++ status = "okay"; ++ }; + }; +}; diff --git a/arch/arm/boot/dts/overlays/dionaudio-loco-overlay.dts b/arch/arm/boot/dts/overlays/dionaudio-loco-overlay.dts new file mode 100644 -index 000000000000..d863e5c167cc +index 000000000000..6f4a9c1a8243 --- /dev/null +++ b/arch/arm/boot/dts/overlays/dionaudio-loco-overlay.dts @@ -0,0 +1,39 @@ @@ -16301,7 +26418,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -16322,14 +26439,14 @@ + target = <&sound>; + __overlay__ { + compatible = "dionaudio,loco-pcm5242-tpa3118"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts b/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts new file mode 100644 -index 000000000000..dfb8922a654b +index 000000000000..975a844eb272 --- /dev/null +++ b/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts @@ -0,0 +1,49 @@ @@ -16350,13 +26467,13 @@ + target = <&sound>; + frag0: __overlay__ { + compatible = "dionaudio,dionaudio-loco-v2"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; + + fragment@1 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -16384,19 +26501,14 @@ +}; diff --git a/arch/arm/boot/dts/overlays/disable-bt-overlay.dts b/arch/arm/boot/dts/overlays/disable-bt-overlay.dts new file mode 100644 -index 000000000000..d5a66e5d76a9 +index 000000000000..f3a8af1375f0 --- /dev/null +++ b/arch/arm/boot/dts/overlays/disable-bt-overlay.dts -@@ -0,0 +1,64 @@ +@@ -0,0 +1,59 @@ +/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 -+*/ ++/* Disable Bluetooth and restore UART0/ttyAMA0 over GPIOs 14 & 15. */ + +#include <dt-bindings/gpio/gpio.h> + @@ -16452,6 +26564,48 @@ + }; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/disable-bt-pi5-overlay.dts b/arch/arm/boot/dts/overlays/disable-bt-pi5-overlay.dts +new file mode 100644 +index 000000000000..6e23b64d44e7 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/disable-bt-pi5-overlay.dts +@@ -0,0 +1,17 @@ ++/dts-v1/; ++/plugin/; ++ ++/* Disable Bluetooth */ ++ ++#include <dt-bindings/gpio/gpio.h> ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&bluetooth>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/disable-emmc2-overlay.dts b/arch/arm/boot/dts/overlays/disable-emmc2-overlay.dts +new file mode 100644 +index 000000000000..8cd1d7fa4a90 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/disable-emmc2-overlay.dts +@@ -0,0 +1,13 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2711"; ++ ++ fragment@0 { ++ target = <&emmc2>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/disable-wifi-overlay.dts b/arch/arm/boot/dts/overlays/disable-wifi-overlay.dts new file mode 100644 index 000000000000..75e046463900 @@ -16478,6 +26632,25 @@ + }; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/disable-wifi-pi5-overlay.dts b/arch/arm/boot/dts/overlays/disable-wifi-pi5-overlay.dts +new file mode 100644 +index 000000000000..d5389c5dbb69 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/disable-wifi-pi5-overlay.dts +@@ -0,0 +1,13 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&sdio2>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/dpi18-overlay.dts b/arch/arm/boot/dts/overlays/dpi18-overlay.dts new file mode 100644 index 000000000000..4abe5be744db @@ -16602,7 +26775,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/draws-overlay.dts b/arch/arm/boot/dts/overlays/draws-overlay.dts new file mode 100644 -index 000000000000..d18187d7f343 +index 000000000000..b8801f583369 --- /dev/null +++ b/arch/arm/boot/dts/overlays/draws-overlay.dts @@ -0,0 +1,208 @@ @@ -16617,7 +26790,7 @@ +/ { + compatible = "brcm,bcm2835"; + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -16739,7 +26912,7 @@ + target = <&sound>; + snd: __overlay__ { + compatible = "simple-audio-card"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + + simple-audio-card,name = "draws"; @@ -16761,7 +26934,7 @@ + "Line Out", "LOL"; + + dailink0_master: simple-audio-card,cpu { -+ sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + }; + + simple-audio-card,codec { @@ -16868,10 +27041,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts b/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts new file mode 100644 -index 000000000000..1210e4b8e6dc +index 000000000000..6e40c0ebb3bf --- /dev/null +++ b/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts -@@ -0,0 +1,26 @@ +@@ -0,0 +1,46 @@ +/* + * Device Tree overlay for EDT 5406 touchscreen controller, as used on the + * Raspberry Pi 7" panel @@ -16897,13 +27070,33 @@ + status = "okay"; + }; + }; ++ ++ __overrides__ { ++ i2c0 = <&ts_i2c_frag>,"target:0=",<&i2c0>; ++ i2c1 = <&ts_i2c_frag>, "target?=0", ++ <&ts_i2c_frag>, "target-path=i2c1", ++ <0>,"-0-1"; ++ i2c3 = <&ts_i2c_frag>, "target?=0", ++ <&ts_i2c_frag>, "target-path=i2c3", ++ <0>,"-0-1"; ++ i2c4 = <&ts_i2c_frag>, "target?=0", ++ <&ts_i2c_frag>, "target-path=i2c4", ++ <0>,"-0-1"; ++ i2c5 = <&ts_i2c_frag>, "target?=0", ++ <&ts_i2c_frag>, "target-path=i2c5", ++ <0>,"-0-1"; ++ i2c6 = <&ts_i2c_frag>, "target?=0", ++ <&ts_i2c_frag>, "target-path=i2c6", ++ <0>,"-0-1"; ++ addr = <&ft5406>,"reg:0"; ++ }; +}; diff --git a/arch/arm/boot/dts/overlays/edt-ft5406.dtsi b/arch/arm/boot/dts/overlays/edt-ft5406.dtsi new file mode 100644 -index 000000000000..2d0ff0e8b24e +index 000000000000..16aa5cf91df5 --- /dev/null +++ b/arch/arm/boot/dts/overlays/edt-ft5406.dtsi -@@ -0,0 +1,47 @@ +@@ -0,0 +1,49 @@ +/* + * Device Tree overlay for an EDT FT5406 touchscreen + * @@ -16928,11 +27121,13 @@ + }; + }; + -+ fragment@12 { ++ ts_i2c_frag: fragment@12 { + target = <&i2c_csi_dsi>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; ++ status = "okay"; ++ + ft5406: ts@38 { + compatible = "edt,edt-ft5506"; + reg = <0x38>; @@ -17736,7 +27931,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts b/arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts new file mode 100644 -index 000000000000..743f14ae5768 +index 000000000000..10624fe4f5ac --- /dev/null +++ b/arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts @@ -0,0 +1,70 @@ @@ -17779,7 +27974,7 @@ + #size-cells = <0>; + status = "okay"; + -+ sgtl5000@0a { ++ sgtl5000@a { + #sound-dai-cells = <0>; + compatible = "fsl,sgtl5000"; + reg = <0x0a>; @@ -17795,7 +27990,7 @@ + }; + + fragment@3 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -17805,7 +28000,7 @@ + target = <&sound>; + __overlay__ { + compatible = "fe-pi,fe-pi-audio"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; @@ -17920,9 +28115,166 @@ + fsm_debug = <&fsm_demo>,"debug:0"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/gc9a01-overlay.dts b/arch/arm/boot/dts/overlays/gc9a01-overlay.dts +new file mode 100644 +index 000000000000..3d31030c5564 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/gc9a01-overlay.dts +@@ -0,0 +1,151 @@ ++/* ++ Device Tree overlay for Galaxycore GC9A01A single chip driver ++ for use on SPI TFT LCD, 240x240 65K RGB ++ Based on Galaxycore's GC9A01A datasheet Rev.1.0 (2019/07/02) ++ Copyright (C) 2022, Julianno F. C. Silva (@juliannojungle) ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU Affero General Public License as published ++ by the Free Software Foundation, either version 3 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 Affero General Public License for more details. ++ ++ You should have received a copy of the GNU Affero General Public License ++ along with this program. If not, see <https://www.gnu.org/licenses/agpl-3.0.html>. ++ ++ Init sequence partially based on Waveshare team's Arduino LCD_Driver V1.0 (2020/12/09). ++ ++ Permission is hereby granted, free of UBYTEge, to any person obtaining a copy ++ of this software and associated documnetation files (the "Software"), to deal ++ in the Software without restriction, including without limitation the rights ++ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ copies of the Software, and to permit persons to whom the Software is ++ furished to do so, subject to the following conditions: ++ ++ The above copyright notice and this permission notice shall be included in ++ all copies or substantial portions of the Software. ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&spidev0>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ gc9a01_pins: gc9a01_pins { ++ brcm,pins = <25 27>; ++ brcm,function = <1 1>; /* out */ ++ brcm,pull = <0 0>; /* none */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ gc9a01: gc9a01@0 { ++ compatible = "ilitek,ili9340"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&gc9a01_pins>; ++ reset-gpios = <&gpio 27 1>; ++ dc-gpios = <&gpio 25 0>; ++ led-gpios = <&gpio 18 0>; ++ spi-max-frequency = <40000000>; ++ buswidth = <8>; ++ width = <240>; ++ height = <240>; ++ rotate = <0>; ++ fps = <50>; ++ bgr; ++ debug = <0>; ++ init = < ++ 0x01000011 /* Sleep mode OFF */ ++ 0x02000078 /* Delay 120ms */ ++ 0x010000EF /* Inter register enable 2 */ ++ 0x010000EB 0x14 ++ /* BEGIN set inter_command HIGH */ ++ 0x010000FE /* Inter register enable 1 */ ++ 0x010000EF /* Inter register enable 2 */ ++ /* END set inter_command HIGH */ ++ 0x010000EB 0x14 ++ 0x01000084 0x40 ++ 0x01000085 0xFF ++ 0x01000086 0xFF ++ 0x01000087 0xFF ++ 0x01000088 0x0A ++ 0x01000089 0x21 ++ 0x0100008A 0x00 ++ 0x0100008B 0x80 ++ 0x0100008C 0x01 ++ 0x0100008D 0x01 ++ 0x0100008E 0xFF ++ 0x0100008F 0xFF ++ 0x010000B6 0x00 0x00 /* Display function control */ ++ 0x01000036 0x08 /* Memory access control */ ++ 0x0100003A 0x05 /* Pixel format */ ++ 0x01000090 0x08 0x08 0x08 0x08 ++ 0x010000BD 0x06 ++ 0x010000BC 0x00 ++ 0x010000FF 0x60 0x01 0x04 ++ 0x010000C3 0x13 /* Voltage regulator 1a */ ++ 0x010000C4 0x13 /* Voltage regulator 1b */ ++ 0x010000C9 0x22 /* Voltage regulator 2a */ ++ 0x010000BE 0x11 ++ 0x010000E1 0x10 0x0E ++ 0x010000DF 0x21 0x0c 0x02 ++ 0x010000F0 0x45 0x09 0x08 0x08 0x26 0x2A /* Set gamma1 */ ++ 0x010000F1 0x43 0x70 0x72 0x36 0x37 0x6F /* Set gamma2 */ ++ 0x010000F2 0x45 0x09 0x08 0x08 0x26 0x2A /* Set gamma3 */ ++ 0x010000F3 0x43 0x70 0x72 0x36 0x37 0x6F /* Set gamma4 */ ++ 0x010000ED 0x1B 0x0B ++ 0x010000AE 0x77 ++ 0x010000CD 0x63 ++ 0x01000070 0x07 0x07 0x04 0x0E 0x0F 0x09 0x07 0x08 0x03 ++ 0x010000E8 0x34 /* Frame rate */ ++ 0x01000062 0x18 0x0D 0x71 0xED 0x70 0x70 0x18 0x0F 0x71 0xEF 0x70 0x70 ++ 0x01000063 0x18 0x11 0x71 0xF1 0x70 0x70 0x18 0x13 0x71 0xF3 0x70 0x70 ++ 0x01000064 0x28 0x29 0xF1 0x01 0xF1 0x00 0x07 ++ 0x01000066 0x3C 0x00 0xCD 0x67 0x45 0x45 0x10 0x00 0x00 0x00 ++ 0x01000067 0x00 0x3C 0x00 0x00 0x00 0x01 0x54 0x10 0x32 0x98 ++ 0x01000074 0x10 0x85 0x80 0x00 0x00 0x4E 0x00 ++ 0x01000098 0x3e 0x07 ++ 0x01000035 /* Tearing effect ON */ ++ 0x01000021 /* Display inversion ON */ ++ 0x01000011 /* Sleep mode OFF */ ++ 0x0200000C /* Delay 12ms */ ++ 0x01000029 /* Display ON */ ++ 0x02000014 /* Delay 20ms */ ++ >; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ speed = <&gc9a01>,"spi-max-frequency:0"; ++ rotate = <&gc9a01>,"rotate:0"; ++ width = <&gc9a01>,"width:0"; ++ height = <&gc9a01>,"height:0"; ++ fps = <&gc9a01>,"fps:0"; ++ debug = <&gc9a01>,"debug:0"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/ghost-amp-overlay.dts b/arch/arm/boot/dts/overlays/ghost-amp-overlay.dts new file mode 100644 -index 000000000000..7509e00679c8 +index 000000000000..d2f1e9a888e0 --- /dev/null +++ b/arch/arm/boot/dts/overlays/ghost-amp-overlay.dts @@ -0,0 +1,145 @@ @@ -17942,7 +28294,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -17971,7 +28323,7 @@ + target = <&sound>; + iqaudio_dac: __overlay__ { + compatible = "iqaudio,iqaudio-dac"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + mute-gpios = <& 0 0>; + iqaudio-dac,auto-mute-amp; + status = "okay"; @@ -18125,7 +28477,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/googlevoicehat-soundcard-overlay.dts b/arch/arm/boot/dts/overlays/googlevoicehat-soundcard-overlay.dts new file mode 100644 -index 000000000000..e443be1f9a0e +index 000000000000..1063f1898562 --- /dev/null +++ b/arch/arm/boot/dts/overlays/googlevoicehat-soundcard-overlay.dts @@ -0,0 +1,49 @@ @@ -18137,7 +28489,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -18173,17 +28525,65 @@ + target = <&sound>; + __overlay__ { + compatible = "googlevoicehat,googlevoicehat-soundcard"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/gpio-charger-overlay.dts b/arch/arm/boot/dts/overlays/gpio-charger-overlay.dts +new file mode 100644 +index 000000000000..2868aa06dd6d +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/gpio-charger-overlay.dts +@@ -0,0 +1,42 @@ ++// Definitions for gpio-charger module ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ // Configure the gpio pin controller ++ target = <&gpio>; ++ __overlay__ { ++ pin_state: charger_pins@0 { ++ brcm,pins = <4>; // gpio number ++ brcm,function = <0>; // 0 = input, 1 = output ++ brcm,pull = <1>; // 0 = none, 1 = pull down, 2 = pull up ++ }; ++ }; ++ }; ++ fragment@1 { ++ target-path = "/"; ++ __overlay__ { ++ charger: charger@0 { ++ compatible = "gpio-charger"; ++ pinctrl-0 = <&pin_state>; ++ status = "okay"; ++ gpios = <&gpio 4 0>; ++ charger-type = "mains"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ gpio = <&charger>,"reg:0", ++ <&charger>,"gpios:4", ++ <&pin_state>,"reg:0", ++ <&pin_state>,"brcm,pins:0"; ++ type = <&charger>,"charger-type"; ++ gpio_pull = <&pin_state>,"brcm,pull:0"; ++ active_low = <&charger>,"gpios:8"; ++ }; ++ ++}; diff --git a/arch/arm/boot/dts/overlays/gpio-fan-overlay.dts b/arch/arm/boot/dts/overlays/gpio-fan-overlay.dts new file mode 100644 -index 000000000000..77a7bbb41e3b +index 000000000000..17b77bb27931 --- /dev/null +++ b/arch/arm/boot/dts/overlays/gpio-fan-overlay.dts -@@ -0,0 +1,79 @@ +@@ -0,0 +1,89 @@ +/* + * Overlay for the Raspberry Pi GPIO Fan @ BCM GPIO12. + * References: @@ -18241,26 +28641,69 @@ + + 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"; -+ }; ++ polling-delay = <2000>; /* milliseconds */ ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&thermal_trips>; ++ __overlay__ { ++ 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>; -+ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&cooling_maps>; ++ __overlay__ { ++ map0 { ++ trip = <&cpu_hot>; ++ cooling-device = <&fan0 1 1>; + }; + }; + }; ++ + __overrides__ { + gpiopin = <&fan0>,"gpios:4", <&fan0>,"brcm,pins:0"; + temp = <&cpu_hot>,"temperature:0"; ++ hyst = <&cpu_hot>,"hysteresis:0"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/gpio-hog-overlay.dts b/arch/arm/boot/dts/overlays/gpio-hog-overlay.dts +new file mode 100644 +index 000000000000..c9e39046fed9 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/gpio-hog-overlay.dts +@@ -0,0 +1,27 @@ ++// Configure a "hog" on the specified GPIO ++/dts-v1/; ++/plugin/; ++ ++#include <dt-bindings/gpio/gpio.h> ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&gpio>; ++ __overlay__ { ++ hog: hog@1a { ++ gpio-hog; ++ gpios = <26 GPIO_ACTIVE_HIGH>; ++ output-high; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ gpio = <&hog>,"reg:0", ++ <&hog>,"gpios:0"; ++ active_low = <&hog>,"output-high!", ++ <&hog>,"output-low?"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts b/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts @@ -18694,6 +29137,110 @@ + }; + +}; +diff --git a/arch/arm/boot/dts/overlays/hat_map.dts b/arch/arm/boot/dts/overlays/hat_map.dts +new file mode 100644 +index 000000000000..cb96b680cb4f +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/hat_map.dts +@@ -0,0 +1,98 @@ ++/dts-v1/; ++ ++/ { ++ hifiberry-amp100-1 { ++ uuid = 5eb863b8 12f9 41ad 978f 4cee1b3eca62 ; ++ overlay = "hifiberry-amp100"; ++ }; ++ ++ hifiberry-amp100-2 { ++ uuid = b1a57dbe 8b52 447f 939e 1baf72157d79 ; ++ overlay = "hifiberry-amp100"; ++ }; ++ ++ hifiberry-amp4pro { ++ uuid = 3619722a c92d 4092 95bd 493a2903e933 ; ++ overlay = "hifiberry-amp4pro"; ++ }; ++ ++ hifiberry-amp4 { ++ uuid = fcb6ec42 a182 419d a314 7eeae416f608 ; ++ overlay = "hifiberry-dacplus-std"; ++ }; ++ ++ hifiberry-dac2proadc { ++ uuid = 30660215 dbb2 4c57 953f 099370b63e2e ; ++ overlay = "hifiberry-dacplusadcpro"; ++ }; ++ ++ hifiberry-dac2hd { ++ uuid = 482ad277 5586 480c 88e7 85ae89c4e501 ; ++ overlay = "hifiberry-dacplushd"; ++ }; ++ ++ hifiberry-dac2pro { ++ uuid = ebf9cfc4 6d77 4880 89fd 353690467dfc ; ++ overlay = "hifiberry-dacplus-pro"; ++ }; ++ ++ hifiberry-dac8x { ++ uuid = f65985f9 5354 4457 ae3b 3da39ba2cf6d ; ++ overlay = "hifiberry-dac8x"; ++ }; ++ ++ hifiberry-dacplus-amp2-1 { ++ uuid = 81cac43d 27c6 4a1e a0b2 c70b4e608ab6 ; ++ overlay = "hifiberry-dacplus-std"; ++ }; ++ ++ hifiberry-dacplus-amp2-2 { ++ uuid = ef586afc 2efa 47a0 be2e 95a7d952fe98 ; ++ overlay = "hifiberry-dacplus-std"; ++ }; ++ ++ hifiberry-digiplus-pro { ++ uuid = 2154f80b 0f92 45e4 96db c1643ec2b46b ; ++ overlay = "hifiberry-digi-pro"; ++ }; ++ ++ hifiberry-dacplusadcpro { ++ uuid = 36e3d3da 1ed9 468b aea3 cd165f6820f0 ; ++ overlay = "hifiberry-dacplusadcpro"; ++ }; ++ ++ hifiberry-digi2pro { ++ uuid = 5af941bb 4dcf 4eac 82a8 e36e84fcabef ; ++ overlay = "hifiberry-digi-pro"; ++ }; ++ ++ hifiberry-digi2standard { ++ uuid = 7c980a0e 9d15 40af 9f40 bddfbd3aee8c ; ++ overlay = "hifiberry-digi"; ++ }; ++ ++ hifiberry-dsp2x4 { ++ uuid = 8f287583 429d 4206 a751 862264bbda63 ; ++ overlay = "hifiberry-dacplus-dsp"; ++ }; ++ ++ iqaudio-pi-codecplus { ++ uuid = dc1c9594 c1ab 4c6c acda a88dc59a3c5b ; ++ overlay = "iqaudio-codec"; ++ }; ++ ++ iqaudio-pi-codeczero { ++ uuid = e15c739c 877d 4e29 ab36 4dc73c21127c ; ++ overlay = "iqaudio-codec"; ++ }; ++ ++ pisound { ++ uuid = a7ee5d28 da03 41f5 bbd7 20438a4bec5d ; ++ overlay = "pisound"; ++ }; ++ ++ recalbox-rgbdual { ++ uuid = 1c955808 681f 4bbc a2ef b7ea47cd388e ; ++ overlay = "recalboxrgbdual"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/hd44780-lcd-overlay.dts b/arch/arm/boot/dts/overlays/hd44780-lcd-overlay.dts new file mode 100644 index 000000000000..ee726669ff51 @@ -18801,7 +29348,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts new file mode 100644 -index 000000000000..142518ab348b +index 000000000000..667cd2601806 --- /dev/null +++ b/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts @@ -0,0 +1,39 @@ @@ -18813,7 +29360,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -18839,17 +29386,17 @@ + target = <&sound>; + __overlay__ { + compatible = "hifiberry,hifiberry-amp"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm/boot/dts/overlays/hifiberry-amp100-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-amp100-overlay.dts new file mode 100644 -index 000000000000..ebdef55d6110 +index 000000000000..b38e6631a572 --- /dev/null +++ b/arch/arm/boot/dts/overlays/hifiberry-amp100-overlay.dts -@@ -0,0 +1,64 @@ +@@ -0,0 +1,67 @@ +// Definitions for HiFiBerry AMP100 +/dts-v1/; +/plugin/; @@ -18867,8 +29414,8 @@ + }; + }; + -+ fragment@1 { -+ target = <&i2s>; ++ frag1: fragment@1 { ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -18898,7 +29445,7 @@ + target = <&sound>; + hifiberry_dacplus: __overlay__ { + compatible = "hifiberry,hifiberry-dacplus"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + mute-gpio = <&gpio 4 0>; + reset-gpio = <&gpio 17 0x11>; @@ -18908,15 +29455,150 @@ + __overrides__ { + 24db_digital_gain = + <&hifiberry_dacplus>,"hifiberry,24db_digital_gain?"; -+ slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?"; ++ slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?", ++ <&frag1>,"target:0=",<&i2s_clk_producer>, ++ <&hifiberry_dacplus>,"i2s-controller:0=",<&i2s_clk_producer>; ++ + leds_off = <&hifiberry_dacplus>,"hifiberry-dacplus,leds_off?"; + mute_ext_ctl = <&hifiberry_dacplus>,"hifiberry-dacplus,mute_ext_ctl:0"; + auto_mute = <&hifiberry_dacplus>,"hifiberry-dacplus,auto_mute?"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/hifiberry-amp3-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-amp3-overlay.dts +new file mode 100644 +index 000000000000..fc8f11b6294e +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/hifiberry-amp3-overlay.dts +@@ -0,0 +1,57 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Definitions for HiFiBerry's Amp3 ++/dts-v1/; ++/plugin/; ++#include <dt-bindings/pinctrl/bcm2835.h> ++#include <dt-bindings/gpio/gpio.h> ++ ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2s_clk_producer>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ hifiberry_amp3_pins: hifiberry_amp3_pins { ++ brcm,pins = <23 17>; ++ brcm,function = <0 1>; ++ brcm,pull = <2 1>; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ hifiberry_amp2: ma120x0p@20 { ++ #sound-dai-cells = <0>; ++ compatible = "ma,ma120x0p"; ++ reg = <0x20>; ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hifiberry_amp3_pins>; ++ error_gp-gpios = <&gpio 23 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&sound>; ++ __overlay__ { ++ compatible = "hifiberry,hifiberry-amp3"; ++ i2s-controller = <&i2s_clk_producer>; ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/hifiberry-amp4pro-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-amp4pro-overlay.dts +new file mode 100644 +index 000000000000..6b211c2932dd +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/hifiberry-amp4pro-overlay.dts +@@ -0,0 +1,63 @@ ++// Definitions for HiFiBerry AMP4PRO ++/dts-v1/; ++/plugin/; ++#include <dt-bindings/gpio/gpio.h> ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ dacpro_osc: dacpro_osc { ++ compatible = "hifiberry,dacpro-clk"; ++ #clock-cells = <0>; ++ }; ++ }; ++ }; ++ ++ frag1: fragment@1 { ++ target = <&i2s_clk_consumer>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ tas5756@4d { ++ #sound-dai-cells = <0>; ++ compatible = "ti,tas5756"; ++ reg = <0x4d>; ++ clocks = <&dacpro_osc>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&sound>; ++ hifiberry_dacplus: __overlay__ { ++ compatible = "hifiberry,hifiberry-dacplus"; ++ i2s-controller = <&i2s_clk_consumer>; ++ status = "okay"; ++ mute-gpio = <&gpio 4 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ __overrides__ { ++ 24db_digital_gain = ++ <&hifiberry_dacplus>,"hifiberry-amp4,24db_digital_gain?"; ++ leds_off = <&hifiberry_dacplus>,"hifiberry-amp4,leds_off?"; ++ mute_ext_ctl = <&hifiberry_dacplus>,"hifiberry-amp4,mute_ext_ctl:0"; ++ auto_mute = <&hifiberry_dacplus>,"hifiberry-amp4,auto_mute?"; ++ slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?", ++ <&frag1>,"target:0=",<&i2s_clk_producer>, ++ <&hifiberry_dacplus>,"i2s-controller:0=",<&i2s_clk_producer>; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts new file mode 100644 -index 000000000000..ea8a6c8f36c0 +index 000000000000..efb0e18dbdc4 --- /dev/null +++ b/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts @@ -0,0 +1,34 @@ @@ -18928,7 +29610,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -18949,17 +29631,73 @@ + target = <&sound>; + __overlay__ { + compatible = "hifiberry,hifiberry-dac"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/hifiberry-dac8x-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-dac8x-overlay.dts +new file mode 100644 +index 000000000000..efeff792f396 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/hifiberry-dac8x-overlay.dts +@@ -0,0 +1,50 @@ ++// Definitions for HiFiBerry DAC8x ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&gpio>; ++ __overlay__ { ++ rp1_i2s0_dac8x: rp1_i2s0_dac8x { ++ function = "i2s0"; ++ pins = "gpio18", "gpio19", "gpio21", ++ "gpio23", "gpio25", "gpio27"; ++ bias-disable; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&i2s_clk_producer>; ++ __overlay__ { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rp1_i2s0_dac8x>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@2 { ++ target-path = "/"; ++ __overlay__ { ++ pcm5102a-codec { ++ #sound-dai-cells = <0>; ++ compatible = "ti,pcm5102a"; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&sound>; ++ __overlay__ { ++ compatible = "hifiberry,hifiberry-dac8x"; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; ++ +}; diff --git a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts new file mode 100644 -index 000000000000..ff19015ba656 +index 000000000000..0d0ab068112f --- /dev/null +++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts -@@ -0,0 +1,65 @@ +@@ -0,0 +1,68 @@ +// Definitions for HiFiBerry DAC+ +/dts-v1/; +/plugin/; @@ -18977,8 +29715,152 @@ + }; + }; + ++ frag1: fragment@1 { ++ target = <&i2s_clk_consumer>; ++ __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_clk_consumer>; ++ status = "okay"; ++ }; ++ }; ++ ++ __overrides__ { ++ 24db_digital_gain = ++ <&hifiberry_dacplus>,"hifiberry,24db_digital_gain?"; ++ slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?", ++ <&frag1>,"target:0=",<&i2s_clk_producer>, ++ <&hifiberry_dacplus>,"i2s-controller:0=",<&i2s_clk_producer>; ++ ++ leds_off = <&hifiberry_dacplus>,"hifiberry-dacplus,leds_off?"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/hifiberry-dacplus-pro-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-dacplus-pro-overlay.dts +new file mode 100644 +index 000000000000..28b1c2f2f1a8 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-pro-overlay.dts +@@ -0,0 +1,64 @@ ++// Definitions for HiFiBerry DAC+ PRO, with onboard clocks ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ dacpro_osc: dacpro_osc { ++ compatible = "hifiberry,dacpro-clk"; ++ #clock-cells = <0>; ++ }; ++ }; ++ }; ++ ++ frag1: fragment@1 { ++ target = <&i2s_clk_consumer>; ++ __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_clk_consumer>; ++ status = "okay"; ++ }; ++ }; ++ ++ __overrides__ { ++ 24db_digital_gain = ++ <&hifiberry_dacplus>,"hifiberry,24db_digital_gain?"; ++ leds_off = <&hifiberry_dacplus>,"hifiberry-dacplus,leds_off?"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/hifiberry-dacplus-std-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-dacplus-std-overlay.dts +new file mode 100644 +index 000000000000..8872e3aa348d +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-std-overlay.dts +@@ -0,0 +1,65 @@ ++// Definitions for HiFiBerry DAC+ Standard w/o onboard clocks ++/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>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -19013,7 +29895,8 @@ + target = <&sound>; + hifiberry_dacplus: __overlay__ { + compatible = "hifiberry,hifiberry-dacplus"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; ++ hifiberry-dacplus,slave; + status = "okay"; + }; + }; @@ -19021,17 +29904,16 @@ + __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 --git a/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts new file mode 100644 -index 000000000000..540563dec10f +index 000000000000..ea4c3572826f --- /dev/null +++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts @@ -0,0 +1,72 @@ -+// Definitions for HiFiBerry DAC+ADC ++// Definitions for HiFiBerry DAC+ADC, no onboard clocks +/dts-v1/; +/plugin/; + @@ -19049,7 +29931,7 @@ + }; + + fragment@1 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -19091,7 +29973,8 @@ + target = <&sound>; + hifiberry_dacplusadc: __overlay__ { + compatible = "hifiberry,hifiberry-dacplusadc"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; ++ hifiberry-dacplusadc,slave; + status = "okay"; + }; + }; @@ -19099,16 +29982,15 @@ + __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 --git a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts new file mode 100644 -index 000000000000..561cd84bbb79 +index 000000000000..a4268bd72477 --- /dev/null +++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts -@@ -0,0 +1,70 @@ +@@ -0,0 +1,72 @@ +// Definitions for HiFiBerry DAC+ADC PRO +/dts-v1/; +/plugin/; @@ -19126,8 +30008,8 @@ + }; + }; + -+ fragment@1 { -+ target = <&i2s>; ++ frag1: fragment@1 { ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -19167,7 +30049,7 @@ + hifiberry_dacplusadcpro: __overlay__ { + compatible = "hifiberry,hifiberry-dacplusadcpro"; + audio-codec = <&hb_dac &hb_adc>; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; @@ -19175,13 +30057,15 @@ + __overrides__ { + 24db_digital_gain = + <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,24db_digital_gain?"; -+ slave = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,slave?"; ++ slave = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,slave?", ++ <&frag1>,"target:0=",<&i2s_clk_producer>, ++ <&hifiberry_dacplusadcpro>,"i2s-controller:0=",<&i2s_clk_producer>; + leds_off = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,leds_off?"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/hifiberry-dacplusdsp-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-dacplusdsp-overlay.dts new file mode 100644 -index 000000000000..63432e8b983f +index 000000000000..e916485f737e --- /dev/null +++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusdsp-overlay.dts @@ -0,0 +1,34 @@ @@ -19193,7 +30077,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -19214,17 +30098,17 @@ + target = <&sound>; + __overlay__ { + compatible = "hifiberrydacplusdsp,hifiberrydacplusdsp-soundcard"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts new file mode 100644 -index 000000000000..c5583e010339 +index 000000000000..1856ac19793b --- /dev/null +++ b/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts -@@ -0,0 +1,106 @@ +@@ -0,0 +1,94 @@ +// Definitions for HiFiBerry DAC+ HD +/dts-v1/; +/plugin/; @@ -19235,23 +30119,13 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target-path = "/"; -+ __overlay__ { -+ dachd_osc: pll_dachd_osc { -+ compatible = "hifiberry,dachd-clk"; -+ #clock-cells = <0>; -+ }; -+ }; -+ }; -+ -+ fragment@1 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; + }; + -+ fragment@2 { ++ fragment@1 { + target = <&i2c1>; + __overlay__ { + #address-cells = <1>; @@ -19262,7 +30136,6 @@ + compatible = "ti,pcm1792a"; + #sound-dai-cells = <0>; + #clock-cells = <0>; -+ clocks = <&dachd_osc>; + reg = <0x4c>; + status = "okay"; + }; @@ -19270,7 +30143,6 @@ + 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 @@ -19319,11 +30191,11 @@ + }; + }; + -+ fragment@3 { ++ fragment@2 { + target = <&sound>; + __overlay__ { + compatible = "hifiberry,hifiberry-dacplushd"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + clocks = <&pll 0>; + reset-gpio = <&gpio 16 GPIO_ACTIVE_LOW>; + status = "okay"; @@ -19333,7 +30205,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts new file mode 100644 -index 000000000000..a2309a50e8d8 +index 000000000000..eb68f117a92a --- /dev/null +++ b/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts @@ -0,0 +1,41 @@ @@ -19345,7 +30217,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -19373,14 +30245,14 @@ + target = <&sound>; + __overlay__ { + compatible = "hifiberry,hifiberry-digi"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts new file mode 100644 -index 000000000000..83de602e76ba +index 000000000000..18d16276e120 --- /dev/null +++ b/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts @@ -0,0 +1,43 @@ @@ -19392,7 +30264,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -19420,7 +30292,7 @@ + target = <&sound>; + __overlay__ { + compatible = "hifiberry,hifiberry-digi"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + clock44-gpio = <&gpio 5 0>; + clock48-gpio = <&gpio 6 0>; @@ -19498,7 +30370,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/hy28a-overlay.dts b/arch/arm/boot/dts/overlays/hy28a-overlay.dts new file mode 100644 -index 000000000000..5843a5e9c86a +index 000000000000..d0d52ebd9bd5 --- /dev/null +++ b/arch/arm/boot/dts/overlays/hy28a-overlay.dts @@ -0,0 +1,93 @@ @@ -19577,7 +30449,7 @@ + spi-max-frequency = <2000000>; + interrupts = <17 2>; /* high-to-low edge triggered */ + interrupt-parent = <&gpio>; -+ pendown-gpio = <&gpio 17 0>; ++ pendown-gpio = <&gpio 17 1>; + ti,x-plate-ohms = /bits/ 16 <100>; + ti,pressure-max = /bits/ 16 <255>; + }; @@ -19597,7 +30469,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/hy28b-2017-overlay.dts b/arch/arm/boot/dts/overlays/hy28b-2017-overlay.dts new file mode 100644 -index 000000000000..95bfb1eadc20 +index 000000000000..9df33c5d95bb --- /dev/null +++ b/arch/arm/boot/dts/overlays/hy28b-2017-overlay.dts @@ -0,0 +1,152 @@ @@ -19735,7 +30607,7 @@ + spi-max-frequency = <2000000>; + interrupts = <17 2>; /* high-to-low edge triggered */ + interrupt-parent = <&gpio>; -+ pendown-gpio = <&gpio 17 0>; ++ pendown-gpio = <&gpio 17 1>; + ti,x-plate-ohms = /bits/ 16 <100>; + ti,pressure-max = /bits/ 16 <255>; + }; @@ -19755,7 +30627,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/hy28b-overlay.dts b/arch/arm/boot/dts/overlays/hy28b-overlay.dts new file mode 100644 -index 000000000000..9edd0848d555 +index 000000000000..421bde94a4a0 --- /dev/null +++ b/arch/arm/boot/dts/overlays/hy28b-overlay.dts @@ -0,0 +1,148 @@ @@ -19889,7 +30761,7 @@ + spi-max-frequency = <2000000>; + interrupts = <17 2>; /* high-to-low edge triggered */ + interrupt-parent = <&gpio>; -+ pendown-gpio = <&gpio 17 0>; ++ pendown-gpio = <&gpio 17 1>; + ti,x-plate-ohms = /bits/ 16 <100>; + ti,pressure-max = /bits/ 16 <255>; + }; @@ -19909,7 +30781,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts b/arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts new file mode 100644 -index 000000000000..0c4cff354674 +index 000000000000..6db52955a8f8 --- /dev/null +++ b/arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts @@ -0,0 +1,39 @@ @@ -19924,13 +30796,13 @@ + target = <&sound>; + frag0: __overlay__ { + compatible = "audiophonics,i-sabre-q2m"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; + + fragment@1 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -19971,6 +30843,120 @@ + }; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/i2c-fan-overlay.dts b/arch/arm/boot/dts/overlays/i2c-fan-overlay.dts +new file mode 100644 +index 000000000000..f2f4a2aa797a +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/i2c-fan-overlay.dts +@@ -0,0 +1,108 @@ ++// Definitions for I2C based sensors using the Industrial IO or HWMON interface. ++/dts-v1/; ++/plugin/; ++ ++#include <dt-bindings/thermal/thermal.h> ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ emc2301: emc2301@2f { ++ compatible = "microchip,emc2301"; ++ reg = <0x2f>; ++ status = "okay"; ++ #cooling-cells = <0x02>; ++ }; ++ }; ++ }; ++ ++ frag100: fragment@100 { ++ target = <&i2c_arm>; ++ i2cbus: __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@101 { ++ target = <&i2c0if>; ++ __dormant__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@102 { ++ target = <&i2c0mux>; ++ __dormant__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@103 { ++ target = <&cpu_thermal>; ++ __overlay__ { ++ polling-delay = <2000>; /* milliseconds */ ++ }; ++ }; ++ ++ fragment@104 { ++ target = <&thermal_trips>; ++ __overlay__ { ++ fanmid0: fanmid0 { ++ temperature = <50000>; ++ hysteresis = <2000>; ++ type = "active"; ++ }; ++ fanmax0: fanmax0 { ++ temperature = <75000>; ++ hysteresis = <2000>; ++ type = "active"; ++ }; ++ }; ++ }; ++ ++ fragment@105 { ++ target = <&cooling_maps>; ++ __overlay__ { ++ map0: map0 { ++ trip = <&fanmid0>; ++ cooling-device = <&emc2301 2 6>; ++ }; ++ map1: map1 { ++ trip = <&fanmax0>; ++ cooling-device = <&emc2301 7 THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ i2c0 = <&frag100>,"target:0=",<&i2c0>; ++ i2c_csi_dsi = <&frag100>,"target:0=",<&i2c_csi_dsi>, ++ <0>,"+101+102"; ++ i2c3 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c3"; ++ i2c4 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c4"; ++ i2c5 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c5"; ++ i2c6 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c6"; ++ addr = <&emc2301>,"reg:0"; ++ minpwm = <&emc2301>,"emc2305,pwm-min.0"; ++ maxpwm = <&emc2301>,"emc2305,pwm-max.0"; ++ midtemp = <&fanmid0>,"temperature:0"; ++ midtemp_hyst = <&fanmid0>,"hysteresis:0"; ++ maxtemp = <&fanmax0>,"temperature:0"; ++ maxtemp_hyst = <&fanmax0>,"hysteresis:0"; ++ ++ emc2301 = <0>,"+0", ++ <&map0>,"cooling-device:0=",<&emc2301>, ++ <&map1>,"cooling-device:0=",<&emc2301>; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts b/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts new file mode 100644 index 000000000000..63231b5d7c0c @@ -20026,20 +31012,22 @@ +}; diff --git a/arch/arm/boot/dts/overlays/i2c-mux-overlay.dts b/arch/arm/boot/dts/overlays/i2c-mux-overlay.dts new file mode 100644 -index 000000000000..112aed91ecb2 +index 000000000000..0575b276cd26 --- /dev/null +++ b/arch/arm/boot/dts/overlays/i2c-mux-overlay.dts -@@ -0,0 +1,139 @@ +@@ -0,0 +1,183 @@ +// Umbrella I2C Mux overlay + +/dts-v1/; +/plugin/; + ++#include <dt-bindings/mux/mux.h> ++ +/{ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; @@ -20066,7 +31054,7 @@ + }; + + fragment@1 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; @@ -20103,7 +31091,7 @@ + }; + + fragment@2 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; @@ -20159,6 +31147,27 @@ + }; + }; + ++ 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__ { + pca9542 = <0>, "+0"; + pca9545 = <0>, "+1"; @@ -20167,14 +31176,35 @@ + addr = <&pca9542>,"reg:0", + <&pca9545>,"reg:0", + <&pca9548>,"reg:0"; ++ ++ base = <&pca9542>,"base-nr:0", ++ <&pca9545>,"base-nr:0", ++ <&pca9548>,"base-nr:0"; ++ ++ i2c0 = <&frag100>, "target:0=",<&i2c0>, ++ <0>,"+101+102"; ++ i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, ++ <0>,"+101+102"; ++ i2c3 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c3"; ++ i2c4 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c4"; ++ i2c5 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c5"; ++ i2c6 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c6"; ++ disconnect_on_idle = ++ <&pca9542>,"idle-state:0=", <MUX_IDLE_DISCONNECT>, ++ <&pca9545>,"idle-state:0=", <MUX_IDLE_DISCONNECT>, ++ <&pca9548>,"idle-state:0=", <MUX_IDLE_DISCONNECT>; + }; +}; diff --git a/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts b/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts new file mode 100644 -index 000000000000..9bb16465a50e +index 000000000000..b8dfbd56d121 --- /dev/null +++ b/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts -@@ -0,0 +1,26 @@ +@@ -0,0 +1,61 @@ +// Definitions for NXP PCA9685A I2C PWM controller on ARM I2C bus. +/dts-v1/; +/plugin/; @@ -20183,7 +31213,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; @@ -20197,16 +31227,51 @@ + }; + }; + }; ++ ++ ++ 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__ { + addr = <&pca>,"reg:0"; ++ i2c0 = <&frag100>, "target:0=",<&i2c0>, ++ <0>,"+101+102"; ++ i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, ++ <0>,"+101+102"; ++ i2c3 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c3"; ++ i2c4 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c4"; ++ i2c5 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c5"; ++ i2c6 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c6"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi b/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi new file mode 100644 -index 000000000000..7f749fc2d802 +index 000000000000..d2b54fe23339 --- /dev/null +++ b/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi -@@ -0,0 +1,323 @@ +@@ -0,0 +1,367 @@ +// Definitions for several I2C based Real Time Clocks + +/ { @@ -20459,7 +31524,7 @@ + #size-cells = <0>; + + s35390a: s35390a@30 { -+ compatible = "ablic,s35390a"; ++ compatible = "sii,s35390a"; + reg = <0x30>; + }; + }; @@ -20479,6 +31544,44 @@ + }; + }; + ++ fragment@20 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ rv8803: rv8803@32 { ++ compatible = "microcrystal,rv8803"; ++ reg = <0x32>; ++ }; ++ }; ++ }; ++ ++ fragment@21 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ rv3032: rv3032@51 { ++ compatible = "microcrystal,rv3032"; ++ reg = <0x51>; ++ }; ++ }; ++ }; ++ ++ fragment@22 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pcf2131@53 { ++ compatible = "nxp,pcf2131"; ++ reg = <0x53>; ++ }; ++ }; ++ }; + + __overrides__ { + abx80x = <0>,"+0"; @@ -20501,6 +31604,9 @@ + pcf85063a = <0>,"+16"; + s35390a = <0>,"+18"; + bq32000 = <0>,"+19"; ++ rv8803 = <0>,"+20"; ++ rv3032 = <0>,"+21"; ++ pcf2131 = <0>,"+22"; + + addr = <&abx80x>, "reg:0", + <&ds1307>, "reg:0", @@ -20520,14 +31626,17 @@ + <&ds1340>,"trickle-resistor-ohms:0", + <&abx80x>,"abracon,tc-resistor:0", + <&rv3028>,"trickle-resistor-ohms:0", ++ <&rv3032>,"trickle-resistor-ohms:0", + <&rv1805>,"abracon,tc-resistor:0", + <&bq32000>,"abracon,tc-resistor:0"; ++ trickle-voltage-mv = <&rv3032>,"trickle-voltage-millivolts:0"; + backup-switchover-mode = <&rv3028>,"backup-switchover-mode:0"; + wakeup-source = <&ds1339>,"wakeup-source?", + <&ds3231>,"wakeup-source?", + <&mcp7940x>,"wakeup-source?", + <&mcp7941x>,"wakeup-source?", -+ <&m41t62>,"wakeup-source?"; ++ <&m41t62>,"wakeup-source?", ++ <&pcf8563>,"wakeup-source?"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts b/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts @@ -20569,10 +31678,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts new file mode 100644 -index 000000000000..1eae9e1a5c96 +index 000000000000..cd31eac7e333 --- /dev/null +++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts -@@ -0,0 +1,34 @@ +@@ -0,0 +1,42 @@ +// Definitions for several I2C based Real Time Clocks +/dts-v1/; +/plugin/; @@ -20605,23 +31714,33 @@ + i2c0 = <&frag100>, "target:0=",<&i2c0>; + i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, + <0>,"+101+102"; ++ i2c3 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c3"; ++ i2c4 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c4"; ++ i2c5 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c5"; ++ i2c6 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c6"; + }; +}; -diff --git a/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts b/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts +diff --git a/arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi b/arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi new file mode 100755 -index 000000000000..33965be4b1e8 +index 000000000000..2f7d1fe402eb --- /dev/null -+++ b/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts -@@ -0,0 +1,340 @@ ++++ b/arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi +@@ -0,0 +1,578 @@ +// Definitions for I2C based sensors using the Industrial IO or HWMON interface. +/dts-v1/; +/plugin/; + ++#include <dt-bindings/gpio/gpio.h> ++ +/ { + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; @@ -20636,7 +31755,7 @@ + }; + + fragment@1 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; @@ -20652,7 +31771,7 @@ + }; + + fragment@2 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; @@ -20667,7 +31786,7 @@ + }; + + fragment@3 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; @@ -20682,14 +31801,14 @@ + }; + + fragment@4 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + htu21: htu21@40 { -+ compatible = "htu21"; ++ compatible = "meas,htu21"; + reg = <0x40>; + status = "okay"; + }; @@ -20697,14 +31816,14 @@ + }; + + fragment@5 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + lm75: lm75@4f { -+ compatible = "lm75"; ++ compatible = "national,lm75"; + reg = <0x4f>; + status = "okay"; + }; @@ -20712,14 +31831,14 @@ + }; + + fragment@6 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + si7020: si7020@40 { -+ compatible = "si7020"; ++ compatible = "silabs,si7020"; + reg = <0x40>; + status = "okay"; + }; @@ -20727,7 +31846,7 @@ + }; + + fragment@7 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; @@ -20742,14 +31861,14 @@ + }; + + fragment@8 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + hdc100x: hdc100x@40 { -+ compatible = "hdc100x"; ++ compatible = "ti,hdc1000"; + reg = <0x40>; + status = "okay"; + }; @@ -20757,14 +31876,14 @@ + }; + + fragment@9 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + tsl4531: tsl4531@29 { -+ compatible = "tsl4531"; ++ compatible = "amstaos,tsl4531"; + reg = <0x29>; + status = "okay"; + }; @@ -20772,14 +31891,14 @@ + }; + + fragment@10 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + veml6070: veml6070@38 { -+ compatible = "veml6070"; ++ compatible = "vishay,veml6070"; + reg = <0x38>; + status = "okay"; + }; @@ -20787,14 +31906,14 @@ + }; + + fragment@11 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + sht3x: sht3x@44 { -+ compatible = "sht3x"; ++ compatible = "sensirion,sht3x"; + reg = <0x44>; + status = "okay"; + }; @@ -20802,14 +31921,14 @@ + }; + + fragment@12 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ds1621: ds1621@48 { -+ compatible = "ds1621"; ++ compatible = "dallas,ds1621"; + reg = <0x48>; + status = "okay"; + }; @@ -20817,7 +31936,7 @@ + }; + + fragment@13 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; @@ -20832,7 +31951,7 @@ + }; + + fragment@14 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; @@ -20847,7 +31966,7 @@ + }; + + fragment@15 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; @@ -20862,7 +31981,7 @@ + }; + + fragment@16 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; @@ -20877,14 +31996,14 @@ + }; + + fragment@17 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ccs811: ccs811@5b { -+ compatible = "ccs811"; ++ compatible = "ams,ccs811"; + reg = <0x5b>; + status = "okay"; + }; @@ -20892,14 +32011,14 @@ + }; + + fragment@18 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + bh1750: bh1750@23 { -+ compatible = "bh1750"; ++ compatible = "rohm,bh1750"; + reg = <0x23>; + status = "okay"; + }; @@ -20907,7 +32026,7 @@ + }; + + fragment@19 { -+ target = <&i2c_arm>; ++ target = <&i2cbus>; + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; @@ -20924,16 +32043,224 @@ + }; + }; + -+ __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"; -+ int_pin = <&max30102>, "interrupts:0"; ++ fragment@20 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ aht10: aht10@38 { ++ compatible = "aosong,aht10"; ++ reg = <0x38>; ++ }; ++ }; ++ }; ++ ++ fragment@21 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ mcp980x: mcp980x@18 { ++ compatible = "maxim,mcp980x"; ++ reg = <0x18>; ++ }; ++ }; ++ }; ++ ++ fragment@22 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ jc42: jc42@18 { ++ compatible = "jedec,jc-42.4-temp"; ++ reg = <0x18>; ++ }; ++ }; ++ }; ++ ++ fragment@23 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ ms5637: ms5637@76 { ++ compatible = "meas,ms5637"; ++ reg = <0x76>; ++ }; ++ }; ++ }; ++ ++ fragment@24 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ ms5803: ms5803@76 { ++ compatible = "meas,ms5803"; ++ reg = <0x76>; ++ }; ++ }; ++ }; ++ ++ fragment@25 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ ms5805: ms5805@76 { ++ compatible = "meas,ms5805"; ++ reg = <0x76>; ++ }; ++ }; ++ }; ++ ++ fragment@26 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ ms5837: ms5837@76 { ++ compatible = "meas,ms5837"; ++ reg = <0x76>; ++ }; ++ }; ++ }; ++ ++ fragment@27 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ ms8607: ms8607@76 { ++ compatible = "meas,ms8607-temppressure"; ++ reg = <0x76>; ++ }; ++ }; ++ }; ++ ++ fragment@28 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ clock-frequency = <400000>; ++ ++ mpu6050: mpu6050@68 { ++ compatible = "invensense,mpu6050"; ++ reg = <0x68>; ++ interrupt-parent = <&gpio>; ++ interrupts = <4 2>; ++ }; ++ }; ++ }; ++ ++ fragment@29 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ clock-frequency = <400000>; ++ ++ mpu9250: mpu9250@68 { ++ compatible = "invensense,mpu9250"; ++ reg = <0x68>; ++ interrupt-parent = <&gpio>; ++ interrupts = <4 2>; ++ }; ++ }; ++ }; ++ ++ fragment@30 { ++ target = <&bno055>; ++ __dormant__ { ++ reset-gpios = <&gpio 5 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ fragment@31 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ bno055: bno055@29 { ++ compatible = "bosch,bno055"; ++ reg = <0x29>; ++ }; ++ }; ++ }; ++ ++ fragment@32 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ sht4x: sht4x@44 { ++ compatible = "sensirion,sht4x"; ++ reg = <0x44>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@33 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ bmp380: bmp380@76 { ++ compatible = "bosch,bmp380"; ++ reg = <0x76>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@34 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ adt7410: adt7410@48 { ++ compatible = "adi,adt7410", "adi,adt7420"; ++ reg = <0x48>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { + bme280 = <0>,"+0"; + bmp085 = <0>,"+1"; + bmp180 = <0>,"+2"; + bmp280 = <0>,"+3"; ++ bmp380 = <0>,"+33"; + htu21 = <0>,"+4"; + lm75 = <0>,"+5"; + lm75addr = <&lm75>,"reg:0"; @@ -20951,6 +32278,82 @@ + ccs811 = <0>, "+17"; + bh1750 = <0>, "+18"; + max30102 = <0>,"+19"; ++ aht10 = <0>,"+20"; ++ mcp980x = <0>,"+21"; ++ jc42 = <0>,"+22"; ++ ms5637 = <0>,"+23"; ++ ms5803 = <0>,"+24"; ++ ms5805 = <0>,"+25"; ++ ms5837 = <0>,"+26"; ++ ms8607 = <0>,"+27"; ++ mpu6050 = <0>,"+28"; ++ mpu9250 = <0>,"+29"; ++ bno055 = <0>,"+31"; ++ sht4x = <0>,"+32"; ++ adt7410 = <0>,"+34"; ++ ++ addr = <&bme280>,"reg:0", <&bmp280>,"reg:0", <&tmp102>,"reg:0", ++ <&lm75>,"reg:0", <&hdc100x>,"reg:0", <&sht3x>,"reg:0", ++ <&ds1621>,"reg:0", <&bme680>,"reg:0", <&ccs811>,"reg:0", ++ <&bh1750>,"reg:0", <&mcp980x>,"reg:0", <&jc42>,"reg:0", ++ <&ms5637>,"reg:0", <&ms5803>,"reg:0", <&ms5805>,"reg:0", ++ <&ms5837>,"reg:0", <&ms8607>,"reg:0", ++ <&mpu6050>,"reg:0", <&mpu9250>,"reg:0", ++ <&bno055>,"reg:0", <&sht4x>,"reg:0", ++ <&bmp380>,"reg:0", <&adt7410>,"reg:0"; ++ int_pin = <&max30102>, "interrupts:0", ++ <&mpu6050>, "interrupts:0", ++ <&mpu9250>, "interrupts:0"; ++ no_timeout = <&jc42>, "smbus-timeout-disable?"; ++ reset_pin = <&bno055>,"reset-gpios:4", <0>,"+30"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts b/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts +new file mode 100755 +index 000000000000..f8a39659d83e +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts +@@ -0,0 +1,42 @@ ++// Definitions for I2C based sensors using the Industrial IO or HWMON interface. ++/dts-v1/; ++/plugin/; ++ ++#include "i2c-sensor-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"; ++ i2c3 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c3"; ++ i2c4 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c4"; ++ i2c5 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c5"; ++ i2c6 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c6"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/i2c0-overlay.dts b/arch/arm/boot/dts/overlays/i2c0-overlay.dts @@ -21042,6 +32445,46 @@ + combine = <0>, "!5"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/i2c0-pi5-overlay.dts b/arch/arm/boot/dts/overlays/i2c0-pi5-overlay.dts +new file mode 100644 +index 000000000000..152794822552 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/i2c0-pi5-overlay.dts +@@ -0,0 +1,34 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&i2c0>; ++ frag0: __overlay__ { ++ status = "okay"; ++ clock-frequency = <100000>; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&frag0>; ++ __overlay__ { ++ pinctrl-0 = <&rp1_i2c0_0_1>; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&frag0>; ++ __dormant__ { ++ pinctrl-0 = <&rp1_i2c0_8_9>; ++ }; ++ }; ++ ++ __overrides__ { ++ pins_0_1 = <0>,"+1-2"; ++ pins_8_9 = <0>,"-1+2"; ++ baudrate = <&frag0>, "clock-frequency:0"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/i2c1-overlay.dts b/arch/arm/boot/dts/overlays/i2c1-overlay.dts new file mode 100644 index 000000000000..addaed73e665 @@ -21092,12 +32535,79 @@ + combine = <0>, "!3"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/i2c1-pi5-overlay.dts b/arch/arm/boot/dts/overlays/i2c1-pi5-overlay.dts +new file mode 100644 +index 000000000000..719966ceb59a +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/i2c1-pi5-overlay.dts +@@ -0,0 +1,34 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&i2c1>; ++ frag0: __overlay__ { ++ status = "okay"; ++ clock-frequency = <100000>; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&frag0>; ++ __overlay__ { ++ pinctrl-0 = <&rp1_i2c1_2_3>; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&frag0>; ++ __dormant__ { ++ pinctrl-0 = <&rp1_i2c1_10_11>; ++ }; ++ }; ++ ++ __overrides__ { ++ pins_2_3 = <0>,"+1-2"; ++ pins_10_11 = <0>,"-1+2"; ++ baudrate = <&frag0>, "clock-frequency:0"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/i2c2-pi5-overlay.dts b/arch/arm/boot/dts/overlays/i2c2-pi5-overlay.dts +new file mode 100644 +index 000000000000..324d344052b8 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/i2c2-pi5-overlay.dts +@@ -0,0 +1,21 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&i2c2>; ++ frag0: __overlay__ { ++ status = "okay"; ++ clock-frequency = <100000>; ++ pinctrl-0 = <&rp1_i2c2_4_5>; ++ }; ++ }; ++ ++ __overrides__ { ++ pins_4_5 = <&frag0>,"pinctrl-0:0=", <&rp1_i2c2_4_5>; ++ pins_12_13 = <&frag0>,"pinctrl-0:0=", <&rp1_i2c2_12_13>; ++ baudrate = <&frag0>, "clock-frequency:0"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/i2c3-overlay.dts b/arch/arm/boot/dts/overlays/i2c3-overlay.dts new file mode 100644 -index 000000000000..e24a1df21f99 +index 000000000000..663d4f060ee8 --- /dev/null +++ b/arch/arm/boot/dts/overlays/i2c3-overlay.dts -@@ -0,0 +1,36 @@ +@@ -0,0 +1,34 @@ +/dts-v1/; +/plugin/; + @@ -21108,8 +32618,6 @@ + target = <&i2c3>; + frag0: __overlay__ { + status = "okay"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c3_pins>; + clock-frequency = <100000>; + }; + }; @@ -21134,12 +32642,40 @@ + baudrate = <&frag0>, "clock-frequency:0"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/i2c3-pi5-overlay.dts b/arch/arm/boot/dts/overlays/i2c3-pi5-overlay.dts +new file mode 100644 +index 000000000000..cbd1f9ff650d +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/i2c3-pi5-overlay.dts +@@ -0,0 +1,22 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&i2c3>; ++ frag0: __overlay__ { ++ status = "okay"; ++ clock-frequency = <100000>; ++ pinctrl-0 = <&rp1_i2c3_6_7>; ++ }; ++ }; ++ ++ __overrides__ { ++ pins_6_7 = <&frag0>,"pinctrl-0:0=", <&rp1_i2c3_6_7>; ++ pins_14_15 = <&frag0>,"pinctrl-0:0=", <&rp1_i2c3_14_15>; ++ pins_22_23 = <&frag0>,"pinctrl-0:0=", <&rp1_i2c3_22_23>; ++ baudrate = <&frag0>, "clock-frequency:0"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/i2c4-overlay.dts b/arch/arm/boot/dts/overlays/i2c4-overlay.dts new file mode 100644 -index 000000000000..14c7f4d1da4c +index 000000000000..495de00f7aa1 --- /dev/null +++ b/arch/arm/boot/dts/overlays/i2c4-overlay.dts -@@ -0,0 +1,36 @@ +@@ -0,0 +1,34 @@ +/dts-v1/; +/plugin/; + @@ -21150,8 +32686,6 @@ + target = <&i2c4>; + frag0: __overlay__ { + status = "okay"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c4_pins>; + clock-frequency = <100000>; + }; + }; @@ -21178,10 +32712,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/i2c5-overlay.dts b/arch/arm/boot/dts/overlays/i2c5-overlay.dts new file mode 100644 -index 000000000000..7953621112de +index 000000000000..d498ebc72de6 --- /dev/null +++ b/arch/arm/boot/dts/overlays/i2c5-overlay.dts -@@ -0,0 +1,36 @@ +@@ -0,0 +1,34 @@ +/dts-v1/; +/plugin/; + @@ -21192,8 +32726,6 @@ + target = <&i2c5>; + frag0: __overlay__ { + status = "okay"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c5_pins>; + clock-frequency = <100000>; + }; + }; @@ -21220,10 +32752,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/i2c6-overlay.dts b/arch/arm/boot/dts/overlays/i2c6-overlay.dts new file mode 100644 -index 000000000000..555305a7ee1f +index 000000000000..4d26178a73ca --- /dev/null +++ b/arch/arm/boot/dts/overlays/i2c6-overlay.dts -@@ -0,0 +1,36 @@ +@@ -0,0 +1,34 @@ +/dts-v1/; +/plugin/; + @@ -21234,8 +32766,6 @@ + target = <&i2c6>; + frag0: __overlay__ { + status = "okay"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c6_pins>; + clock-frequency = <100000>; + }; + }; @@ -21260,6 +32790,46 @@ + baudrate = <&frag0>, "clock-frequency:0"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/i2s-dac-overlay.dts b/arch/arm/boot/dts/overlays/i2s-dac-overlay.dts +new file mode 100644 +index 000000000000..1d8874a18860 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/i2s-dac-overlay.dts +@@ -0,0 +1,34 @@ ++// Definitions for RPi DAC ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2s_clk_producer>; ++ __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_clk_producer>; ++ status = "okay"; ++ }; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/i2s-gpio28-31-overlay.dts b/arch/arm/boot/dts/overlays/i2s-gpio28-31-overlay.dts new file mode 100644 index 000000000000..cf43094c6ff4 @@ -21337,10 +32907,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/imx219-overlay.dts b/arch/arm/boot/dts/overlays/imx219-overlay.dts new file mode 100644 -index 000000000000..bc1217397dd5 +index 000000000000..4c4bcd309a3d --- /dev/null +++ b/arch/arm/boot/dts/overlays/imx219-overlay.dts -@@ -0,0 +1,96 @@ +@@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Definitions for IMX219 camera module on VC I2C bus +/dts-v1/; @@ -21380,35 +32950,159 @@ + #size-cells = <0>; + status = "okay"; + -+ imx219: imx219@10 { -+ compatible = "sony,imx219"; -+ reg = <0x10>; -+ status = "okay"; -+ -+ clocks = <&cam1_clk>; -+ clock-names = "xclk"; ++ #include "imx219.dtsi" + -+ VANA-supply = <&cam1_reg>; /* 2.8v */ -+ VDIG-supply = <&cam_dummy_reg>; /* 1.8v */ -+ VDDL-supply = <&cam_dummy_reg>; /* 1.2v */ ++ vcm: ad5398@c { ++ compatible = "adi,ad5398"; ++ reg = <0x0c>; ++ status = "disabled"; ++ VANA-supply = <&cam1_reg>; ++ }; ++ }; ++ }; + -+ rotation = <180>; -+ orientation = <2>; ++ csi_frag: fragment@101 { ++ target = <&csi1>; ++ csi: __overlay__ { ++ status = "okay"; ++ brcm,media-controller; + -+ port { -+ imx219_0: endpoint { -+ remote-endpoint = <&csi_ep>; -+ clock-lanes = <0>; -+ data-lanes = <1 2>; -+ clock-noncontinuous; -+ link-frequencies = -+ /bits/ 64 <456000000>; -+ }; ++ port { ++ csi_ep: endpoint { ++ remote-endpoint = <&cam_endpoint>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; + }; + }; + }; + }; + ++ __overrides__ { ++ rotation = <&cam_node>,"rotation:0"; ++ orientation = <&cam_node>,"orientation:0"; ++ media-controller = <&csi>,"brcm,media-controller?"; ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&csi_frag>, "target:0=",<&csi0>, ++ <&clk_frag>, "target:0=",<&cam0_clk>, ++ <&cam_node>, "clocks:0=",<&cam0_clk>, ++ <&cam_node>, "VANA-supply:0=",<&cam0_reg>, ++ <&vcm>, "VANA-supply:0=", <&cam0_reg>; ++ vcm = <&vcm>, "status=okay", ++ <&cam_node>,"lens-focus:0=", <&vcm>; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; +diff --git a/arch/arm/boot/dts/overlays/imx219.dtsi b/arch/arm/boot/dts/overlays/imx219.dtsi +new file mode 100644 +index 000000000000..fa870f77ef07 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx219.dtsi +@@ -0,0 +1,27 @@ ++// Fragment that configures an imx219 ++ ++cam_node: imx219@10 { ++ compatible = "sony,imx219"; ++ reg = <0x10>; ++ status = "disabled"; ++ ++ clocks = <&cam1_clk>; ++ clock-names = "xclk"; ++ ++ VANA-supply = <&cam1_reg>; /* 2.8v */ ++ VDIG-supply = <&cam_dummy_reg>; /* 1.8v */ ++ VDDL-supply = <&cam_dummy_reg>; /* 1.2v */ ++ ++ rotation = <180>; ++ orientation = <2>; ++ ++ port { ++ cam_endpoint: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = ++ /bits/ 64 <456000000>; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/imx258-overlay.dts b/arch/arm/boot/dts/overlays/imx258-overlay.dts +new file mode 100644 +index 000000000000..656a588f15cc +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx258-overlay.dts +@@ -0,0 +1,131 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Definitions for IMX258 camera module on VC I2C bus ++/dts-v1/; ++/plugin/; ++ ++#include <dt-bindings/gpio/gpio.h> ++ ++/{ ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ clk_frag: fragment@1 { ++ target = <&cam1_clk>; ++ cam_clk: __overlay__ { ++ clock-frequency = <24000000>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@11 { ++ target = <&cam_endpoint>; ++ __overlay__ { ++ data-lanes = <1 2>; ++ link-frequencies = /bits/ 64 <633600000 ++ 320000000>; ++ }; ++ }; ++ ++ fragment@12 { ++ target = <&cam_endpoint>; ++ __dormant__ { ++ data-lanes = <1 2 3 4>; ++ link-frequencies = ++ /bits/ 64 <633600000 320000000>; ++ }; ++ }; ++ ++ fragment@13 { ++ target = <&csi_ep>; ++ __overlay__ { ++ data-lanes = <1 2>; ++ }; ++ }; ++ ++ fragment@14 { ++ target = <&csi_ep>; ++ __dormant__ { ++ data-lanes = <1 2 3 4>; ++ }; ++ }; ++ + csi_frag: fragment@101 { + target = <&csi1>; + csi: __overlay__ { @@ -21417,29 +33111,101 @@ + + port { + csi_ep: endpoint { -+ remote-endpoint = <&imx219_0>; ++ remote-endpoint = <&cam_endpoint>; + clock-lanes = <0>; -+ data-lanes = <1 2>; + clock-noncontinuous; + }; + }; + }; + }; + ++ reg_frag: fragment@5 { ++ target = <&cam1_reg>; ++ cam_reg: __overlay__ { ++ regulator-name = "imx258_vana"; ++ startup-delay-us = <300000>; ++ regulator-min-microvolt = <2700000>; ++ regulator-max-microvolt = <2700000>; ++ }; ++ }; ++ ++ i2c_frag: fragment@100 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ #include "imx258.dtsi" ++ ++ vcm: ad5398@c { ++ compatible = "adi,ad5398"; ++ reg = <0x0c>; ++ status = "disabled"; ++ VANA-supply = <&cam1_reg>; ++ }; ++ }; ++ }; ++ + __overrides__ { -+ rotation = <&imx219>,"rotation:0"; -+ orientation = <&imx219>,"orientation:0"; ++ rotation = <&cam_node>,"rotation:0"; ++ orientation = <&cam_node>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; -+ cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, -+ <&imx219>, "clocks:0=",<&cam0_clk>, -+ <&imx219>, "VANA-supply:0=",<&cam0_reg>; ++ <®_frag>, "target:0=",<&cam0_reg>, ++ <&cam_node>, "clocks:0=",<&cam0_clk>, ++ <&cam_node>, "vana-supply:0=",<&cam0_reg>; ++ vcm = <&vcm>, "status=okay", ++ <&cam_node>,"lens-focus:0=", <&vcm>; ++ 4lane = <0>, "-11+12-13+14"; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; +diff --git a/arch/arm/boot/dts/overlays/imx258.dtsi b/arch/arm/boot/dts/overlays/imx258.dtsi +new file mode 100644 +index 000000000000..cca81e1aa8b3 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx258.dtsi +@@ -0,0 +1,27 @@ ++// Fragment that configures a Sony IMX258 ++ ++cam_node: imx258@10 { ++ compatible = "sony,imx258"; ++ reg = <0x10>; ++ status = "disabled"; ++ ++ clocks = <&cam1_clk>; ++ clock-names = "xclk"; ++ ++ vana-supply = <&cam1_reg>; /* 2.8v */ ++ vdig-supply = <&cam_dummy_reg>; /* 1.05v */ ++ vif-supply = <&cam_dummy_reg>; /* 1.8v */ ++ ++ rotation = <180>; ++ orientation = <2>; ++ ++ port { ++ cam_endpoint: endpoint { ++ clock-lanes = <0>; ++ clock-noncontinuous; ++ link-frequencies = ++ /bits/ 64 <633600000 ++ 320000000>; ++ }; + }; +}; diff --git a/arch/arm/boot/dts/overlays/imx290-overlay.dts b/arch/arm/boot/dts/overlays/imx290-overlay.dts new file mode 100644 -index 000000000000..e536aa7f9e33 +index 000000000000..3de3c3910d90 --- /dev/null +++ b/arch/arm/boot/dts/overlays/imx290-overlay.dts @@ -0,0 +1,32 @@ @@ -21458,16 +33224,16 @@ + // included imx290_327 overlay file. + + fragment@101 { -+ target = <&imx290>; ++ target = <&cam_node>; + __overlay__ { -+ compatible = "sony,imx290"; ++ compatible = "sony,imx290lqr"; + }; + }; + + fragment@102 { -+ target = <&imx290>; ++ target = <&cam_node>; + __dormant__ { -+ compatible = "sony,imx290-mono"; ++ compatible = "sony,imx290llr"; + }; + }; + @@ -21477,10 +33243,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi b/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi new file mode 100644 -index 000000000000..111d69597554 +index 000000000000..8fe48352e695 --- /dev/null +++ b/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi -@@ -0,0 +1,125 @@ +@@ -0,0 +1,112 @@ +// 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 @@ -21499,28 +33265,7 @@ + #size-cells = <0>; + status = "okay"; + -+ imx290: imx290@1a { -+ reg = <0x1a>; -+ status = "okay"; -+ -+ clocks = <&cam1_clk>; -+ clock-names = "xclk"; -+ clock-frequency = <37125000>; -+ -+ rotation = <0>; -+ orientation = <2>; -+ -+ vdda-supply = <&cam1_reg>; /* 2.8v */ -+ vdddo-supply = <&cam_dummy_reg>; /* 1.8v */ -+ vddd-supply = <&cam_dummy_reg>; /* 1.5v */ -+ -+ port { -+ imx290_0: endpoint { -+ remote-endpoint = <&csi1_ep>; -+ clock-lanes = <0>; -+ }; -+ }; -+ }; ++ #include "imx290_327.dtsi" + }; + }; + @@ -21531,8 +33276,8 @@ + brcm,media-controller; + + port { -+ csi1_ep: endpoint { -+ remote-endpoint = <&imx290_0>; ++ csi_ep: endpoint { ++ remote-endpoint = <&cam_endpoint>; + }; + }; + }; @@ -21561,7 +33306,7 @@ + }; + + fragment@6 { -+ target = <&imx290_0>; ++ target = <&cam_endpoint>; + __overlay__ { + data-lanes = <1 2>; + link-frequencies = @@ -21570,7 +33315,7 @@ + }; + + fragment@7 { -+ target = <&imx290_0>; ++ target = <&cam_endpoint>; + __dormant__ { + data-lanes = <1 2 3 4>; + link-frequencies = @@ -21579,14 +33324,14 @@ + }; + + fragment@8 { -+ target = <&csi1_ep>; ++ target = <&csi_ep>; + __overlay__ { + data-lanes = <1 2>; + }; + }; + + fragment@9 { -+ target = <&csi1_ep>; ++ target = <&csi_ep>; + __dormant__ { + data-lanes = <1 2 3 4>; + }; @@ -21595,23 +33340,220 @@ + __overrides__ { + 4lane = <0>, "-6+7-8+9"; + clock-frequency = <&cam_clk>,"clock-frequency:0", -+ <&imx290>,"clock-frequency:0"; -+ rotation = <&imx290>,"rotation:0"; -+ orientation = <&imx290>,"orientation:0"; ++ <&cam_node>,"clock-frequency:0"; ++ rotation = <&cam_node>,"rotation:0"; ++ orientation = <&cam_node>,"orientation:0"; ++ media-controller = <&csi>,"brcm,media-controller?"; ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&csi_frag>, "target:0=",<&csi0>, ++ <&clk_frag>, "target:0=",<&cam0_clk>, ++ <&cam_node>, "clocks:0=",<&cam0_clk>, ++ <&cam_node>, "vdda-supply:0=",<&cam0_reg>; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; +diff --git a/arch/arm/boot/dts/overlays/imx290_327.dtsi b/arch/arm/boot/dts/overlays/imx290_327.dtsi +new file mode 100644 +index 000000000000..14d1f0b95bb3 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx290_327.dtsi +@@ -0,0 +1,24 @@ ++// Fragment to configure and IMX290 / IMX327 / IMX462 image sensor ++ ++cam_node: imx290@1a { ++ compatible = "sony,imx290lqr"; ++ reg = <0x1a>; ++ status = "disabled"; ++ ++ clocks = <&cam1_clk>; ++ clock-names = "xclk"; ++ clock-frequency = <37125000>; ++ ++ rotation = <0>; ++ orientation = <2>; ++ ++ vdda-supply = <&cam1_reg>; /* 2.8v */ ++ vdddo-supply = <&cam_dummy_reg>; /* 1.8v */ ++ vddd-supply = <&cam_dummy_reg>; /* 1.5v */ ++ ++ port { ++ cam_endpoint: endpoint { ++ clock-lanes = <0>; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/imx296-overlay.dts b/arch/arm/boot/dts/overlays/imx296-overlay.dts +new file mode 100644 +index 000000000000..0eb4d9c2dc3b +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx296-overlay.dts +@@ -0,0 +1,114 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Definitions for IMX296 camera module on VC I2C bus ++/dts-v1/; ++/plugin/; ++ ++#include <dt-bindings/gpio/gpio.h> ++ ++/{ ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ clk_frag: fragment@1 { ++ target = <&cam1_clk>; ++ clk_over: __overlay__ { ++ status = "okay"; ++ clock-frequency = <54000000>; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ reg_frag: fragment@5 { ++ target = <&cam1_reg>; ++ cam_reg: __overlay__ { ++ startup-delay-us = <500000>; ++ }; ++ }; ++ ++ reg_alwayson_frag: fragment@99 { ++ target = <&cam1_reg>; ++ __dormant__ { ++ regulator-always-on; ++ }; ++ }; ++ ++ i2c_frag: fragment@100 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ imx296: imx296@1a { ++ compatible = "sony,imx296"; ++ reg = <0x1a>; ++ status = "okay"; ++ ++ clocks = <&cam1_clk>; ++ clock-names = "inck"; ++ ++ avdd-supply = <&cam1_reg>; /* 3.3v */ ++ dvdd-supply = <&cam_dummy_reg>; /* 1.8v */ ++ ovdd-supply = <&cam_dummy_reg>; /* 1.2v */ ++ ++ rotation = <180>; ++ orientation = <2>; ++ ++ port { ++ imx296_0: endpoint { ++ remote-endpoint = <&csi_ep>; ++ clock-lanes = <0>; ++ data-lanes = <1>; ++ clock-noncontinuous; ++ link-frequencies = ++ /bits/ 64 <594000000>; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ csi_frag: fragment@101 { ++ target = <&csi1>; ++ csi: __overlay__ { ++ status = "okay"; ++ brcm,media-controller; ++ ++ port { ++ csi_ep: endpoint { ++ remote-endpoint = <&imx296_0>; ++ clock-lanes = <0>; ++ data-lanes = <1>; ++ clock-noncontinuous; ++ }; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ rotation = <&imx296>,"rotation:0"; ++ orientation = <&imx296>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; -+ cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, -+ <&imx290>, "clocks:0=",<&cam0_clk>, -+ <&imx290>, "vdda-supply:0=",<&cam0_reg>; ++ <®_frag>, "target:0=",<&cam0_reg>, ++ <®_alwayson_frag>, "target:0=",<&cam0_reg>, ++ <&imx296>, "clocks:0=",<&cam0_clk>, ++ <&imx296>, "avdd-supply:0=",<&cam0_reg>; ++ clock-frequency = <&clk_over>, "clock-frequency:0"; ++ always-on = <0>, "+99"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/imx327-overlay.dts b/arch/arm/boot/dts/overlays/imx327-overlay.dts +new file mode 100644 +index 000000000000..0776954bdba2 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx327-overlay.dts +@@ -0,0 +1,33 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Definitions for IMX327 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 = <&cam_node>; ++ __overlay__ { ++ compatible = "sony,imx327lqr"; ++ }; ++ }; ++ ++ fragment@102 { ++ target = <&cam_node>; ++ __dormant__ { ++ // No mono IMX327 is currently defined. Use IMX290. ++ compatible = "sony,imx290llr"; ++ }; ++ }; ++ ++ __overrides__ { ++ mono = <0>, "-101+102"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/imx378-overlay.dts b/arch/arm/boot/dts/overlays/imx378-overlay.dts new file mode 100644 -index 000000000000..74c7288d12f5 +index 000000000000..4a5072489a34 --- /dev/null +++ b/arch/arm/boot/dts/overlays/imx378-overlay.dts -@@ -0,0 +1,10 @@ +@@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Definitions for IMX378 camera module on VC I2C bus +/dts-v1/; @@ -21619,15 +33561,67 @@ + +#include "imx477_378-overlay.dtsi" + -+&imx477 { ++&cam_node { + compatible = "sony,imx378"; +}; ++ ++/{ ++ __overrides__ { ++ sync-sink = <&cam_node>,"trigger-mode:0=2"; ++ sync-source = <&cam_node>,"trigger-mode:0=1"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/imx462-overlay.dts b/arch/arm/boot/dts/overlays/imx462-overlay.dts +new file mode 100644 +index 000000000000..c4d7aabe2efe +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx462-overlay.dts +@@ -0,0 +1,39 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Definitions for IMX462 camera module on VC I2C bus ++ ++// IMX462 is the successor to IMX290. The drivers currently don't support ++// any additional feature of IMX462, so use the IMX290 compatible strings ++// for now. ++ ++/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. ++ ++ //IMX462 is not defined in the bindings, so use IMX290 for now. ++ ++ fragment@101 { ++ target = <&cam_node>; ++ __overlay__ { ++ compatible = "sony,imx290lqr"; ++ }; ++ }; ++ ++ fragment@102 { ++ target = <&cam_node>; ++ __dormant__ { ++ compatible = "sony,imx290llr"; ++ }; ++ }; ++ ++ __overrides__ { ++ mono = <0>, "-101+102"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/imx477-overlay.dts b/arch/arm/boot/dts/overlays/imx477-overlay.dts new file mode 100644 -index 000000000000..ca315d120e6b +index 000000000000..8645162682f4 --- /dev/null +++ b/arch/arm/boot/dts/overlays/imx477-overlay.dts -@@ -0,0 +1,10 @@ +@@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Definitions for IMX477 camera module on VC I2C bus +/dts-v1/; @@ -21635,29 +33629,36 @@ + +#include "imx477_378-overlay.dtsi" + -+&imx477 { ++&cam_node { + compatible = "sony,imx477"; +}; ++ ++/{ ++ __overrides__ { ++ sync-sink = <&cam_node>,"trigger-mode:0=2"; ++ sync-source = <&cam_node>,"trigger-mode:0=1"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi b/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi new file mode 100644 -index 000000000000..bfea40ce98d6 +index 000000000000..1ce42c2c8946 --- /dev/null +++ b/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi -@@ -0,0 +1,99 @@ +@@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Definitions for IMX477 camera module on VC I2C bus + +/{ + compatible = "brcm,bcm2835"; + -+ fragment@2 { ++ fragment@0 { + target = <&i2c0if>; + __overlay__ { + status = "okay"; + }; + }; + -+ clk_frag: fragment@3 { ++ clk_frag: fragment@1 { + target = <&cam1_clk>; + cam_clk: __overlay__ { + clock-frequency = <24000000>; @@ -21665,20 +33666,27 @@ + }; + }; + -+ fragment@4 { ++ fragment@2 { + target = <&i2c0mux>; + __overlay__ { + status = "okay"; + }; + }; + -+ reg_frag: fragment@5 { ++ reg_frag: fragment@3 { + target = <&cam1_reg>; + cam_reg: __overlay__ { + startup-delay-us = <300000>; + }; + }; + ++ reg_alwayson_frag: fragment@99 { ++ target = <&cam1_reg>; ++ __dormant__ { ++ regulator-always-on; ++ }; ++ }; ++ + i2c_frag: fragment@100 { + target = <&i2c_csi_dsi>; + __overlay__ { @@ -21686,31 +33694,7 @@ + #size-cells = <0>; + status = "okay"; + -+ imx477: imx477@1a { -+ reg = <0x1a>; -+ status = "okay"; -+ -+ clocks = <&cam1_clk>; -+ clock-names = "xclk"; -+ -+ VANA-supply = <&cam1_reg>; /* 2.8v */ -+ VDIG-supply = <&cam_dummy_reg>; /* 1.05v */ -+ VDDL-supply = <&cam_dummy_reg>; /* 1.8v */ -+ -+ rotation = <180>; -+ orientation = <2>; -+ -+ port { -+ imx477_0: endpoint { -+ remote-endpoint = <&csi_ep>; -+ clock-lanes = <0>; -+ data-lanes = <1 2>; -+ clock-noncontinuous; -+ link-frequencies = -+ /bits/ 64 <450000000>; -+ }; -+ }; -+ }; ++ #include "imx477_378.dtsi" + }; + }; + @@ -21722,7 +33706,7 @@ + + port { + csi_ep: endpoint { -+ remote-endpoint = <&imx477_0>; ++ remote-endpoint = <&cam_endpoint>; + clock-lanes = <0>; + data-lanes = <1 2>; + clock-noncontinuous; @@ -21732,23 +33716,63 @@ + }; + + __overrides__ { -+ rotation = <&imx477>,"rotation:0"; -+ orientation = <&imx477>,"orientation:0"; ++ rotation = <&cam_node>,"rotation:0"; ++ orientation = <&cam_node>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; -+ cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <®_frag>, "target:0=",<&cam0_reg>, -+ <&imx477>, "clocks:0=",<&cam0_clk>, -+ <&imx477>, "vdda-supply:0=",<&cam0_reg>; ++ <®_alwayson_frag>, "target:0=",<&cam0_reg>, ++ <&cam_node>, "clocks:0=",<&cam0_clk>, ++ <&cam_node>, "VANA-supply:0=",<&cam0_reg>; ++ always-on = <0>, "+99"; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; +diff --git a/arch/arm/boot/dts/overlays/imx477_378.dtsi b/arch/arm/boot/dts/overlays/imx477_378.dtsi +new file mode 100644 +index 000000000000..a0c154c2a11f +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx477_378.dtsi +@@ -0,0 +1,24 @@ ++cam_node: imx477@1a { ++ reg = <0x1a>; ++ status = "disabled"; ++ ++ clocks = <&cam1_clk>; ++ clock-names = "xclk"; ++ ++ VANA-supply = <&cam1_reg>; /* 2.8v */ ++ VDIG-supply = <&cam_dummy_reg>; /* 1.05v */ ++ VDDL-supply = <&cam_dummy_reg>; /* 1.8v */ ++ ++ rotation = <180>; ++ orientation = <2>; ++ ++ port { ++ cam_endpoint: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = ++ /bits/ 64 <450000000>; ++ }; + }; +}; diff --git a/arch/arm/boot/dts/overlays/imx519-overlay.dts b/arch/arm/boot/dts/overlays/imx519-overlay.dts new file mode 100644 -index 000000000000..ada1224dd19b +index 000000000000..f572634836b8 --- /dev/null +++ b/arch/arm/boot/dts/overlays/imx519-overlay.dts -@@ -0,0 +1,96 @@ +@@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Definitions for imx519 camera module on VC I2C bus +/dts-v1/; @@ -21766,32 +33790,7 @@ + #size-cells = <0>; + status = "okay"; + -+ imx519: imx519@1a { -+ compatible = "sony,imx519"; -+ reg = <0x1a>; -+ status = "okay"; -+ -+ clocks = <&cam1_clk>; -+ clock-names = "xclk"; -+ -+ VANA-supply = <&cam1_reg>; /* 2.8v */ -+ VDIG-supply = <&cam_dummy_reg>; /* 1.8v */ -+ VDDL-supply = <&cam_dummy_reg>; /* 1.2v */ -+ -+ rotation = <0>; -+ orientation = <2>; -+ -+ port { -+ imx519_0: endpoint { -+ remote-endpoint = <&csi1_ep>; -+ clock-lanes = <0>; -+ data-lanes = <1 2>; -+ clock-noncontinuous; -+ link-frequencies = -+ /bits/ 64 <493500000>; -+ }; -+ }; -+ }; ++ #include "imx519.dtsi" + }; + }; + @@ -21802,8 +33801,8 @@ + brcm,media-controller; + + port{ -+ csi1_ep: endpoint{ -+ remote-endpoint = <&imx519_0>; ++ csi_ep: endpoint{ ++ remote-endpoint = <&cam_endpoint>; + clock-lanes = <0>; + data-lanes = <1 2>; + clock-noncontinuous; @@ -21834,20 +33833,368 @@ + }; + }; + ++ fragment@5 { ++ target = <&cam_node>; ++ __overlay__ { ++ lens-focus = <&vcm_node>; ++ }; ++ }; ++ ++ __overrides__ { ++ rotation = <&cam_node>,"rotation:0"; ++ orientation = <&cam_node>,"orientation:0"; ++ media-controller = <&csi>,"brcm,media-controller?"; ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&csi_frag>, "target:0=",<&csi0>, ++ <&clk_frag>, "target:0=",<&cam0_clk>, ++ <&cam_node>, "clocks:0=",<&cam0_clk>, ++ <&cam_node>, "VANA-supply:0=",<&cam0_reg>, ++ <&vcm_node>, "vdd-supply:0=",<&cam0_reg>; ++ vcm = <&vcm_node>, "status", ++ <0>, "=5"; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; ++ ++&vcm_node { ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/overlays/imx519.dtsi b/arch/arm/boot/dts/overlays/imx519.dtsi +new file mode 100644 +index 000000000000..18cba1781ec4 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx519.dtsi +@@ -0,0 +1,34 @@ ++// Fragment that configures a Sony IMX519 ++ ++cam_node: imx519@1a { ++ compatible = "sony,imx519"; ++ reg = <0x1a>; ++ status = "disabled"; ++ ++ clocks = <&cam1_clk>; ++ clock-names = "xclk"; ++ ++ VANA-supply = <&cam1_reg>; /* 2.8v */ ++ VDIG-supply = <&cam_dummy_reg>; /* 1.8v */ ++ VDDL-supply = <&cam_dummy_reg>; /* 1.2v */ ++ ++ rotation = <0>; ++ orientation = <2>; ++ ++ port { ++ cam_endpoint: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = ++ /bits/ 64 <408000000>; ++ }; ++ }; ++}; ++ ++vcm_node: ak7375@c { ++ compatible = "asahi-kasei,ak7375"; ++ reg = <0x0c>; ++ status = "disabled"; ++ vdd-supply = <&cam1_reg>; ++}; +diff --git a/arch/arm/boot/dts/overlays/imx708-overlay.dts b/arch/arm/boot/dts/overlays/imx708-overlay.dts +new file mode 100644 +index 000000000000..a7042284a1ea +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx708-overlay.dts +@@ -0,0 +1,105 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Definitions for IMX708 camera module on VC I2C bus ++/dts-v1/; ++/plugin/; ++ ++#include <dt-bindings/gpio/gpio.h> ++ ++/{ ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ clk_frag: fragment@1 { ++ target = <&cam1_clk>; ++ __overlay__ { ++ status = "okay"; ++ clock-frequency = <24000000>; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ reg_frag: fragment@3 { ++ target = <&cam1_reg>; ++ cam_reg: __overlay__ { ++ startup-delay-us = <70000>; ++ off-on-delay-us = <30000>; ++ regulator-min-microvolt = <2700000>; ++ regulator-max-microvolt = <2700000>; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&cam_node>; ++ __overlay__ { ++ lens-focus = <&vcm_node>; ++ }; ++ }; ++ ++ i2c_frag: fragment@100 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ #include "imx708.dtsi" ++ }; ++ }; ++ ++ csi_frag: fragment@101 { ++ target = <&csi1>; ++ csi: __overlay__ { ++ status = "okay"; ++ brcm,media-controller; ++ ++ port { ++ csi_ep: endpoint { ++ remote-endpoint = <&cam_endpoint>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ }; ++ }; ++ }; ++ }; ++ + __overrides__ { -+ rotation = <&imx519>,"rotation:0"; -+ orientation = <&imx519>,"orientation:0"; ++ rotation = <&cam_node>,"rotation:0"; ++ orientation = <&cam_node>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; -+ cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, -+ <&imx519>, "clocks:0=",<&cam0_clk>, -+ <&imx519>, "VANA-supply:0=",<&cam0_reg>; ++ <®_frag>, "target:0=",<&cam0_reg>, ++ <&cam_node>, "clocks:0=",<&cam0_clk>, ++ <&cam_node>, "vana1-supply:0=",<&cam0_reg>, ++ <&vcm_node>, "VDD-supply:0=",<&cam0_reg>; ++ vcm = <&vcm_node>, "status", ++ <0>, "=4"; ++ link-frequency = <&cam_endpoint>,"link-frequencies#0"; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; ++ ++&vcm_node { ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/overlays/imx708.dtsi b/arch/arm/boot/dts/overlays/imx708.dtsi +new file mode 100644 +index 000000000000..1558458d58ec +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx708.dtsi +@@ -0,0 +1,35 @@ ++// Fragment that configures a Sony IMX708 ++ ++cam_node: imx708@1a { ++ compatible = "sony,imx708"; ++ reg = <0x1a>; ++ status = "disabled"; ++ ++ clocks = <&cam1_clk>; ++ clock-names = "inclk"; ++ ++ vana1-supply = <&cam1_reg>; /* 2.8v */ ++ vana2-supply = <&cam_dummy_reg>;/* 1.8v */ ++ vdig-supply = <&cam_dummy_reg>; /* 1.1v */ ++ vddl-supply = <&cam_dummy_reg>; /* 1.8v */ ++ ++ rotation = <180>; ++ orientation = <2>; ++ ++ port { ++ cam_endpoint: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = ++ /bits/ 64 <450000000>; ++ }; ++ }; ++}; ++ ++vcm_node: dw9817@c { ++ compatible = "dongwoon,dw9817-vcm"; ++ reg = <0x0c>; ++ status = "disabled"; ++ VDD-supply = <&cam1_reg>; ++}; +diff --git a/arch/arm/boot/dts/overlays/interludeaudio-analog-overlay.dts b/arch/arm/boot/dts/overlays/interludeaudio-analog-overlay.dts +new file mode 100644 +index 000000000000..e2590135f919 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/interludeaudio-analog-overlay.dts +@@ -0,0 +1,73 @@ ++// Definitions for Interlude audio analog hat ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&sound>; ++ __overlay__ { ++ compatible = "simple-audio-card"; ++ i2s-controller = <&i2s_clk_consumer>; ++ status = "okay"; ++ ++ simple-audio-card,name = "snd_IA_Analog_Hat"; ++ ++ 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_clk_consumer>; ++ __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 24 0>; /* Pin 26, active high */ ++ }; ++ }; ++ }; ++ __overrides__ { ++ gpiopin = <&cs4271>,"reset-gpio:4"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/interludeaudio-digital-overlay.dts b/arch/arm/boot/dts/overlays/interludeaudio-digital-overlay.dts +new file mode 100644 +index 000000000000..24be00860310 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/interludeaudio-digital-overlay.dts +@@ -0,0 +1,49 @@ ++// Definitions for Interlude Audio Digital Hat ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2s_clk_consumer>; ++ __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 = "interludeaudio,interludeaudio-digital"; ++ i2s-controller = <&i2s_clk_consumer>; ++ status = "okay"; ++ clock44-gpio = <&gpio 22 0>; ++ clock48-gpio = <&gpio 27 0>; ++ led1-gpio = <&gpio 13 0>; ++ led2-gpio = <&gpio 12 0>; ++ led3-gpio = <&gpio 6 0>; ++ reset-gpio = <&gpio 23 0>; ++ }; + }; ++ +}; diff --git a/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts b/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts new file mode 100644 -index 000000000000..9110f5d34298 +index 000000000000..bffff5a4d64c --- /dev/null +++ b/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts @@ -0,0 +1,42 @@ @@ -21859,7 +34206,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -21885,7 +34232,7 @@ + target = <&sound>; + iqaudio_dac: __overlay__ { + compatible = "iqaudio,iqaudio-codec"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; @@ -21895,7 +34242,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts b/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts new file mode 100644 -index 000000000000..24073cadd0ef +index 000000000000..05d348f5e58a --- /dev/null +++ b/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts @@ -0,0 +1,46 @@ @@ -21907,7 +34254,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -21936,7 +34283,7 @@ + target = <&sound>; + frag2: __overlay__ { + compatible = "iqaudio,iqaudio-dac"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; @@ -21947,7 +34294,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts new file mode 100644 -index 000000000000..7c70b25e58d7 +index 000000000000..3993580f7ac1 --- /dev/null +++ b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts @@ -0,0 +1,49 @@ @@ -21959,7 +34306,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -21988,7 +34335,7 @@ + target = <&sound>; + iqaudio_dac: __overlay__ { + compatible = "iqaudio,iqaudio-dac"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + mute-gpios = <&gpio 22 0>; + status = "okay"; + }; @@ -22002,7 +34349,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts b/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts new file mode 100644 -index 000000000000..ee54095c869b +index 000000000000..f24faf11ecfa --- /dev/null +++ b/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts @@ -0,0 +1,47 @@ @@ -22014,7 +34361,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -22042,7 +34389,7 @@ + target = <&sound>; + wm8804_digi: __overlay__ { + compatible = "iqaudio,wm8804-digi"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; @@ -22053,9 +34400,74 @@ + dai_stream_name = <&wm8804_digi>,"wm8804-digi,dai-stream-name"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/iqs550-overlay.dts b/arch/arm/boot/dts/overlays/iqs550-overlay.dts +new file mode 100644 +index 000000000000..c3956937055f +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/iqs550-overlay.dts +@@ -0,0 +1,59 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++// Definitions for Azoteq IQS550 trackpad/touchscreen controller ++/dts-v1/; ++/plugin/; ++#include <dt-bindings/gpio/gpio.h> ++#include <dt-bindings/interrupt-controller/irq.h> ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2c1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ iqs550: iqs550@74 { ++ compatible = "azoteq,iqs550"; ++ reg = <0x74>; ++ interrupt-parent = <&gpio>; ++ interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&iqs550_pins>; ++ touchscreen-size-x = <800>; ++ touchscreen-size-y = <480>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&iqs550>; ++ iqs550_reset: __dormant__ { ++ reset-gpios = <&gpio 255 (GPIO_ACTIVE_LOW | ++ GPIO_PUSH_PULL)>; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&gpio>; ++ __overlay__ { ++ iqs550_pins: iqs550_pins { ++ brcm,pins = <4>; ++ brcm,pull = <1>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ interrupt = <&iqs550>,"interrupts:0", ++ <&iqs550_pins>,"brcm,pins:0"; ++ reset = <0>,"+1", <&iqs550_reset>,"reset-gpios:4"; ++ sizex = <&iqs550>,"touchscreen-size-x:0"; ++ sizey = <&iqs550>,"touchscreen-size-y:0"; ++ invx = <&iqs550>,"touchscreen-inverted-x?"; ++ invy = <&iqs550>,"touchscreen-inverted-y?"; ++ swapxy = <&iqs550>,"touchscreen-swapped-x-y?"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/irs1125-overlay.dts b/arch/arm/boot/dts/overlays/irs1125-overlay.dts new file mode 100644 -index 000000000000..8f8432c07a89 +index 000000000000..0fe854557cd7 --- /dev/null +++ b/arch/arm/boot/dts/overlays/irs1125-overlay.dts @@ -0,0 +1,90 @@ @@ -22143,7 +34555,7 @@ + + __overrides__ { + media-controller = <&csi>,"brcm,media-controller?"; -+ cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&irs1125>, "clocks:0=",<&cam0_clk>; @@ -22151,15 +34563,16 @@ +}; diff --git a/arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts b/arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts new file mode 100644 -index 000000000000..585c7dbcdf7f +index 000000000000..fb6d4bc91bf3 --- /dev/null +++ b/arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts -@@ -0,0 +1,309 @@ +@@ -0,0 +1,136 @@ +// 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>. ++// speed - Set the SPI clock speed in Hz +// +// If devices are present on SPI1 or SPI2, those interfaces must be enabled with one of the spi1-1/2/3cs and/or spi2-1/2/3cs overlays. +// @@ -22236,101 +34649,23 @@ + }; + }; + -+ // enable flash on spi0.0 ++ // Enable fast read for device ++ // Use default active low interrupt signalling. + fragment@8 { -+ target = <&spi0>; ++ target = <&spi_nor>; + __dormant__ { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ spi_nor_00: spi_nor@0 { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ compatible = "jedec,spi-nor"; -+ reg = <0>; -+ spi-max-frequency = <500000>; -+ }; ++ m25p,fast-read; + }; + }; + -+ // enable flash on spi0.1 -+ fragment@9 { ++ payload: fragment@100 { + target = <&spi0>; -+ __dormant__ { -+ 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__ { ++ __overlay__ { + 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>; -+ }; -+ }; -+ }; ++ #address-cells = <1>; ++ #size-cells = <0>; + -+ // 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>; ++ spi_nor: spi_nor@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <500000>; @@ -22338,135 +34673,39 @@ + }; + }; + -+ // enable flash on spi2.1 -+ fragment@14 { -+ target = <&spi2>; -+ __dormant__ { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ spi_nor_21: spi_nor@1 { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ compatible = "jedec,spi-nor"; -+ reg = <1>; -+ spi-max-frequency = <500000>; -+ }; -+ }; -+ }; -+ -+ // enable flash on spi2.2 -+ fragment@15 { -+ target = <&spi2>; -+ __dormant__ { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ spi_nor_22: spi_nor@2 { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ compatible = "jedec,spi-nor"; -+ reg = <2>; -+ spi-max-frequency = <500000>; -+ }; -+ }; -+ }; -+ -+ // Enable fast read for device on spi0.0. -+ // Use default active low interrupt signalling. -+ fragment@16 { -+ target = <&spi_nor_00>; -+ __dormant__ { -+ m25p,fast-read; -+ }; -+ }; -+ -+ // Enable fast read for device on spi0.1. -+ // Use default active low interrupt signalling. -+ fragment@17 { -+ target = <&spi_nor_01>; -+ __dormant__ { -+ m25p,fast-read; -+ }; -+ }; -+ -+ // Enable fast read for device on spi1.0. -+ // Use default active low interrupt signalling. -+ fragment@18 { -+ target = <&spi_nor_10>; -+ __dormant__ { -+ m25p,fast-read; -+ }; -+ }; -+ -+ // Enable fast read for device on spi1.1. -+ // Use default active low interrupt signalling. -+ fragment@19 { -+ target = <&spi_nor_11>; -+ __dormant__ { -+ m25p,fast-read; -+ }; -+ }; -+ -+ // Enable fast read for device on spi1.2. -+ // Use default active low interrupt signalling. -+ fragment@20 { -+ target = <&spi_nor_12>; -+ __dormant__ { -+ m25p,fast-read; -+ }; -+ }; -+ -+ // Enable fast read for device on spi2.0. -+ // Use default active low interrupt signalling. -+ fragment@21 { -+ target = <&spi_nor_20>; -+ __dormant__ { -+ m25p,fast-read; -+ }; -+ }; -+ -+ // Enable fast read for device on spi2.1. -+ // Use default active low interrupt signalling. -+ fragment@22 { -+ target = <&spi_nor_21>; -+ __dormant__ { -+ m25p,fast-read; -+ }; -+ }; -+ -+ // Enable fast read for device on spi2.2. -+ // Use default active low interrupt signalling. -+ fragment@23 { -+ target = <&spi_nor_22>; -+ __dormant__ { -+ m25p,fast-read; -+ }; -+ }; -+ + __overrides__ { -+ flash-spi0-0 = <0>,"+0+8"; -+ flash-spi0-1 = <0>,"+1+9"; -+ flash-spi1-0 = <0>,"+2+10"; -+ flash-spi1-1 = <0>,"+3+11"; -+ flash-spi1-2 = <0>,"+4+12"; -+ flash-spi2-0 = <0>,"+5+13"; -+ flash-spi2-1 = <0>,"+6+14"; -+ flash-spi2-2 = <0>,"+7+15"; -+ flash-fastr-spi0-0 = <0>,"+0+8+16"; -+ flash-fastr-spi0-1 = <0>,"+1+9+17"; -+ flash-fastr-spi1-0 = <0>,"+2+10+18"; -+ flash-fastr-spi1-1 = <0>,"+3+11+19"; -+ flash-fastr-spi1-2 = <0>,"+4+12+20"; -+ flash-fastr-spi2-0 = <0>,"+5+13+21"; -+ flash-fastr-spi2-1 = <0>,"+6+14+22"; -+ flash-fastr-spi2-2 = <0>,"+7+15+23"; ++ spi0-0 = <0>,"+0", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=0"; ++ spi0-1 = <0>,"+1", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=1"; ++ spi1-0 = <0>,"+2", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=0"; ++ spi1-1 = <0>,"+3", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=1"; ++ spi1-2 = <0>,"+4", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=2"; ++ spi2-0 = <0>,"+5", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=0"; ++ spi2-1 = <0>,"+6", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=1"; ++ spi2-2 = <0>,"+7", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=2"; ++ flash-spi0-0 = <0>,"+0", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=0"; ++ flash-spi0-1 = <0>,"+1", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=1"; ++ flash-spi1-0 = <0>,"+2", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=0"; ++ flash-spi1-1 = <0>,"+3", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=1"; ++ flash-spi1-2 = <0>,"+4", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=2"; ++ flash-spi2-0 = <0>,"+5", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=0"; ++ flash-spi2-1 = <0>,"+6", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=1"; ++ flash-spi2-2 = <0>,"+7", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=2"; ++ flash-fastr-spi0-0 = <0>,"+0+8", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=0"; ++ flash-fastr-spi0-1 = <0>,"+1+8", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=1"; ++ flash-fastr-spi1-0 = <0>,"+2+8", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=0"; ++ flash-fastr-spi1-1 = <0>,"+3+8", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=1"; ++ flash-fastr-spi1-2 = <0>,"+4+8", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=2"; ++ flash-fastr-spi2-0 = <0>,"+5+8", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=0"; ++ flash-fastr-spi2-1 = <0>,"+6+8", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=1"; ++ flash-fastr-spi2-2 = <0>,"+7+8", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=2"; ++ fastr = <0>,"+8"; ++ speed = <&spi_nor>, "spi-max-frequency:0"; + }; +}; + diff --git a/arch/arm/boot/dts/overlays/justboom-both-overlay.dts b/arch/arm/boot/dts/overlays/justboom-both-overlay.dts new file mode 100644 -index 000000000000..9c42670631c0 +index 000000000000..9185d668d1d5 --- /dev/null +++ b/arch/arm/boot/dts/overlays/justboom-both-overlay.dts @@ -0,0 +1,65 @@ @@ -22479,7 +34718,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -22526,7 +34765,7 @@ + target = <&sound>; + frag3: __overlay__ { + compatible = "justboom,justboom-both"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; @@ -22537,7 +34776,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts b/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts new file mode 100644 -index 000000000000..d00515dca419 +index 000000000000..901a6aaba4bc --- /dev/null +++ b/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts @@ -0,0 +1,46 @@ @@ -22549,7 +34788,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -22578,7 +34817,7 @@ + target = <&sound>; + frag2: __overlay__ { + compatible = "justboom,justboom-dac"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; @@ -22589,7 +34828,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts b/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts new file mode 100644 -index 000000000000..e73336029c54 +index 000000000000..c4c968200a4c --- /dev/null +++ b/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts @@ -0,0 +1,41 @@ @@ -22601,7 +34840,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -22629,7 +34868,7 @@ + target = <&sound>; + __overlay__ { + compatible = "justboom,justboom-digi"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; @@ -22728,7 +34967,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/max98357a-overlay.dts b/arch/arm/boot/dts/overlays/max98357a-overlay.dts new file mode 100644 -index 000000000000..9e2afb05b7cb +index 000000000000..263d071fe977 --- /dev/null +++ b/arch/arm/boot/dts/overlays/max98357a-overlay.dts @@ -0,0 +1,84 @@ @@ -22746,7 +34985,7 @@ + + /* Enable I2S */ + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -22786,7 +35025,7 @@ + simple-audio-card,name = "MAX98357A"; + status = "okay"; + simple-audio-card,cpu { -+ sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + }; + simple-audio-card,codec { + sound-dai = <&max98357a_dac>; @@ -22803,7 +35042,7 @@ + simple-audio-card,name = "MAX98357A"; + status = "okay"; + simple-audio-card,cpu { -+ sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + }; + simple-audio-card,codec { + sound-dai = <&max98357a_nsd>; @@ -23010,7 +35249,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/mbed-dac-overlay.dts b/arch/arm/boot/dts/overlays/mbed-dac-overlay.dts new file mode 100644 -index 000000000000..840dd9b31db4 +index 000000000000..e3f56608c643 --- /dev/null +++ b/arch/arm/boot/dts/overlays/mbed-dac-overlay.dts @@ -0,0 +1,64 @@ @@ -23022,7 +35261,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -23048,7 +35287,7 @@ + target = <&sound>; + __overlay__ { + compatible = "simple-audio-card"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + + simple-audio-card,name = "mbed-DAC"; @@ -23068,7 +35307,7 @@ + simple-audio-card,format = "i2s"; + + simple-audio-card,cpu { -+ sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + }; + + sound_master: simple-audio-card,codec { @@ -23080,10 +35319,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts new file mode 100644 -index 000000000000..c546d8ba7e6d +index 000000000000..d77690b17711 --- /dev/null +++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts -@@ -0,0 +1,69 @@ +@@ -0,0 +1,103 @@ +// Definitions for MCP23017 Gpio Extender from Microchip Semiconductor + +/dts-v1/; @@ -23093,7 +35332,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2c1>; ++ target = <&i2cbus>; + __overlay__ { + status = "okay"; + }; @@ -23110,13 +35349,33 @@ + }; + + fragment@2 { -+ target = <&i2c1>; ++ target = <&mcp23017>; ++ __dormant__ { ++ compatible = "microchip,mcp23008"; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&mcp23017>; ++ mcp23017_irq: __overlay__ { ++ #interrupt-cells=<2>; ++ interrupt-parent = <&gpio>; ++ interrupts = <4 2>; ++ interrupt-controller; ++ microchip,irq-mirror; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&i2cbus>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + + mcp23017: mcp@20 { + compatible = "microchip,mcp23017"; ++ pinctrl-name = "default"; ++ pinctrl-0 = <&mcp23017_pins>; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; @@ -23126,30 +35385,44 @@ + }; + }; + -+ fragment@3 { -+ target = <&mcp23017>; -+ __dormant__ { -+ compatible = "microchip,mcp23008"; ++ frag100: fragment@100 { ++ target = <&i2c1>; ++ i2cbus: __overlay__ { ++ status = "okay"; + }; + }; + -+ fragment@4 { -+ target = <&mcp23017>; -+ mcp23017_irq: __overlay__ { -+ #interrupt-cells=<2>; -+ interrupt-parent = <&gpio>; -+ interrupts = <4 2>; -+ interrupt-controller; -+ microchip,irq-mirror; -+ }; ++ fragment@101 { ++ target = <&i2c0if>; ++ __dormant__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@102 { ++ target = <&i2c0mux>; ++ __dormant__ { ++ status = "okay"; ++ }; + }; + + __overrides__ { + gpiopin = <&mcp23017_pins>,"brcm,pins:0", + <&mcp23017_irq>,"interrupts:0"; + addr = <&mcp23017>,"reg:0", <&mcp23017_pins>,"reg:0"; -+ mcp23008 = <0>,"=3"; -+ noints = <0>,"!1!4"; ++ mcp23008 = <0>,"=2"; ++ noints = <0>,"!1!3"; ++ i2c0 = <&frag100>, "target:0=",<&i2c0>; ++ i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, ++ <0>,"+101+102"; ++ i2c3 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c3"; ++ i2c4 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c4"; ++ i2c5 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c5"; ++ i2c6 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c6"; + }; +}; + @@ -25037,10 +37310,10 @@ + diff --git a/arch/arm/boot/dts/overlays/media-center-overlay.dts b/arch/arm/boot/dts/overlays/media-center-overlay.dts new file mode 100644 -index 000000000000..1b56963f4f16 +index 000000000000..4bc2eaa1f215 --- /dev/null +++ b/arch/arm/boot/dts/overlays/media-center-overlay.dts -@@ -0,0 +1,134 @@ +@@ -0,0 +1,86 @@ +/* + * Device Tree overlay for Media Center HAT by Pi Supply + * @@ -25053,21 +37326,20 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&spi0>; ++ target = <&spidev0>; + __overlay__ { -+ status = "okay"; -+ -+ spidev@0{ -+ status = "disabled"; -+ }; -+ -+ spidev@1{ -+ status = "disabled"; -+ }; ++ status = "disabled"; + }; + }; + + fragment@1 { ++ target = <&spidev1>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@2 { + target = <&gpio>; + __overlay__ { + rpi_display_pins: rpi_display_pins { @@ -25078,12 +37350,13 @@ + }; + }; + -+ fragment@2 { ++ fragment@3 { + target = <&spi0>; + __overlay__ { + /* needed to avoid dtc warning */ + #address-cells = <1>; + #size-cells = <0>; ++ status = "okay"; + + rpidisplay: rpi-display@0{ + compatible = "ilitek,ili9341"; @@ -25116,71 +37389,23 @@ + }; + }; + -+ 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"; ++ 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"; -+ -+ 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 --git a/arch/arm/boot/dts/overlays/merus-amp-overlay.dts b/arch/arm/boot/dts/overlays/merus-amp-overlay.dts new file mode 100644 -index 000000000000..4501fbdc253d +index 000000000000..96159a48d33f --- /dev/null +++ b/arch/arm/boot/dts/overlays/merus-amp-overlay.dts -@@ -0,0 +1,60 @@ +@@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Definitions for Infineon Merus-Amp +/dts-v1/; @@ -25188,12 +37413,11 @@ +#include <dt-bindings/pinctrl/bcm2835.h> +#include <dt-bindings/gpio/gpio.h> + -+ +/ { + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -25203,9 +37427,9 @@ + target = <&gpio>; + __overlay__ { + merus_amp_pins: merus_amp_pins { -+ brcm,pins = <23>; -+ brcm,function = <0>; /* in */ -+ brcm,pull = <2>; /* up */ ++ brcm,pins = <23 8>; ++ brcm,function = <0 0>; ++ brcm,pull = <2 0>; + }; + }; + }; @@ -25236,7 +37460,7 @@ + target = <&sound>; + __overlay__ { + compatible = "merus,merus-amp"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; @@ -25283,6 +37507,47 @@ + }; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/midi-uart0-pi5-overlay.dts b/arch/arm/boot/dts/overlays/midi-uart0-pi5-overlay.dts +new file mode 100644 +index 000000000000..6cd1f3ed2d8d +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/midi-uart0-pi5-overlay.dts +@@ -0,0 +1,35 @@ ++/dts-v1/; ++/plugin/; ++ ++#include <dt-bindings/clock/rp1.h> ++ ++/* ++ * Fake a higher clock rate to get a larger divisor, and thereby a lower ++ * baudrate. The real clock is 100MHz, which we scale so that requesting ++ * 38.4kHz results in an actual 31.25kHz. ++ * ++ * 100000000*38400/31250 = 122880000 ++ */ ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ midi_clk: midi_clk0 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "uart0_pclk"; ++ clock-frequency = <122880000>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&uart0>; ++ __overlay__ { ++ clocks = <&midi_clk &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ }; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/midi-uart1-overlay.dts b/arch/arm/boot/dts/overlays/midi-uart1-overlay.dts new file mode 100644 index 000000000000..e0bc410acbff @@ -25332,9 +37597,50 @@ + }; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/midi-uart1-pi5-overlay.dts b/arch/arm/boot/dts/overlays/midi-uart1-pi5-overlay.dts +new file mode 100644 +index 000000000000..18f526865eed +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/midi-uart1-pi5-overlay.dts +@@ -0,0 +1,35 @@ ++/dts-v1/; ++/plugin/; ++ ++#include <dt-bindings/clock/rp1.h> ++ ++/* ++ * Fake a higher clock rate to get a larger divisor, and thereby a lower ++ * baudrate. The real clock is 100MHz, which we scale so that requesting ++ * 38.4kHz results in an actual 31.25kHz. ++ * ++ * 100000000*38400/31250 = 122880000 ++ */ ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ midi_clk: midi_clk1 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "uart1_pclk"; ++ clock-frequency = <122880000>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&uart1>; ++ __overlay__ { ++ clocks = <&midi_clk &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ }; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/midi-uart2-overlay.dts b/arch/arm/boot/dts/overlays/midi-uart2-overlay.dts new file mode 100644 -index 000000000000..66f3092e9a74 +index 000000000000..5c6985f41ea2 --- /dev/null +++ b/arch/arm/boot/dts/overlays/midi-uart2-overlay.dts @@ -0,0 +1,37 @@ @@ -25352,7 +37658,7 @@ + */ + +/{ -+ compatible = "brcm,bcm2835"; ++ compatible = "brcm,bcm2711"; + + fragment@0 { + target-path = "/"; @@ -25375,9 +37681,50 @@ + }; +}; + +diff --git a/arch/arm/boot/dts/overlays/midi-uart2-pi5-overlay.dts b/arch/arm/boot/dts/overlays/midi-uart2-pi5-overlay.dts +new file mode 100644 +index 000000000000..5e1e0c6fd7a9 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/midi-uart2-pi5-overlay.dts +@@ -0,0 +1,35 @@ ++/dts-v1/; ++/plugin/; ++ ++#include <dt-bindings/clock/rp1.h> ++ ++/* ++ * Fake a higher clock rate to get a larger divisor, and thereby a lower ++ * baudrate. The real clock is 100MHz, which we scale so that requesting ++ * 38.4kHz results in an actual 31.25kHz. ++ * ++ * 100000000*38400/31250 = 122880000 ++ */ ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ midi_clk: midi_clk2 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "uart2_pclk"; ++ clock-frequency = <122880000>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&uart2>; ++ __overlay__ { ++ clocks = <&midi_clk &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ }; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/midi-uart3-overlay.dts b/arch/arm/boot/dts/overlays/midi-uart3-overlay.dts new file mode 100644 -index 000000000000..55c6cb94f963 +index 000000000000..052027db0564 --- /dev/null +++ b/arch/arm/boot/dts/overlays/midi-uart3-overlay.dts @@ -0,0 +1,38 @@ @@ -25395,7 +37742,7 @@ + */ + +/{ -+ compatible = "brcm,bcm2835"; ++ compatible = "brcm,bcm2711"; + + fragment@0 { + target-path = "/"; @@ -25419,9 +37766,50 @@ +}; + + +diff --git a/arch/arm/boot/dts/overlays/midi-uart3-pi5-overlay.dts b/arch/arm/boot/dts/overlays/midi-uart3-pi5-overlay.dts +new file mode 100644 +index 000000000000..705a2793d00c +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/midi-uart3-pi5-overlay.dts +@@ -0,0 +1,35 @@ ++/dts-v1/; ++/plugin/; ++ ++#include <dt-bindings/clock/rp1.h> ++ ++/* ++ * Fake a higher clock rate to get a larger divisor, and thereby a lower ++ * baudrate. The real clock is 100MHz, which we scale so that requesting ++ * 38.4kHz results in an actual 31.25kHz. ++ * ++ * 100000000*38400/31250 = 122880000 ++ */ ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ midi_clk: midi_clk3 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "uart3_pclk"; ++ clock-frequency = <122880000>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&uart3>; ++ __overlay__ { ++ clocks = <&midi_clk &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ }; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/midi-uart4-overlay.dts b/arch/arm/boot/dts/overlays/midi-uart4-overlay.dts new file mode 100644 -index 000000000000..5819df1a6b2e +index 000000000000..5f09a7ccd675 --- /dev/null +++ b/arch/arm/boot/dts/overlays/midi-uart4-overlay.dts @@ -0,0 +1,38 @@ @@ -25439,7 +37827,7 @@ + */ + +/{ -+ compatible = "brcm,bcm2835"; ++ compatible = "brcm,bcm2711"; + + fragment@0 { + target-path = "/"; @@ -25463,9 +37851,50 @@ +}; + + +diff --git a/arch/arm/boot/dts/overlays/midi-uart4-pi5-overlay.dts b/arch/arm/boot/dts/overlays/midi-uart4-pi5-overlay.dts +new file mode 100644 +index 000000000000..0d2f823ed7dd +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/midi-uart4-pi5-overlay.dts +@@ -0,0 +1,35 @@ ++/dts-v1/; ++/plugin/; ++ ++#include <dt-bindings/clock/rp1.h> ++ ++/* ++ * Fake a higher clock rate to get a larger divisor, and thereby a lower ++ * baudrate. The real clock is 100MHz, which we scale so that requesting ++ * 38.4kHz results in an actual 31.25kHz. ++ * ++ * 100000000*38400/31250 = 122880000 ++ */ ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ midi_clk: midi_clk4 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "uart4_pclk"; ++ clock-frequency = <122880000>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&uart4>; ++ __overlay__ { ++ clocks = <&midi_clk &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ }; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/midi-uart5-overlay.dts b/arch/arm/boot/dts/overlays/midi-uart5-overlay.dts new file mode 100644 -index 000000000000..a1d37f7103ff +index 000000000000..74551ec2a672 --- /dev/null +++ b/arch/arm/boot/dts/overlays/midi-uart5-overlay.dts @@ -0,0 +1,38 @@ @@ -25483,7 +37912,7 @@ + */ + +/{ -+ compatible = "brcm,bcm2835"; ++ compatible = "brcm,bcm2711"; + + fragment@0 { + target-path = "/"; @@ -25509,7 +37938,7 @@ + diff --git a/arch/arm/boot/dts/overlays/minipitft13-overlay.dts b/arch/arm/boot/dts/overlays/minipitft13-overlay.dts new file mode 100644 -index 000000000000..b1a0a2a41f72 +index 000000000000..5e0941e8ba54 --- /dev/null +++ b/arch/arm/boot/dts/overlays/minipitft13-overlay.dts @@ -0,0 +1,70 @@ @@ -25525,21 +37954,20 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&spi0>; ++ target = <&spidev0>; + __overlay__ { -+ status = "okay"; -+ -+ spidev@0{ -+ status = "disabled"; -+ }; -+ -+ spidev@1{ -+ status = "disabled"; -+ }; ++ status = "disabled"; + }; + }; + + fragment@1 { ++ target = <&spidev1>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@2 { + target = <&gpio>; + __overlay__ { + pitft_pins: pitft_pins { @@ -25550,12 +37978,13 @@ + }; + }; + -+ fragment@2 { ++ fragment@3 { + target = <&spi0>; + __overlay__ { + /* needed to avoid dtc warning */ + #address-cells = <1>; + #size-cells = <0>; ++ status = "okay"; + + pitft: pitft@0 { + compatible = "fbtft,minipitft13"; @@ -25585,10 +38014,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/miniuart-bt-overlay.dts b/arch/arm/boot/dts/overlays/miniuart-bt-overlay.dts new file mode 100644 -index 000000000000..da49f14a0940 +index 000000000000..757e5cd3c4e8 --- /dev/null +++ b/arch/arm/boot/dts/overlays/miniuart-bt-overlay.dts -@@ -0,0 +1,93 @@ +@@ -0,0 +1,83 @@ +/dts-v1/; +/plugin/; + @@ -25631,7 +38060,7 @@ + target = <&uart1>; + __overlay__ { + pinctrl-names = "default"; -+ pinctrl-0 = <&uart1_pins &bt_pins &fake_bt_cts>; ++ pinctrl-0 = <&uart1_pins>; + status = "okay"; + }; + }; @@ -25646,35 +38075,25 @@ + }; + + fragment@4 { -+ target = <&uart1_pins>; ++ target = <&uart1>; + __overlay__ { -+ brcm,pins = <32 33>; -+ brcm,function = <2>; /* alt5=UART1 */ -+ brcm,pull = <0 2>; ++ pinctrl-0 = <&uart1_bt_pins>; + }; + }; + + 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"; ++ bluetooth = "/soc/serial@7e215040/bluetooth"; + }; + }; + -+ fragment@7 { ++ fragment@6 { + target = <&minibt>; + minibt_frag: __overlay__ { ++ status = "okay"; + }; + }; + @@ -25682,6 +38101,187 @@ + krnbt = <&minibt_frag>,"status"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/mipi-dbi-spi-overlay.dts b/arch/arm/boot/dts/overlays/mipi-dbi-spi-overlay.dts +new file mode 100644 +index 000000000000..63fb3a5f2388 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/mipi-dbi-spi-overlay.dts +@@ -0,0 +1,175 @@ ++/* ++ * mipi-dbi-spi-overlay.dts ++ */ ++ ++#include <dt-bindings/gpio/gpio.h> ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ spidev_fragment: fragment@0 { ++ target-path = "spi0/spidev@0"; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ panel_fragment: fragment@1 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "okay"; ++ ++ panel: panel@0 { ++ compatible = "panel", "panel-mipi-dbi-spi"; ++ reg = <0>; ++ spi-max-frequency = <32000000>; ++ ++ width-mm = <0>; ++ height-mm = <0>; ++ ++ timing: panel-timing { ++ hactive = <320>; ++ vactive = <240>; ++ hback-porch = <0>; ++ vback-porch = <0>; ++ ++ clock-frequency = <0>; ++ hfront-porch = <0>; ++ hsync-len = <0>; ++ vfront-porch = <0>; ++ vsync-len = <0>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@10 { ++ target = <&panel>; ++ __dormant__ { ++ backlight = <&backlight_gpio>; ++ }; ++ }; ++ ++ fragment@11 { ++ target-path = "/"; ++ __dormant__ { ++ backlight_gpio: backlight_gpio { ++ compatible = "gpio-backlight"; ++ gpios = <&gpio 255 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ }; ++ ++ fragment@20 { ++ target = <&panel>; ++ __dormant__ { ++ backlight = <&backlight_pwm>; ++ }; ++ }; ++ ++ fragment@21 { ++ target-path = "/"; ++ __dormant__ { ++ backlight_pwm: backlight_pwm { ++ compatible = "pwm-backlight"; ++ brightness-levels = <0 6 8 12 16 24 32 40 48 64 96 128 160 192 224 255>; ++ default-brightness-level = <15>; ++ pwms = <&pwm 0 200000 0>; ++ }; ++ }; ++ }; ++ ++ fragment@22 { ++ target = <&pwm>; ++ __dormant__ { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm_pins>; ++ assigned-clock-rates = <1000000>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@23 { ++ target = <&gpio>; ++ __dormant__ { ++ pwm_pins: pwm_pins { ++ brcm,pins = <18>; ++ brcm,function = <2>; /* Alt5 */ ++ }; ++ }; ++ }; ++ ++ fragment@24 { ++ target = <&chosen>; ++ __dormant__ { ++ bootargs = "snd_bcm2835.enable_headphones=0"; ++ }; ++ }; ++ ++ __overrides__ { ++ compatible = <&panel>, "compatible"; ++ ++ spi0-0 = <&panel_fragment>, "target:0=",<&spi0>, ++ <&spidev_fragment>, "target-path=spi0/spidev@0", ++ <&panel>, "reg:0=0"; ++ spi0-1 = <&panel_fragment>, "target:0=",<&spi0>, ++ <&spidev_fragment>, "target-path=spi0/spidev@1", ++ <&panel>, "reg:0=1"; ++ spi1-0 = <&panel_fragment>, "target:0=",<&spi1>, ++ <&spidev_fragment>, "target-path=spi1/spidev@0", ++ <&panel>, "reg:0=0"; ++ spi1-1 = <&panel_fragment>, "target:0=",<&spi1>, ++ <&spidev_fragment>, "target-path=spi1/spidev@1", ++ <&panel>, "reg:0=1"; ++ spi1-2 = <&panel_fragment>, "target:0=",<&spi1>, ++ <&spidev_fragment>, "target-path=spi1/spidev@2", ++ <&panel>, "reg:0=2"; ++ spi2-0 = <&panel_fragment>, "target:0=",<&spi2>, ++ <&spidev_fragment>, "target-path=spi2/spidev@0", ++ <&panel>, "reg:0=0"; ++ spi2-1 = <&panel_fragment>, "target:0=",<&spi2>, ++ <&spidev_fragment>, "target-path=spi2/spidev@1", ++ <&panel>, "reg:0=1"; ++ spi2-2 = <&panel_fragment>, "target:0=",<&spi2>, ++ <&spidev_fragment>, "target-path=spi2/spidev@2", ++ <&panel>, "reg:0=2"; ++ ++ speed = <&panel>, "spi-max-frequency:0"; ++ cpha = <&panel>, "spi-cpha?"; ++ cpol = <&panel>, "spi-cpol?"; ++ ++ write-only = <&panel>, "write-only?"; ++ ++ width = <&timing>, "hactive:0"; ++ height = <&timing>, "vactive:0"; ++ x-offset = <&timing>, "hback-porch:0"; ++ y-offset = <&timing>, "vback-porch:0"; ++ clock-frequency = <&timing>, "clock-frequency:0"; ++ ++ width-mm = <&panel>, "width-mm:0"; ++ height-mm = <&panel>, "height-mm:0"; ++ ++ /* optional gpios */ ++ reset-gpio = <&panel>, "reset-gpios:0=", <&gpio>, ++ <&panel>, "reset-gpios:4", ++ <&panel>, "reset-gpios:8=0"; /* GPIO_ACTIVE_HIGH */ ++ dc-gpio = <&panel>, "dc-gpios:0=", <&gpio>, ++ <&panel>, "dc-gpios:4", ++ <&panel>, "dc-gpios:8=0"; /* GPIO_ACTIVE_HIGH */ ++ ++ backlight-gpio = <0>, "+10+11", ++ <&backlight_gpio>, "gpios:4"; ++ backlight-pwm = <0>, "+20+21+22+23+24"; ++ backlight-pwm-chan = <&backlight_pwm>, "pwms:4"; ++ backlight-pwm-gpio = <&pwm_pins>, "brcm,pins:0"; ++ backlight-pwm-func = <&pwm_pins>, "brcm,function:0"; ++ backlight-def-brightness = <&backlight_pwm>, "default-brightness-level:0"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/mlx90640-overlay.dts b/arch/arm/boot/dts/overlays/mlx90640-overlay.dts new file mode 100644 index 000000000000..a2655ed82585 @@ -25762,44 +38362,9 @@ + overclock_50 = <&frag0>,"brcm,overclock-50:0"; + }; +}; -diff --git a/arch/arm/boot/dts/overlays/mpu6050-overlay.dts b/arch/arm/boot/dts/overlays/mpu6050-overlay.dts -new file mode 100644 -index 000000000000..1b4c06535687 ---- /dev/null -+++ b/arch/arm/boot/dts/overlays/mpu6050-overlay.dts -@@ -0,0 +1,29 @@ -+// 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 --git a/arch/arm/boot/dts/overlays/mz61581-overlay.dts b/arch/arm/boot/dts/overlays/mz61581-overlay.dts new file mode 100644 -index 000000000000..6e00e8b2ddf2 +index 000000000000..101ad21d8093 --- /dev/null +++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts @@ -0,0 +1,117 @@ @@ -25904,7 +38469,7 @@ + spi-max-frequency = <2000000>; + interrupts = <4 2>; /* high-to-low edge triggered */ + interrupt-parent = <&gpio>; -+ pendown-gpio = <&gpio 4 0>; ++ pendown-gpio = <&gpio 4 1>; + + ti,x-plate-ohms = /bits/ 16 <60>; + ti,pressure-max = /bits/ 16 <255>; @@ -25920,17 +38485,19 @@ + xohms = <&mz61581_ts>,"ti,x-plate-ohms;0"; + }; +}; -diff --git a/arch/arm/boot/dts/overlays/ov5647-overlay.dts b/arch/arm/boot/dts/overlays/ov5647-overlay.dts +diff --git a/arch/arm/boot/dts/overlays/ov2311-overlay.dts b/arch/arm/boot/dts/overlays/ov2311-overlay.dts new file mode 100644 -index 000000000000..a1221024d334 +index 000000000000..f51c772428ca --- /dev/null -+++ b/arch/arm/boot/dts/overlays/ov5647-overlay.dts -@@ -0,0 +1,99 @@ ++++ b/arch/arm/boot/dts/overlays/ov2311-overlay.dts +@@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-only -+// Definitions for OV5647 camera module on VC I2C bus ++// Definitions for OV2311 camera module on VC I2C bus +/dts-v1/; +/plugin/; + ++#include <dt-bindings/gpio/gpio.h> ++ +/{ + compatible = "brcm,bcm2835"; + @@ -25941,30 +38508,126 @@ + #size-cells = <0>; + status = "okay"; + -+ ov5647: ov5647@36 { -+ compatible = "ovti,ov5647"; -+ reg = <0x36>; -+ status = "okay"; ++ #include "ov2311.dtsi" ++ }; ++ }; + -+ clocks = <&cam1_clk>; ++ csi_frag: fragment@1 { ++ target = <&csi1>; ++ csi: __overlay__ { ++ status = "okay"; ++ brcm,media-controller; ++ ++ port { ++ csi_ep: endpoint { ++ remote-endpoint = <&cam_endpoint>; ++ data-lanes = <1 2>; ++ }; ++ }; ++ }; ++ }; + -+ avdd-supply = <&cam1_reg>; -+ dovdd-supply = <&cam_dummy_reg>; -+ dvdd-supply = <&cam_dummy_reg>; ++ fragment@2 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; + -+ rotation = <0>; -+ orientation = <2>; ++ fragment@3 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; + -+ port { -+ ov5647_0: endpoint { -+ remote-endpoint = <&csi1_ep>; -+ clock-lanes = <0>; -+ data-lanes = <1 2>; -+ clock-noncontinuous; -+ link-frequencies = -+ /bits/ 64 <297000000>; -+ }; -+ }; ++ clk_frag: fragment@4{ ++ target = <&cam1_clk>; ++ __overlay__ { ++ status = "okay"; ++ clock-frequency = <24000000>; ++ }; ++ }; ++ ++ __overrides__ { ++ rotation = <&cam_node>,"rotation:0"; ++ orientation = <&cam_node>,"orientation:0"; ++ media-controller = <&csi>,"brcm,media-controller?"; ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&csi_frag>, "target:0=",<&csi0>, ++ <&clk_frag>, "target:0=",<&cam0_clk>, ++ <&cam_node>, "clocks:0=",<&cam0_clk>, ++ <&cam_node>, "avdd-supply:0=",<&cam0_reg>; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; +diff --git a/arch/arm/boot/dts/overlays/ov2311.dtsi b/arch/arm/boot/dts/overlays/ov2311.dtsi +new file mode 100644 +index 000000000000..a1714d6941c3 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/ov2311.dtsi +@@ -0,0 +1,26 @@ ++// Fragment that configures an ov2311 ++ ++cam_node: ov2311@60 { ++ compatible = "ovti,ov2311"; ++ reg = <0x60>; ++ status = "disabled"; ++ ++ clocks = <&cam1_clk>; ++ clock-names = "xvclk"; ++ ++ avdd-supply = <&cam1_reg>; ++ dovdd-supply = <&cam_dummy_reg>; ++ dvdd-supply = <&cam_dummy_reg>; ++ ++ rotation = <0>; ++ orientation = <2>; ++ ++ port { ++ cam_endpoint: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ link-frequencies = ++ /bits/ 64 <400000000>; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/ov5647-overlay.dts b/arch/arm/boot/dts/overlays/ov5647-overlay.dts +new file mode 100644 +index 000000000000..37fe46412439 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/ov5647-overlay.dts +@@ -0,0 +1,93 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Definitions for OV5647 camera module on VC I2C bus ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2835"; ++ ++ i2c_frag: fragment@0 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ #include "ov5647.dtsi" ++ ++ vcm_node: ad5398@c { ++ compatible = "adi,ad5398"; ++ reg = <0x0c>; ++ status = "disabled"; ++ VANA-supply = <&cam1_reg>; + }; + }; + }; @@ -25976,8 +38639,8 @@ + brcm,media-controller; + + port { -+ csi1_ep: endpoint { -+ remote-endpoint = <&ov5647_0>; ++ csi_ep: endpoint { ++ remote-endpoint = <&cam_endpoint>; + data-lanes = <1 2>; + }; + }; @@ -26014,23 +38677,202 @@ + }; + + __overrides__ { -+ rotation = <&ov5647>,"rotation:0"; -+ orientation = <&ov5647>,"orientation:0"; ++ rotation = <&cam_node>,"rotation:0"; ++ orientation = <&cam_node>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; -+ cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <®_frag>, "target:0=",<&cam0_reg>, + <&clk_frag>, "target:0=",<&cam0_clk>, -+ <&ov5647>, "clocks:0=",<&cam0_clk>, -+ <&ov5647>, "avdd-supply:0=",<&cam0_reg>; ++ <&cam_node>, "clocks:0=",<&cam0_clk>, ++ <&cam_node>, "avdd-supply:0=",<&cam0_reg>, ++ <&vcm_node>, "VANA-supply:0=",<&cam0_reg>; ++ vcm = <&vcm_node>, "status=okay", ++ <&cam_node>,"lens-focus:0=", <&vcm_node>; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; +diff --git a/arch/arm/boot/dts/overlays/ov5647.dtsi b/arch/arm/boot/dts/overlays/ov5647.dtsi +new file mode 100644 +index 000000000000..6455a191a394 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/ov5647.dtsi +@@ -0,0 +1,25 @@ ++cam_node: ov5647@36 { ++ compatible = "ovti,ov5647"; ++ reg = <0x36>; ++ status = "disabled"; ++ ++ clocks = <&cam1_clk>; ++ ++ avdd-supply = <&cam1_reg>; ++ dovdd-supply = <&cam_dummy_reg>; ++ dvdd-supply = <&cam_dummy_reg>; ++ ++ rotation = <0>; ++ orientation = <2>; ++ ++ port { ++ cam_endpoint: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = ++ /bits/ 64 <297000000>; ++ }; ++ }; ++}; ++ +diff --git a/arch/arm/boot/dts/overlays/ov64a40-overlay.dts b/arch/arm/boot/dts/overlays/ov64a40-overlay.dts +new file mode 100644 +index 000000000000..b6f8586d6b24 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/ov64a40-overlay.dts +@@ -0,0 +1,91 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Definitions for OV64A40 camera module on VC I2C bus ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2835"; ++ ++ i2c_frag: fragment@0 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ #include "ov64a40.dtsi" ++ }; ++ }; ++ ++ csi_frag: fragment@1 { ++ target = <&csi1>; ++ csi: __overlay__ { ++ status = "okay"; ++ brcm,media-controller; ++ ++ port{ ++ csi_ep: endpoint{ ++ remote-endpoint = <&cam_endpoint>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ clk_frag: fragment@3 { ++ target = <&cam1_clk>; ++ __overlay__ { ++ clock-frequency = <24000000>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@5 { ++ target = <&cam_node>; ++ __overlay__ { ++ lens-focus = <&vcm_node>; ++ }; ++ }; ++ ++ __overrides__ { ++ rotation = <&cam_node>,"rotation:0"; ++ orientation = <&cam_node>,"orientation:0"; ++ media-controller = <&csi>,"brcm,media-controller?"; ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&csi_frag>, "target:0=",<&csi0>, ++ <&clk_frag>, "target:0=",<&cam0_clk>, ++ <&cam_node>, "clocks:0=",<&cam0_clk>, ++ <&cam_node>, "avdd-supply:0=",<&cam0_reg>, ++ <&vcm_node>, "vdd-supply:0=",<&cam0_reg>; ++ vcm = <&vcm_node>, "status", ++ <0>, "=5"; ++ link-frequency = <&cam_endpoint>,"link-frequencies#0"; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; ++ ++&vcm_node { ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/overlays/ov64a40.dtsi b/arch/arm/boot/dts/overlays/ov64a40.dtsi +new file mode 100644 +index 000000000000..471b383fa151 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/ov64a40.dtsi +@@ -0,0 +1,34 @@ ++// Fragment that configures an OV64A40 ++ ++cam_node: ov64a40@36 { ++ compatible = "ovti,ov64a40"; ++ reg = <0x36>; ++ status = "disabled"; ++ ++ clocks = <&cam1_clk>; ++ clock-names = "xclk"; ++ ++ avdd-supply = <&cam1_reg>; /* 2.8v */ ++ dovdd-supply = <&cam_dummy_reg>;/* 1.8v */ ++ dvdd-supply = <&cam_dummy_reg>; /* 1.1v */ ++ ++ rotation = <180>; ++ orientation = <2>; ++ ++ port { ++ cam_endpoint: endpoint { ++ bus-type = <4>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ link-frequencies = ++ /bits/ 64 <456000000>; ++ }; + }; +}; ++ ++vcm_node: bu64754@76 { ++ compatible = "rohm,bu64754"; ++ reg = <0x76>; ++ status = "disabled"; ++ vdd-supply = <&cam1_reg>; ++}; diff --git a/arch/arm/boot/dts/overlays/ov7251-overlay.dts b/arch/arm/boot/dts/overlays/ov7251-overlay.dts new file mode 100644 -index 000000000000..0e44be8a4468 +index 000000000000..9975febc8995 --- /dev/null +++ b/arch/arm/boot/dts/overlays/ov7251-overlay.dts -@@ -0,0 +1,94 @@ +@@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Definitions for OV7251 camera module on VC I2C bus +/dts-v1/; @@ -26048,33 +38890,7 @@ + #size-cells = <0>; + status = "okay"; + -+ ov7251: ov7251@60 { -+ compatible = "ovti,ov7251"; -+ reg = <0x60>; -+ status = "okay"; -+ -+ clocks = <&cam1_clk>; -+ clock-names = "xclk"; -+ clock-frequency = <24000000>; -+ -+ vdddo-supply = <&cam_dummy_reg>; -+ vdda-supply = <&cam1_reg>; -+ vddd-supply = <&cam_dummy_reg>; -+ -+ rotation = <0>; -+ orientation = <2>; -+ -+ port { -+ ov7251_0: endpoint { -+ remote-endpoint = <&csi1_ep>; -+ clock-lanes = <0>; -+ data-lanes = <1>; -+ clock-noncontinuous; -+ link-frequencies = -+ /bits/ 64 <456000000>; -+ }; -+ }; -+ }; ++ #include "ov7251.dtsi" + }; + }; + @@ -26082,10 +38898,11 @@ + target = <&csi1>; + csi: __overlay__ { + status = "okay"; ++ brcm,media-controller; + + port { -+ csi1_ep: endpoint { -+ remote-endpoint = <&ov7251_0>; ++ csi_ep: endpoint { ++ remote-endpoint = <&cam_endpoint>; + data-lanes = <1>; + }; + }; @@ -26115,22 +38932,64 @@ + }; + + __overrides__ { -+ rotation = <&ov7251>,"rotation:0"; -+ orientation = <&ov7251>,"orientation:0"; ++ rotation = <&cam_node>,"rotation:0"; ++ orientation = <&cam_node>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; -+ cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, -+ <&ov7251>, "clocks:0=",<&cam0_clk>, -+ <&ov7251>, "vdda-supply:0=",<&cam0_reg>; ++ <&cam_node>, "clocks:0=",<&cam0_clk>, ++ <&cam_node>, "vdda-supply:0=",<&cam0_reg>; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; +diff --git a/arch/arm/boot/dts/overlays/ov7251.dtsi b/arch/arm/boot/dts/overlays/ov7251.dtsi +new file mode 100644 +index 000000000000..561fed1db837 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/ov7251.dtsi +@@ -0,0 +1,28 @@ ++// Fragment that configures an ov7251 ++ ++cam_node: ov7251@60 { ++ compatible = "ovti,ov7251"; ++ reg = <0x60>; ++ status = "disabled"; ++ ++ clocks = <&cam1_clk>; ++ clock-names = "xclk"; ++ clock-frequency = <24000000>; ++ ++ vdddo-supply = <&cam_dummy_reg>; ++ vdda-supply = <&cam1_reg>; ++ vddd-supply = <&cam_dummy_reg>; ++ ++ rotation = <0>; ++ orientation = <2>; ++ ++ port { ++ cam_endpoint: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1>; ++ clock-noncontinuous; ++ link-frequencies = ++ /bits/ 64 <240000000>; ++ }; + }; +}; diff --git a/arch/arm/boot/dts/overlays/ov9281-overlay.dts b/arch/arm/boot/dts/overlays/ov9281-overlay.dts new file mode 100644 -index 000000000000..8c08a3a1077c +index 000000000000..ec95b7a8b2f1 --- /dev/null +++ b/arch/arm/boot/dts/overlays/ov9281-overlay.dts -@@ -0,0 +1,95 @@ +@@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Definitions for OV9281 camera module on VC I2C bus +/dts-v1/; @@ -26148,32 +39007,7 @@ + #size-cells = <0>; + status = "okay"; + -+ ov9281: ov9281@60 { -+ compatible = "ovti,ov9281"; -+ reg = <0x60>; -+ status = "okay"; -+ -+ clocks = <&cam1_clk>; -+ clock-names = "xvclk"; -+ -+ avdd-supply = <&cam1_reg>; -+ dovdd-supply = <&cam_dummy_reg>; -+ dvdd-supply = <&cam_dummy_reg>; -+ -+ rotation = <0>; -+ orientation = <2>; -+ -+ port { -+ ov9281_0: endpoint { -+ remote-endpoint = <&csi1_ep>; -+ clock-lanes = <0>; -+ data-lanes = <1 2>; -+ clock-noncontinuous; -+ link-frequencies = -+ /bits/ 64 <400000000>; -+ }; -+ }; -+ }; ++ #include "ov9281.dtsi" + }; + }; + @@ -26184,8 +39018,8 @@ + brcm,media-controller; + + port { -+ csi1_ep: endpoint { -+ remote-endpoint = <&ov9281_0>; ++ csi_ep: endpoint { ++ remote-endpoint = <&cam_endpoint>; + data-lanes = <1 2>; + clock-noncontinuous; + }; @@ -26216,47 +39050,164 @@ + }; + + __overrides__ { -+ rotation = <&ov9281>,"rotation:0"; -+ orientation = <&ov9281>,"orientation:0"; ++ rotation = <&cam_node>,"rotation:0"; ++ orientation = <&cam_node>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; -+ cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, -+ <&ov9281>, "clocks:0=",<&cam0_clk>, -+ <&ov9281>, "avdd-supply:0=",<&cam0_reg>; ++ <&cam_node>, "clocks:0=",<&cam0_clk>, ++ <&cam_node>, "avdd-supply:0=",<&cam0_reg>; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; +diff --git a/arch/arm/boot/dts/overlays/ov9281.dtsi b/arch/arm/boot/dts/overlays/ov9281.dtsi +new file mode 100644 +index 000000000000..7df43bc6ef39 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/ov9281.dtsi +@@ -0,0 +1,27 @@ ++// Fragment that configures an ov9281 ++ ++cam_node: ov9281@60 { ++ compatible = "ovti,ov9281"; ++ reg = <0x60>; ++ status = "disabled"; ++ ++ clocks = <&cam1_clk>; ++ clock-names = "xvclk"; ++ ++ avdd-supply = <&cam1_reg>; ++ dovdd-supply = <&cam_dummy_reg>; ++ dvdd-supply = <&cam_dummy_reg>; ++ ++ rotation = <0>; ++ orientation = <2>; ++ ++ port { ++ cam_endpoint: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = ++ /bits/ 64 <400000000>; ++ }; + }; +}; diff --git a/arch/arm/boot/dts/overlays/overlay_map.dts b/arch/arm/boot/dts/overlays/overlay_map.dts new file mode 100644 -index 000000000000..0e01f46d8db0 +index 000000000000..c2643b485bbc --- /dev/null +++ b/arch/arm/boot/dts/overlays/overlay_map.dts -@@ -0,0 +1,166 @@ +@@ -0,0 +1,493 @@ +/dts-v1/; + +/ { ++ audremap { ++ bcm2835; ++ bcm2711; ++ }; ++ ++ balena-fin { ++ bcm2835; ++ bcm2711; ++ }; ++ + bmp085_i2c-sensor { + deprecated = "use i2c-sensor,bmp085"; + }; + ++ cm-swap-i2c0 { ++ bcm2835; ++ bcm2711; ++ }; ++ + cutiepi-panel { + bcm2711; + }; + ++ disable-bt { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "disable-bt-pi5"; ++ }; ++ ++ disable-bt-pi5 { ++ bcm2712; ++ }; ++ ++ disable-emmc2 { ++ bcm2711; ++ }; ++ ++ disable-wifi { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "disable-wifi-pi5"; ++ }; ++ ++ disable-wifi-pi5 { ++ bcm2712; ++ }; ++ ++ hifiberry-dac8x { ++ bcm2712; ++ }; ++ + highperi { + bcm2711; + }; + ++ i2c0 { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "i2c0-pi5"; ++ }; ++ + i2c0-bcm2708 { + deprecated = "use i2c0"; + }; + ++ i2c0-pi5 { ++ bcm2712; ++ }; ++ ++ i2c1 { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "i2c1-pi5"; ++ }; ++ + i2c1-bcm2708 { + deprecated = "use i2c1"; + }; + ++ i2c1-pi5 { ++ bcm2712; ++ }; ++ ++ i2c2 { ++ bcm2712 = "i2c2-pi5"; ++ }; ++ ++ i2c2-pi5 { ++ bcm2712; ++ }; ++ + i2c3 { + bcm2711; ++ bcm2712 = "i2c3-pi5"; ++ }; ++ ++ i2c3-pi5 { ++ bcm2712; + }; + + i2c4 { @@ -26271,12 +39222,87 @@ + bcm2711; + }; + ++ i2s-gpio28-31 { ++ bcm2835; ++ bcm2711; ++ }; ++ + lirc-rpi { + deprecated = "use gpio-ir"; + }; + ++ midi-uart0 { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "midi-uart0-pi5"; ++ }; ++ ++ midi-uart0-pi5 { ++ bcm2712; ++ }; ++ ++ midi-uart1 { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "midi-uart1-pi5"; ++ }; ++ ++ midi-uart1-pi5 { ++ bcm2712; ++ }; ++ ++ midi-uart2 { ++ bcm2711; ++ bcm2712 = "midi-uart2-pi5"; ++ }; ++ ++ midi-uart2-pi5 { ++ bcm2712; ++ }; ++ ++ midi-uart3 { ++ bcm2711; ++ bcm2712 = "midi-uart3-pi5"; ++ }; ++ ++ midi-uart3-pi5 { ++ bcm2712; ++ }; ++ ++ midi-uart4 { ++ bcm2711; ++ bcm2712 = "midi-uart4-pi5"; ++ }; ++ ++ midi-uart4-pi5 { ++ bcm2712; ++ }; ++ ++ midi-uart5 { ++ bcm2711; ++ }; ++ ++ miniuart-bt { ++ bcm2835; ++ bcm2711; ++ }; ++ ++ mmc { ++ bcm2835; ++ bcm2711; ++ }; ++ ++ mpu6050 { ++ deprecated = "use i2c-sensor,mpu6050"; ++ }; ++ + pcie-32bit-dma { + bcm2711; ++ bcm2712 = "pcie-32bit-dma-pi5"; ++ }; ++ ++ pcie-32bit-dma-pi5 { ++ bcm2712; + }; + + pi3-act-led { @@ -26295,7 +39321,56 @@ + renamed = "miniuart-bt"; + }; + ++ pisound { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "pisound-pi5"; ++ }; ++ ++ pisound-pi5 { ++ bcm2712; ++ }; ++ ++ pwm1 { ++ bcm2711; ++ }; ++ ++ ramoops { ++ bcm2835; ++ bcm2711 = "ramoops-pi4"; ++ }; ++ ++ ramoops-pi4 { ++ bcm2711; ++ }; ++ ++ rpi-cirrus-wm5102 { ++ renamed = "cirrus-wm5102"; ++ }; ++ ++ rpi-dac { ++ renamed = "i2s-dac"; ++ }; ++ ++ rpi-display { ++ renamed = "watterott-display"; ++ }; ++ ++ rpi-proto { ++ renamed = "proto-codec"; ++ }; ++ + rpivid-v4l2 { ++ deprecated = "no longer necessary"; ++ }; ++ ++ sdhost { ++ bcm2835; ++ bcm2711; ++ }; ++ ++ sdio { ++ bcm2835; + bcm2711; + }; + @@ -26303,10 +39378,29 @@ + deprecated = "use sdio,bus_width=1,gpios_22_25"; + }; + ++ sdio-pi5 { ++ bcm2712; ++ }; ++ + sdtweak { + deprecated = "use 'dtparam=sd_poll_once' etc."; + }; + ++ smi { ++ bcm2835; ++ bcm2711; ++ }; ++ ++ smi-dev { ++ bcm2835; ++ bcm2711; ++ }; ++ ++ smi-nand { ++ bcm2835; ++ bcm2711; ++ }; ++ + spi0-cs { + renamed = "spi0-2cs"; + }; @@ -26315,12 +39409,42 @@ + deprecated = "no longer necessary"; + }; + ++ spi2-1cs { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "spi2-1cs-pi5"; ++ }; ++ ++ spi2-1cs-pi5 { ++ bcm2712; ++ }; ++ ++ spi2-2cs { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "spi2-2cs-pi5"; ++ }; ++ ++ spi2-2cs-pi5 { ++ bcm2712; ++ }; ++ + spi3-1cs { + bcm2711; ++ bcm2712 = "spi3-1cs-pi5"; ++ }; ++ ++ spi3-1cs-pi5 { ++ bcm2712; + }; + + spi3-2cs { + bcm2711; ++ bcm2712 = "spi3-2cs-pi5"; ++ }; ++ ++ spi3-2cs-pi5 { ++ bcm2712; + }; + + spi4-1cs { @@ -26333,10 +39457,20 @@ + + spi5-1cs { + bcm2711; ++ bcm2712 = "spi5-1cs-pi5"; ++ }; ++ ++ spi5-1cs-pi5 { ++ bcm2712; + }; + + spi5-2cs { + bcm2711; ++ bcm2712 = "spi5-2cs-pi5"; ++ }; ++ ++ spi5-2cs-pi5 { ++ bcm2712; + }; + + spi6-1cs { @@ -26347,16 +39481,51 @@ + bcm2711; + }; + ++ uart0 { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "uart0-pi5"; ++ }; ++ ++ uart0-pi5 { ++ bcm2712; ++ }; ++ ++ uart1 { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "uart1-pi5"; ++ }; ++ ++ uart1-pi5 { ++ bcm2712; ++ }; ++ + uart2 { + bcm2711; ++ bcm2712 = "uart2-pi5"; ++ }; ++ ++ uart2-pi5 { ++ bcm2712; + }; + + uart3 { + bcm2711; ++ bcm2712 = "uart3-pi5"; ++ }; ++ ++ uart3-pi5 { ++ bcm2712; + }; + + uart4 { + bcm2711; ++ bcm2712 = "uart4-pi5"; ++ }; ++ ++ uart4-pi5 { ++ bcm2712; + }; + + uart5 { @@ -26379,10 +39548,12 @@ + vc4-fkms-v3d { + bcm2835; + bcm2711 = "vc4-fkms-v3d-pi4"; ++ bcm2712 = "vc4-fkms-v3d-pi4"; + }; + + vc4-fkms-v3d-pi4 { + bcm2711; ++ bcm2712; + }; + + vc4-kms-dpi-at056tn53v1 { @@ -26392,18 +39563,49 @@ + vc4-kms-v3d { + bcm2835; + bcm2711 = "vc4-kms-v3d-pi4"; ++ bcm2712 = "vc4-kms-v3d-pi5"; + }; + + vc4-kms-v3d-pi4 { + bcm2711; ++ bcm2712 = "vc4-kms-v3d-pi5"; ++ }; ++ ++ vc4-kms-v3d-pi5 { ++ bcm2712; ++ }; ++ ++ vl805 { ++ bcm2711; ++ }; ++ ++ w1-gpio { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "w1-gpio-pi5"; ++ }; ++ ++ w1-gpio-pi5 { ++ bcm2712; ++ }; ++ ++ w1-gpio-pullup { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "w1-gpio-pullup-pi5"; + }; ++ ++ w1-gpio-pullup-pi5 { ++ bcm2712; ++ }; ++ +}; diff --git a/arch/arm/boot/dts/overlays/papirus-overlay.dts b/arch/arm/boot/dts/overlays/papirus-overlay.dts new file mode 100644 -index 000000000000..7b6bcfd49c86 +index 000000000000..67052b53a59c --- /dev/null +++ b/arch/arm/boot/dts/overlays/papirus-overlay.dts -@@ -0,0 +1,89 @@ +@@ -0,0 +1,84 @@ +/* PaPiRus ePaper Screen by Pi Supply */ + +/dts-v1/; @@ -26420,7 +39622,7 @@ + status = "okay"; + + display_temp: lm75@48 { -+ compatible = "lm75b"; ++ compatible = "national,lm75b"; + reg = <0x48>; + status = "okay"; + #thermal-sensor-cells = <0>; @@ -26429,26 +39631,20 @@ + }; + + fragment@1 { -+ target-path = "/"; ++ target-path = "/thermal-zones"; + __overlay__ { -+ thermal-zones { -+ display { -+ polling-delay-passive = <0>; -+ polling-delay = <0>; -+ thermal-sensors = <&display_temp>; -+ }; ++ display { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&display_temp>; + }; + }; + }; + + fragment@2 { -+ target = <&spi0>; ++ target = <&spidev0>; + __overlay__ { -+ status = "okay"; -+ -+ spidev@0{ -+ status = "disabled"; -+ }; ++ status = "disabled"; + }; + }; + @@ -26468,6 +39664,7 @@ + /* needed to avoid dtc warning */ + #address-cells = <1>; + #size-cells = <0>; ++ status = "okay"; + + repaper: repaper@0{ + compatible = "not_set"; @@ -26495,7 +39692,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/pca953x-overlay.dts b/arch/arm/boot/dts/overlays/pca953x-overlay.dts new file mode 100644 -index 000000000000..8b6ee44665ce +index 000000000000..ab414e92e366 --- /dev/null +++ b/arch/arm/boot/dts/overlays/pca953x-overlay.dts @@ -0,0 +1,240 @@ @@ -26611,19 +39808,19 @@ + fragment@15 { + target = <&pca>; + __dormant__ { -+ compatible = "nxp,pca16416"; ++ compatible = "nxp,pcal6416"; + }; + }; + fragment@16 { + target = <&pca>; + __dormant__ { -+ compatible = "nxp,pca16524"; ++ compatible = "nxp,pcal6524"; + }; + }; + fragment@17 { + target = <&pca>; + __dormant__ { -+ compatible = "nxp,pca19555a"; ++ compatible = "nxp,pcal9555a"; + }; + }; + fragment@18 { @@ -26721,9 +39918,9 @@ + pca9574 = <0>, "+12"; + pca9575 = <0>, "+13"; + pca9698 = <0>, "+14"; -+ pca16416 = <0>, "+15"; -+ pca16524 = <0>, "+16"; -+ pca19555a = <0>, "+17"; ++ pcal6416 = <0>, "+15"; ++ pcal6524 = <0>, "+16"; ++ pcal9555a = <0>, "+17"; + max7310 = <0>, "+18"; + max7312 = <0>, "+19"; + max7313 = <0>, "+20"; @@ -26739,6 +39936,44 @@ + xra1202 = <0>, "+30"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/pcf857x-overlay.dts b/arch/arm/boot/dts/overlays/pcf857x-overlay.dts +new file mode 100644 +index 000000000000..68943e1c3320 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/pcf857x-overlay.dts +@@ -0,0 +1,32 @@ ++// Definitions for PCF857X GPIO Extender from NXP ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2c_arm>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pcf857x: pcf857x@0 { ++ compatible = ""; ++ reg = <0x00>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ pcf8574 = <&pcf857x>,"compatible=nxp,pcf8574", <&pcf857x>,"reg:0=0x20"; ++ pcf8574a = <&pcf857x>,"compatible=nxp,pcf8574a", <&pcf857x>,"reg:0=0x38"; ++ pcf8575 = <&pcf857x>,"compatible=nxp,pcf8575", <&pcf857x>,"reg:0=0x20"; ++ pca8574 = <&pcf857x>,"compatible=nxp,pca8574", <&pcf857x>,"reg:0=0x20"; ++ addr = <&pcf857x>,"reg:0"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/pcie-32bit-dma-overlay.dts b/arch/arm/boot/dts/overlays/pcie-32bit-dma-overlay.dts new file mode 100644 index 000000000000..955703563df7 @@ -26783,9 +40018,41 @@ + }; + +}; +diff --git a/arch/arm/boot/dts/overlays/pcie-32bit-dma-pi5-overlay.dts b/arch/arm/boot/dts/overlays/pcie-32bit-dma-pi5-overlay.dts +new file mode 100644 +index 000000000000..f9908494f101 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/pcie-32bit-dma-pi5-overlay.dts +@@ -0,0 +1,26 @@ ++/* ++ * pcie-32bit-dma-pi5-overlay.dts ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&pcie1>; ++ __overlay__ { ++ /* ++ * The size of the range is rounded up to a power of 2, ++ * so the range ends up being 0-4GB, and the MSI vector ++ * gets pushed beyond 4GB. ++ */ ++ #address-cells = <3>; ++ #size-cells = <2>; ++ dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 ++ 0x0 0x80000000>; ++ }; ++ }; ++ ++}; diff --git a/arch/arm/boot/dts/overlays/pibell-overlay.dts b/arch/arm/boot/dts/overlays/pibell-overlay.dts new file mode 100644 -index 000000000000..9333a9b09772 +index 000000000000..99d4b6d97969 --- /dev/null +++ b/arch/arm/boot/dts/overlays/pibell-overlay.dts @@ -0,0 +1,81 @@ @@ -26815,7 +40082,7 @@ + }; + + fragment@1 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + #sound-dai-cells = <0>; + status = "okay"; @@ -26834,7 +40101,7 @@ + format = "i2s"; + + r_cpu_dai: cpu { -+ sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + +/* example TDM slot configuration + dai-tdm-slot-num = <2>; @@ -26851,7 +40118,7 @@ + format = "i2s"; + + p_cpu_dai: cpu { -+ sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + +/* example TDM slot configuration + dai-tdm-slot-num = <2>; @@ -27022,7 +40289,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/pifi-40-overlay.dts b/arch/arm/boot/dts/overlays/pifi-40-overlay.dts new file mode 100644 -index 000000000000..51a20e54977f +index 000000000000..d9ef4ea4097e --- /dev/null +++ b/arch/arm/boot/dts/overlays/pifi-40-overlay.dts @@ -0,0 +1,50 @@ @@ -27034,7 +40301,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -27070,7 +40337,7 @@ + pifi_40: __overlay__ { + compatible = "pifi,pifi-40"; + audio-codec = <&tas5711l &tas5711r>; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + pdn-gpios = <&gpio 23 1>; + status = "okay"; + }; @@ -27078,7 +40345,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/pifi-dac-hd-overlay.dts b/arch/arm/boot/dts/overlays/pifi-dac-hd-overlay.dts new file mode 100644 -index 000000000000..67f50db7861a +index 000000000000..236098365dc2 --- /dev/null +++ b/arch/arm/boot/dts/overlays/pifi-dac-hd-overlay.dts @@ -0,0 +1,49 @@ @@ -27090,7 +40357,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -27122,7 +40389,7 @@ + simple-audio-card,dai-link@1 { + format = "i2s"; + cpu { -+ sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + }; + codec { + sound-dai = <&pcm5142>; @@ -27133,7 +40400,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/pifi-dac-zero-overlay.dts b/arch/arm/boot/dts/overlays/pifi-dac-zero-overlay.dts new file mode 100644 -index 000000000000..645ea74cb435 +index 000000000000..dd272388779e --- /dev/null +++ b/arch/arm/boot/dts/overlays/pifi-dac-zero-overlay.dts @@ -0,0 +1,49 @@ @@ -27155,7 +40422,7 @@ + format = "i2s"; + + cpu { -+ sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; @@ -27179,7 +40446,7 @@ + }; + + fragment@2 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + #sound-dai-cells = <0>; + status = "okay"; @@ -27188,7 +40455,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/pifi-mini-210-overlay.dts b/arch/arm/boot/dts/overlays/pifi-mini-210-overlay.dts new file mode 100644 -index 000000000000..963597d611b5 +index 000000000000..a7b857144a48 --- /dev/null +++ b/arch/arm/boot/dts/overlays/pifi-mini-210-overlay.dts @@ -0,0 +1,42 @@ @@ -27200,7 +40467,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -27228,7 +40495,7 @@ + target = <&sound>; + __overlay__ { + compatible = "pifi,pifi-mini-210"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + + status = "okay"; + }; @@ -27339,10 +40606,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/piscreen-overlay.dts b/arch/arm/boot/dts/overlays/piscreen-overlay.dts new file mode 100644 -index 000000000000..1ac75a248fab +index 000000000000..29bcd41f39cf --- /dev/null +++ b/arch/arm/boot/dts/overlays/piscreen-overlay.dts -@@ -0,0 +1,102 @@ +@@ -0,0 +1,107 @@ +/* + * Device Tree overlay for PiScreen 3.5" display shield by Ozzmaker + * @@ -27351,6 +40618,8 @@ +/dts-v1/; +/plugin/; + ++#include <dt-bindings/gpio/gpio.h> ++ +/ { + compatible = "brcm,bcm2835"; + @@ -27404,9 +40673,9 @@ + fps = <30>; + buswidth = <8>; + regwidth = <16>; -+ reset-gpios = <&gpio 25 1>; -+ dc-gpios = <&gpio 24 0>; -+ led-gpios = <&gpio 22 0>; ++ reset-gpios = <&gpio 25 GPIO_ACTIVE_LOW>; ++ dc-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>; ++ led-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; + debug = <0>; + + init = <0x10000b0 0x00 @@ -27430,7 +40699,7 @@ + spi-max-frequency = <2000000>; + interrupts = <17 2>; /* high-to-low edge triggered */ + interrupt-parent = <&gpio>; -+ pendown-gpio = <&gpio 17 0>; ++ pendown-gpio = <&gpio 17 GPIO_ACTIVE_LOW>; + ti,swap-xy; + ti,x-plate-ohms = /bits/ 16 <100>; + ti,pressure-max = /bits/ 16 <255>; @@ -27439,15 +40708,18 @@ + }; + __overrides__ { + speed = <&piscreen>,"spi-max-frequency:0"; -+ rotate = <&piscreen>,"rotate:0"; ++ rotate = <&piscreen>,"rotate:0", ++ <&piscreen>,"rotation:0"; + fps = <&piscreen>,"fps:0"; + debug = <&piscreen>,"debug:0"; + xohms = <&piscreen_ts>,"ti,x-plate-ohms;0"; ++ drm = <&piscreen>,"compatible=waveshare,rpi-lcd-35", ++ <&piscreen>,"reset-gpios:8=",<GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts b/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts new file mode 100644 -index 000000000000..9d2b51101969 +index 000000000000..4468f4a54bf7 --- /dev/null +++ b/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts @@ -0,0 +1,106 @@ @@ -27541,7 +40813,7 @@ + spi-max-frequency = <2000000>; + interrupts = <17 2>; /* high-to-low edge triggered */ + interrupt-parent = <&gpio>; -+ pendown-gpio = <&gpio 17 0>; ++ pendown-gpio = <&gpio 17 1>; + ti,swap-xy; + ti,x-plate-ohms = /bits/ 16 <100>; + ti,pressure-max = /bits/ 16 <255>; @@ -27559,13 +40831,13 @@ + diff --git a/arch/arm/boot/dts/overlays/pisound-overlay.dts b/arch/arm/boot/dts/overlays/pisound-overlay.dts new file mode 100644 -index 000000000000..49efb2b768fb +index 000000000000..226bcbdf8a09 --- /dev/null +++ b/arch/arm/boot/dts/overlays/pisound-overlay.dts -@@ -0,0 +1,120 @@ +@@ -0,0 +1,118 @@ +/* + * Pisound Linux kernel module. -+ * Copyright (C) 2016-2017 Vilniaus Blokas UAB, https://blokas.io/pisound ++ * Copyright (C) 2016-2024 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 @@ -27620,9 +40892,8 @@ + pisound_spi: pisound_spi@0{ + compatible = "blokaslabs,pisound-spi"; + reg = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi0_pins>; + spi-max-frequency = <1000000>; ++ spi-speed-hz = <150000>; + }; + }; + }; @@ -27642,9 +40913,11 @@ + target = <&sound>; + __overlay__ { + compatible = "blokaslabs,pisound"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; ++ spi-controller = <&pisound_spi>; + status = "okay"; + ++ pinctrl-names = "default"; + pinctrl-0 = <&pisound_button_pins>; + + osr-gpios = @@ -27665,9 +40938,6 @@ + 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 @@ -27677,18 +40947,55 @@ + }; + + fragment@7 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/pisound-pi5-overlay.dts b/arch/arm/boot/dts/overlays/pisound-pi5-overlay.dts +new file mode 100644 +index 000000000000..a54974c446a0 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/pisound-pi5-overlay.dts +@@ -0,0 +1,31 @@ ++/* ++ * Pisound Linux kernel module. ++ * Copyright (C) 2016-2024 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 "pisound-overlay.dts" ++ ++&pisound_spi { ++ spi-speed-hz = <100000>; ++}; ++ ++/ { ++ compatible = "brcm,bcm2712"; ++}; diff --git a/arch/arm/boot/dts/overlays/pitft22-overlay.dts b/arch/arm/boot/dts/overlays/pitft22-overlay.dts new file mode 100644 -index 000000000000..589ad13795b1 +index 000000000000..5759d48aed57 --- /dev/null +++ b/arch/arm/boot/dts/overlays/pitft22-overlay.dts -@@ -0,0 +1,69 @@ +@@ -0,0 +1,71 @@ +/* + * Device Tree overlay for pitft by Adafruit + * @@ -27698,72 +41005,74 @@ +/plugin/; + +/ { -+ compatible = "brcm,bcm2835"; -+ -+ fragment@0 { -+ target = <&spi0>; -+ __overlay__ { -+ status = "okay"; -+ -+ spidev@0{ -+ status = "disabled"; -+ }; ++ compatible = "brcm,bcm2835"; + -+ spidev@1{ -+ status = "disabled"; -+ }; -+ }; ++ fragment@0 { ++ target = <&spidev0>; ++ __overlay__ { ++ status = "disabled"; ++ }; + }; + -+ fragment@1 { -+ target = <&gpio>; -+ __overlay__ { -+ pitft_pins: pitft_pins { -+ brcm,pins = <25>; -+ brcm,function = <1>; /* out */ -+ brcm,pull = <0>; /* none */ -+ }; -+ }; -+ }; ++ fragment@1 { ++ target = <&spidev1>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; + -+ fragment@2 { -+ target = <&spi0>; -+ __overlay__ { -+ /* needed to avoid dtc warning */ -+ #address-cells = <1>; -+ #size-cells = <0>; ++ fragment@2 { ++ target = <&gpio>; ++ __overlay__ { ++ pitft_pins: pitft_pins { ++ brcm,pins = <25>; ++ brcm,function = <1>; /* out */ ++ brcm,pull = <0>; /* none */ ++ }; ++ }; ++ }; + -+ pitft: pitft@0{ -+ compatible = "ilitek,ili9340"; -+ reg = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pitft_pins>; ++ fragment@3 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; + -+ spi-max-frequency = <32000000>; -+ rotate = <90>; -+ fps = <25>; -+ bgr; -+ buswidth = <8>; -+ dc-gpios = <&gpio 25 0>; -+ debug = <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"; -+ }; ++ }; ++ }; ++ ++ __overrides__ { ++ speed = <&pitft>,"spi-max-frequency:0"; ++ rotate = <&pitft>,"rotate:0", /* fbtft */ ++ <&pitft>,"rotation:0"; /* drm */ ++ fps = <&pitft>,"fps:0"; ++ debug = <&pitft>,"debug:0"; ++ drm = <&pitft>,"compatible=adafruit,yx240qv29"; ++ }; +}; diff --git a/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts b/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts new file mode 100644 -index 000000000000..33901ee1db7a +index 000000000000..de98ee7b4496 --- /dev/null +++ b/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts -@@ -0,0 +1,91 @@ +@@ -0,0 +1,93 @@ +/* + * Device Tree overlay for Adafruit PiTFT 2.8" capacitive touch screen + * @@ -27773,14 +41082,14 @@ +/plugin/; + +/ { -+ compatible = "brcm,bcm2835"; ++ compatible = "brcm,bcm2835"; + -+ fragment@0 { -+ target = <&spi0>; -+ __overlay__ { -+ status = "okay"; -+ }; -+ }; ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; + + fragment@1 { + target = <&spidev0>; @@ -27789,78 +41098,80 @@ + }; + }; + -+ 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@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>; ++ 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>; ++ 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>; -+ }; -+ }; -+ }; ++ 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>; ++ fragment@4 { ++ target = <&i2c1>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; + -+ ft6236: ft6236@38 { -+ compatible = "focaltech,ft6236"; -+ reg = <0x38>; ++ ft6236: ft6236@38 { ++ compatible = "focaltech,ft6236"; ++ reg = <0x38>; + -+ interrupt-parent = <&gpio>; -+ interrupts = <24 2>; -+ touchscreen-size-x = <240>; -+ touchscreen-size-y = <320>; -+ }; -+ }; -+ }; ++ 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?"; -+ }; ++ __overrides__ { ++ speed = <&pitft>,"spi-max-frequency:0"; ++ rotate = <&pitft>,"rotate:0", /* fbtft */ ++ <&pitft>,"rotation:0"; /* drm */ ++ fps = <&pitft>,"fps:0"; ++ debug = <&pitft>,"debug:0"; ++ drm = <&pitft>,"compatible=adafruit,yx240qv29"; ++ touch-sizex = <&ft6236>,"touchscreen-size-x:0"; ++ touch-sizey = <&ft6236>,"touchscreen-size-y:0"; ++ touch-invx = <&ft6236>,"touchscreen-inverted-x?"; ++ touch-invy = <&ft6236>,"touchscreen-inverted-y?"; ++ touch-swapxy = <&ft6236>,"touchscreen-swapped-x-y?"; ++ }; +}; diff --git a/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts b/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts new file mode 100644 -index 000000000000..4a4a3f44c29d +index 000000000000..bc2597179b9c --- /dev/null +++ b/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts -@@ -0,0 +1,119 @@ +@@ -0,0 +1,126 @@ +/* + * Device Tree overlay for Adafruit PiTFT 2.8" resistive touch screen + * @@ -27927,16 +41238,18 @@ + }; + + pitft_ts@1 { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #interrupt-cells = <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 { ++ stmpe_touchscreen: stmpe_touchscreen { + compatible = "st,stmpe-ts"; + st,sample-time = <4>; + st,mod-12b = <1>; @@ -27975,17 +41288,22 @@ + + __overrides__ { + speed = <&pitft>,"spi-max-frequency:0"; -+ rotate = <&pitft>,"rotate:0"; ++ rotate = <&pitft>,"rotate:0", /* fbtft */ ++ <&pitft>,"rotation:0"; /* drm */ + fps = <&pitft>,"fps:0"; + debug = <&pitft>,"debug:0"; ++ drm = <&pitft>,"compatible=adafruit,yx240qv29"; ++ touch-invx = <&stmpe_touchscreen>,"touchscreen-inverted-x?"; ++ touch-invy = <&stmpe_touchscreen>,"touchscreen-inverted-y?"; ++ touch-swapxy = <&stmpe_touchscreen>,"touchscreen-swapped-x-y?"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts b/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts new file mode 100644 -index 000000000000..37629f18a740 +index 000000000000..c3e81ef6003a --- /dev/null +++ b/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts -@@ -0,0 +1,119 @@ +@@ -0,0 +1,127 @@ +/* + * Device Tree overlay for Adafruit PiTFT 3.5" resistive touch screen + * @@ -28037,7 +41355,7 @@ + #size-cells = <0>; + + pitft: pitft@0{ -+ compatible = "himax,hx8357d", "adafruit,yx350hv15"; ++ compatible = "himax,hx8357d"; + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pitft_pins>; @@ -28052,16 +41370,18 @@ + }; + + pitft_ts@1 { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #interrupt-cells = <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 { ++ stmpe_touchscreen: stmpe_touchscreen { + compatible = "st,stmpe-ts"; + st,sample-time = <4>; + st,mod-12b = <1>; @@ -28090,7 +41410,7 @@ + fragment@5 { + target-path = "/soc"; + __overlay__ { -+ backlight { ++ backlight: backlight { + compatible = "gpio-backlight"; + gpios = <&stmpe_gpio 2 0>; + default-on; @@ -28100,17 +41420,23 @@ + + __overrides__ { + speed = <&pitft>,"spi-max-frequency:0"; -+ rotate = <&pitft>,"rotate:0"; ++ rotate = <&pitft>,"rotate:0", /* fbtft */ ++ <&pitft>,"rotation:0"; /* drm */ + fps = <&pitft>,"fps:0"; + debug = <&pitft>,"debug:0"; ++ drm = <&pitft>,"compatible=adafruit,yx350hv15", ++ <&pitft>,"backlight:0=",<&backlight>; ++ touch-invx = <&stmpe_touchscreen>,"touchscreen-inverted-x?"; ++ touch-invy = <&stmpe_touchscreen>,"touchscreen-inverted-y?"; ++ touch-swapxy = <&stmpe_touchscreen>,"touchscreen-swapped-x-y?"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/pps-gpio-overlay.dts b/arch/arm/boot/dts/overlays/pps-gpio-overlay.dts new file mode 100644 -index 000000000000..524a1c1d3670 +index 000000000000..a4f6b868aad8 --- /dev/null +++ b/arch/arm/boot/dts/overlays/pps-gpio-overlay.dts -@@ -0,0 +1,38 @@ +@@ -0,0 +1,39 @@ +/dts-v1/; +/plugin/; + @@ -28147,14 +41473,60 @@ + <&pps_pins>,"reg:0"; + assert_falling_edge = <&pps>,"assert-falling-edge?"; + capture_clear = <&pps>,"capture-clear?"; ++ pull = <&pps_pins>,"brcm,pull:0"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/proto-codec-overlay.dts b/arch/arm/boot/dts/overlays/proto-codec-overlay.dts +new file mode 100644 +index 000000000000..92f6ed158923 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/proto-codec-overlay.dts +@@ -0,0 +1,39 @@ ++// Definitions for Rpi-Proto ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2s_clk_consumer>; ++ __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_clk_consumer>; ++ status = "okay"; ++ }; + }; +}; diff --git a/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts b/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts new file mode 100644 -index 000000000000..4ddbbfa04065 +index 000000000000..823c8b4126d1 --- /dev/null +++ b/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts -@@ -0,0 +1,49 @@ +@@ -0,0 +1,48 @@ +/dts-v1/; +/plugin/; + @@ -28191,7 +41563,6 @@ + frag1: __overlay__ { + pinctrl-names = "default"; + pinctrl-0 = <&pwm_pins>; -+ assigned-clock-rates = <100000000>; + status = "okay"; + }; + }; @@ -28206,7 +41577,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/pwm-ir-tx-overlay.dts b/arch/arm/boot/dts/overlays/pwm-ir-tx-overlay.dts new file mode 100644 -index 000000000000..119caf746b3b +index 000000000000..33597eb79729 --- /dev/null +++ b/arch/arm/boot/dts/overlays/pwm-ir-tx-overlay.dts @@ -0,0 +1,40 @@ @@ -28240,7 +41611,7 @@ + __overlay__ { + pwm-ir-transmitter { + compatible = "pwm-ir-tx"; -+ pwms = <&pwm 0 100>; ++ pwms = <&pwm 0 100 0>; + }; + }; + }; @@ -28252,10 +41623,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/pwm-overlay.dts b/arch/arm/boot/dts/overlays/pwm-overlay.dts new file mode 100644 -index 000000000000..92876ab3bc8c +index 000000000000..32853492aaea --- /dev/null +++ b/arch/arm/boot/dts/overlays/pwm-overlay.dts -@@ -0,0 +1,45 @@ +@@ -0,0 +1,44 @@ +/dts-v1/; +/plugin/; + @@ -28290,7 +41661,6 @@ + frag1: __overlay__ { + pinctrl-names = "default"; + pinctrl-0 = <&pwm_pins>; -+ assigned-clock-rates = <100000000>; + status = "okay"; + }; + }; @@ -28301,6 +41671,71 @@ + clock = <&frag1>,"assigned-clock-rates:0"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/pwm1-overlay.dts b/arch/arm/boot/dts/overlays/pwm1-overlay.dts +new file mode 100644 +index 000000000000..3324d4160653 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/pwm1-overlay.dts +@@ -0,0 +1,59 @@ ++/dts-v1/; ++/plugin/; ++ ++#include <dt-bindings/pinctrl/bcm2835.h> ++ ++/ { ++ compatible = "brcm,bcm2711"; ++ ++ fragment@0 { ++ target = <&pins>; ++ __overlay__ { ++ brcm,pins = <40 41>; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&pins>; ++ __dormant__ { ++ brcm,pins = <40>; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&pins>; ++ __dormant__ { ++ brcm,pins = <41>; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&gpio>; ++ __overlay__ { ++ pins: pwm1_overlay_pins { ++ brcm,pins = <40 41>; ++ brcm,function = <BCM2835_FSEL_ALT0>; ++ brcm,pull = <BCM2835_PUD_UP>; ++ }; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&pwm1>; ++ pwm: __overlay__ { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pins>; ++ }; ++ }; ++ ++ __overrides__ { ++ clock = <&pwm>, "assigned-clock-rates:0"; ++ pins_40_41 = <0>,"+0-1-2"; ++ pins_40 = <0>,"-0+1-2"; ++ pins_41 = <0>,"-0-1+2"; ++ pull_up = <&pins>, "brcm,pull:0=", <BCM2835_PUD_UP>; ++ pull_down = <&pins>, "brcm,pull:0=", <BCM2835_PUD_DOWN>; ++ pull_off = <&pins>, "brcm,pull:0=", <BCM2835_PUD_OFF>; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/qca7000-overlay.dts b/arch/arm/boot/dts/overlays/qca7000-overlay.dts new file mode 100644 index 000000000000..f695f36024fa @@ -28364,7 +41799,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/qca7000-uart0-overlay.dts b/arch/arm/boot/dts/overlays/qca7000-uart0-overlay.dts new file mode 100644 -index 000000000000..5dee70853289 +index 000000000000..f103916c9e1c --- /dev/null +++ b/arch/arm/boot/dts/overlays/qca7000-uart0-overlay.dts @@ -0,0 +1,46 @@ @@ -28394,7 +41829,7 @@ + fragment@1 { + target = <&gpio>; + __overlay__ { -+ uart0_pins: uart0_pins { ++ uart0_pins: uart0_ovl_pins { + brcm,pins = <14 15>; + brcm,function = <4>; /* alt0 */ + brcm,pull = <0 2>; @@ -28414,6 +41849,68 @@ + baudrate = <ð2>, "current-speed:0"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/ramoops-overlay.dts b/arch/arm/boot/dts/overlays/ramoops-overlay.dts +new file mode 100644 +index 000000000000..e5038658138d +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/ramoops-overlay.dts +@@ -0,0 +1,25 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&rmem>; ++ __overlay__ { ++ ramoops: ramoops@b000000 { ++ compatible = "ramoops"; ++ reg = <0x0b000000 0x10000>; /* 64kB */ ++ record-size = <0x4000>; /* 16kB */ ++ console-size = <0>; /* disabled by default */ ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ base-addr = <&ramoops>,"reg:0"; ++ total-size = <&ramoops>,"reg:4"; ++ record-size = <&ramoops>,"record-size:0"; ++ console-size = <&ramoops>,"console-size:0"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/ramoops-pi4-overlay.dts b/arch/arm/boot/dts/overlays/ramoops-pi4-overlay.dts +new file mode 100644 +index 000000000000..1737e37f5724 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/ramoops-pi4-overlay.dts +@@ -0,0 +1,25 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2711"; ++ ++ fragment@0 { ++ target = <&rmem>; ++ __overlay__ { ++ ramoops: ramoops@b000000 { ++ compatible = "ramoops"; ++ reg = <0x0 0x0b000000 0x10000>; /* 64kB */ ++ record-size = <0x4000>; /* 16kB */ ++ console-size = <0>; /* disabled by default */ ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ base-addr = <&ramoops>,"reg#0"; ++ total-size = <&ramoops>,"reg:8"; ++ record-size = <&ramoops>,"record-size:0"; ++ console-size = <&ramoops>,"console-size:0"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/rotary-encoder-overlay.dts b/arch/arm/boot/dts/overlays/rotary-encoder-overlay.dts new file mode 100644 index 000000000000..ea1d952734e9 @@ -28506,319 +42003,88 @@ + }; + }; +}; -diff --git a/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts +diff --git a/arch/arm/boot/dts/overlays/rpi-codeczero-overlay.dts b/arch/arm/boot/dts/overlays/rpi-codeczero-overlay.dts new file mode 100644 -index 000000000000..ed0c2745399f +index 000000000000..c3b0564b2fb2 --- /dev/null -+++ b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts -@@ -0,0 +1,172 @@ -+// 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>; ++++ b/arch/arm/boot/dts/overlays/rpi-codeczero-overlay.dts +@@ -0,0 +1,9 @@ ++// Overlay for the Raspberry Pi Codec Zero soundcard + -+ 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>; -+ }; -+ }; -+ }; ++#include "iqaudio-codec-overlay.dts" + -+ fragment@8 { -+ target = <&sound>; -+ __overlay__ { -+ compatible = "wlf,rpi-cirrus"; -+ i2s-controller = <&i2s>; -+ status = "okay"; -+ }; -+ }; ++&iqaudio_dac { ++ card_name = "RPi Codec Zero"; ++ dai_name = "Raspberry Pi Codec Zero"; ++ dai_stream_name = "Raspberry Pi Codec Zero HiFi"; +}; -diff --git a/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts b/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts +diff --git a/arch/arm/boot/dts/overlays/rpi-dacplus-overlay.dts b/arch/arm/boot/dts/overlays/rpi-dacplus-overlay.dts new file mode 100644 -index 000000000000..07a915342702 +index 000000000000..47557aa17f19 --- /dev/null -+++ b/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts -@@ -0,0 +1,34 @@ -+// Definitions for RPi DAC -+/dts-v1/; -+/plugin/; -+ -+/ { -+ compatible = "brcm,bcm2835"; ++++ b/arch/arm/boot/dts/overlays/rpi-dacplus-overlay.dts +@@ -0,0 +1,17 @@ ++// Overlay for the Raspberry Pi DAC Plus soundcard + -+ fragment@0 { -+ target = <&i2s>; -+ __overlay__ { -+ status = "okay"; -+ }; -+ }; ++#include "iqaudio-dacplus-overlay.dts" + -+ fragment@1 { -+ target-path = "/"; -+ __overlay__ { -+ pcm1794a-codec { -+ #sound-dai-cells = <0>; -+ compatible = "ti,pcm1794a"; -+ status = "okay"; -+ }; -+ }; -+ }; ++&iqaudio_dac { ++ card_name = "RPi DAC+"; ++ dai_name = "Raspberry Pi DAC+"; ++ dai_stream_name = "Raspberry Pi DAC+ HiFi"; ++ /delete-property/ mute-gpios; ++}; + -+ fragment@2 { -+ target = <&sound>; -+ __overlay__ { -+ compatible = "rpi,rpi-dac"; -+ i2s-controller = <&i2s>; -+ status = "okay"; -+ }; ++/ { ++ __overrides__ { ++ /delete-property/ auto_mute_amp; ++ /delete-property/ unmute_amp; + }; +}; -diff --git a/arch/arm/boot/dts/overlays/rpi-display-overlay.dts b/arch/arm/boot/dts/overlays/rpi-display-overlay.dts +diff --git a/arch/arm/boot/dts/overlays/rpi-dacpro-overlay.dts b/arch/arm/boot/dts/overlays/rpi-dacpro-overlay.dts new file mode 100644 -index 000000000000..2cf937b56456 +index 000000000000..412260c64edf --- /dev/null -+++ b/arch/arm/boot/dts/overlays/rpi-display-overlay.dts -@@ -0,0 +1,91 @@ -+/* -+ * Device Tree overlay for rpi-display by Watterott -+ * -+ */ -+ -+/dts-v1/; -+/plugin/; -+ -+/ { -+ compatible = "brcm,bcm2835"; -+ -+ fragment@0 { -+ target = <&spi0>; -+ __overlay__ { -+ status = "okay"; -+ }; -+ }; ++++ b/arch/arm/boot/dts/overlays/rpi-dacpro-overlay.dts +@@ -0,0 +1,17 @@ ++// Overlay for the Raspberry Pi DAC Pro soundcard + -+ fragment@1 { -+ target = <&spidev0>; -+ __overlay__ { -+ status = "disabled"; -+ }; -+ }; ++#include "iqaudio-dacplus-overlay.dts" + -+ fragment@2 { -+ target = <&spidev1>; -+ __overlay__ { -+ status = "disabled"; -+ }; -+ }; ++&iqaudio_dac { ++ card_name = "RPi DAC Pro"; ++ dai_name = "Raspberry Pi DAC Pro"; ++ dai_stream_name = "Raspberry Pi DAC Pro HiFi"; ++ /delete-property/ mute-gpios; ++}; + -+ 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 */ -+ }; -+ }; ++/ { ++ __overrides__ { ++ /delete-property/ auto_mute_amp; ++ /delete-property/ unmute_amp; + }; ++}; +diff --git a/arch/arm/boot/dts/overlays/rpi-digiampplus-overlay.dts b/arch/arm/boot/dts/overlays/rpi-digiampplus-overlay.dts +new file mode 100644 +index 000000000000..5e73d6c1bf42 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/rpi-digiampplus-overlay.dts +@@ -0,0 +1,17 @@ ++// Overlay for the Raspberry Pi DAC Plus soundcard + -+ 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 1>; -+ debug = <0>; -+ }; ++#include "iqaudio-dacplus-overlay.dts" + -+ rpidisplay_ts: rpi-display-ts@1 { -+ compatible = "ti,ads7846"; -+ reg = <1>; ++&iqaudio_dac { ++ card_name = "RPi DigiAMP+"; ++ dai_name = "Raspberry Pi DigiAMP+"; ++ dai_stream_name = "Raspberry Pi DigiAMP+ HiFi"; ++ iqaudio-dac,auto-mute-amp; ++}; + -+ 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"; ++ unmute_amp = <&iqaudio_dac>,"iqaudio-dac,unmute-amp?", ++ <&iqaudio_dac>,"iqaudio-dac,auto-mute-amp!"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts b/arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts @@ -28854,10 +42120,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts b/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts new file mode 100644 -index 000000000000..af812132a8f7 +index 000000000000..cfd9fe37e108 --- /dev/null +++ b/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts -@@ -0,0 +1,95 @@ +@@ -0,0 +1,154 @@ +/* + * Overlay for the Raspberry Pi POE HAT. + */ @@ -28870,14 +42136,11 @@ + 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>; ++ fan: pwm-fan { ++ compatible = "pwm-fan"; + cooling-levels = <0 1 10 100 255>; -+ status = "okay"; ++ #cooling-cells = <2>; ++ pwms = <&fwpwm 0 80000 0>; + }; + }; + }; @@ -28885,52 +42148,61 @@ + 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>; -+ }; -+ }; ++ polling-delay = <2000>; /* milliseconds */ + }; + }; + + fragment@2 { -+ target-path = "/__overrides__"; ++ target = <&thermal_trips>; ++ __overlay__ { ++ 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"; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&cooling_maps>; + __overlay__ { ++ map0 { ++ trip = <&trip0>; ++ cooling-device = <&fan 0 1>; ++ }; ++ map1 { ++ trip = <&trip1>; ++ cooling-device = <&fan 1 2>; ++ }; ++ map2 { ++ trip = <&trip2>; ++ cooling-device = <&fan 2 3>; ++ }; ++ map3 { ++ trip = <&trip3>; ++ cooling-device = <&fan 3 4>; ++ }; ++ }; ++ }; ++ ++ fragment@4 { ++ target-path = "/__overrides__"; ++ params: __overlay__ { + poe_fan_temp0 = <&trip0>,"temperature:0"; + poe_fan_temp0_hyst = <&trip0>,"hysteresis:0"; + poe_fan_temp1 = <&trip1>,"temperature:0"; @@ -28939,6 +42211,54 @@ + poe_fan_temp2_hyst = <&trip2>,"hysteresis:0"; + poe_fan_temp3 = <&trip3>,"temperature:0"; + poe_fan_temp3_hyst = <&trip3>,"hysteresis:0"; ++ poe_fan_i2c = <&fwpwm>,"status=disabled", ++ <&poe_mfd>,"status=okay", ++ <&fan>,"pwms:0=",<&poe_mfd_pwm>; ++ }; ++ }; ++ ++ fragment@5 { ++ target = <&firmware>; ++ __overlay__ { ++ fwpwm: pwm { ++ compatible = "raspberrypi,firmware-poe-pwm"; ++ #pwm-cells = <2>; ++ }; ++ }; ++ }; ++ ++ fragment@6 { ++ target = <&i2c0>; ++ i2c_bus: __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ poe_mfd: poe@51 { ++ compatible = "raspberrypi,poe-core"; ++ reg = <0x51>; ++ status = "disabled"; ++ ++ poe_mfd_pwm: poe_pwm@f0 { ++ compatible = "raspberrypi,poe-pwm"; ++ reg = <0xf0>; ++ status = "okay"; ++ #pwm-cells = <2>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@7 { ++ target = <&i2c0if>; ++ __dormant__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@8 { ++ target = <&i2c0mux>; ++ __dormant__ { ++ status = "okay"; + }; + }; + @@ -28951,14 +42271,19 @@ + poe_fan_temp2_hyst = <&trip2>,"hysteresis:0"; + poe_fan_temp3 = <&trip3>,"temperature:0"; + poe_fan_temp3_hyst = <&trip3>,"hysteresis:0"; ++ i2c = <0>, "+5+6", ++ <&fwpwm>,"status=disabled", ++ <&i2c_bus>,"status=okay", ++ <&poe_mfd>,"status=okay", ++ <&fan>,"pwms:0=",<&poe_mfd_pwm>; + }; +}; diff --git a/arch/arm/boot/dts/overlays/rpi-poe-plus-overlay.dts b/arch/arm/boot/dts/overlays/rpi-poe-plus-overlay.dts new file mode 100644 -index 000000000000..5b12d02c3707 +index 000000000000..54deda2f18c3 --- /dev/null +++ b/arch/arm/boot/dts/overlays/rpi-poe-plus-overlay.dts -@@ -0,0 +1,23 @@ +@@ -0,0 +1,49 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +// Overlay for the Raspberry Pi PoE+ HAT. + @@ -28967,28 +42292,54 @@ +/ { + compatible = "brcm,bcm2835"; + -+ fragment@3 { ++ fragment@10 { + target-path = "/"; + __overlay__ { -+ rpi_poe_power_supply: rpi-poe-power-supply@0 { ++ rpi_poe_power_supply: rpi-poe-power-supply { + compatible = "raspberrypi,rpi-poe-power-supply"; + firmware = <&firmware>; + status = "okay"; + }; + }; + }; ++ fragment@11 { ++ target = <&poe_mfd>; ++ __overlay__ { ++ rpi-poe-power-supply@f2 { ++ compatible = "raspberrypi,rpi-poe-power-supply"; ++ reg = <0xf2>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ i2c = <0>, "+5+6", ++ <&fwpwm>,"status=disabled", ++ <&rpi_poe_power_supply>,"status=disabled", ++ <&i2c_bus>,"status=okay", ++ <&poe_mfd>,"status=okay", ++ <&fan>,"pwms:0=",<&poe_mfd_pwm>; ++ }; +}; + -+&fan0 { ++&fan { + cooling-levels = <0 32 64 128 255>; +}; -diff --git a/arch/arm/boot/dts/overlays/rpi-proto-overlay.dts b/arch/arm/boot/dts/overlays/rpi-proto-overlay.dts ++ ++¶ms { ++ poe_fan_i2c = <&fwpwm>,"status=disabled", ++ <&rpi_poe_power_supply>,"status=disabled", ++ <&poe_mfd>,"status=okay", ++ <&fan>,"pwms:0=",<&poe_mfd_pwm>; ++}; +diff --git a/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts b/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts new file mode 100644 -index 000000000000..9cda044a0f62 +index 000000000000..89d8d2ea6b2e --- /dev/null -+++ b/arch/arm/boot/dts/overlays/rpi-proto-overlay.dts -@@ -0,0 +1,39 @@ -+// Definitions for Rpi-Proto ++++ b/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts +@@ -0,0 +1,47 @@ ++// rpi-sense HAT +/dts-v1/; +/plugin/; + @@ -28996,42 +42347,50 @@ + 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>; ++ rpi-sense@46 { ++ compatible = "rpi,rpi-sense"; ++ reg = <0x46>; ++ keys-int-gpios = <&gpio 23 1>; + status = "okay"; + }; -+ }; -+ }; + -+ fragment@2 { -+ target = <&sound>; -+ __overlay__ { -+ compatible = "rpi,rpi-proto"; -+ i2s-controller = <&i2s>; -+ 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 --git a/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts b/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts +diff --git a/arch/arm/boot/dts/overlays/rpi-sense-v2-overlay.dts b/arch/arm/boot/dts/overlays/rpi-sense-v2-overlay.dts new file mode 100644 -index 000000000000..89d8d2ea6b2e +index 000000000000..1b86c032259b --- /dev/null -+++ b/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts ++++ b/arch/arm/boot/dts/overlays/rpi-sense-v2-overlay.dts @@ -0,0 +1,47 @@ +// rpi-sense HAT +/dts-v1/; @@ -29060,12 +42419,6 @@ + status = "okay"; + }; + -+ lsm9ds1-accel6a { -+ compatible = "st,lsm9ds1-accel"; -+ reg = <0x6a>; -+ status = "okay"; -+ }; -+ + lps25h-press@5c { + compatible = "st,lps25h-press"; + reg = <0x5c>; @@ -29077,6 +42430,12 @@ + reg = <0x5f>; + status = "okay"; + }; ++ ++ lsm9ds1-accel@6a { ++ compatible = "st,lsm9ds1-accel"; ++ reg = <0x6a>; ++ status = "okay"; ++ }; + }; + }; +}; @@ -29120,65 +42479,9 @@ + }; + +}; -diff --git a/arch/arm/boot/dts/overlays/rpivid-v4l2-overlay.dts b/arch/arm/boot/dts/overlays/rpivid-v4l2-overlay.dts -new file mode 100644 -index 000000000000..bdd1c0e5a915 ---- /dev/null -+++ b/arch/arm/boot/dts/overlays/rpivid-v4l2-overlay.dts -@@ -0,0 +1,50 @@ -+// 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 --git a/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts b/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts new file mode 100644 -index 000000000000..87e9a326eff1 +index 000000000000..97db53a91fda --- /dev/null +++ b/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts @@ -0,0 +1,49 @@ @@ -29190,7 +42493,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -29226,7 +42529,7 @@ + target = <&sound>; + __overlay__ { + compatible = "rra,digidac1-soundcard"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; @@ -29642,6 +42945,36 @@ + gpios_34_39 = <0>,"=5"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/sdio-pi5-overlay.dts b/arch/arm/boot/dts/overlays/sdio-pi5-overlay.dts +new file mode 100644 +index 000000000000..4e42cb5c856e +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/sdio-pi5-overlay.dts +@@ -0,0 +1,24 @@ ++/dts-v1/; ++/plugin/; ++ ++/* SDIO/SD/MMC on RP1 bank 0 */ ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&rp1_mmc0>; ++ frag0: __overlay__ { ++ status = "okay"; ++ pinctrl-0 = <&rp1_sdio0_22_27>; ++ pinctrl-names = "default"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&rp1_sdio_clk0>; ++ frag1: __overlay__ { ++ status = "okay"; ++ }; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/seeed-can-fd-hat-v1-overlay.dts b/arch/arm/boot/dts/overlays/seeed-can-fd-hat-v1-overlay.dts new file mode 100644 index 000000000000..210d027a073e @@ -30280,7 +43613,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/spi-rtc-overlay.dts b/arch/arm/boot/dts/overlays/spi-rtc-overlay.dts new file mode 100644 -index 000000000000..51b7fec281c0 +index 000000000000..df3286929c2e --- /dev/null +++ b/arch/arm/boot/dts/overlays/spi-rtc-overlay.dts @@ -0,0 +1,75 @@ @@ -30294,14 +43627,14 @@ + fragment@0 { + target = <&rtc>; + __dormant__ { -+ compatible = "maxim,ds3232"; ++ compatible = "dallas,ds3232"; + }; + }; + + fragment@1 { + target = <&rtc>; + __dormant__ { -+ compatible = "maxim,ds3234"; ++ compatible = "dallas,ds3234"; + }; + }; + @@ -30783,6 +44116,45 @@ + cs0_spidev = <&spidev2_0>,"status"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/spi2-1cs-pi5-overlay.dts b/arch/arm/boot/dts/overlays/spi2-1cs-pi5-overlay.dts +new file mode 100644 +index 000000000000..44382cc5a7c0 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/spi2-1cs-pi5-overlay.dts +@@ -0,0 +1,33 @@ ++/dts-v1/; ++/plugin/; ++ ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&spi2>; ++ frag1: __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cs-gpios = <&gpio 0 1>; ++ status = "okay"; ++ ++ spidev2_0: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ cs0_pin = <&frag1>,"cs-gpios:4"; ++ cs0_spidev = <&spidev2_0>,"status"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts b/arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts new file mode 100644 index 000000000000..642678fc9ddd @@ -30858,6 +44230,56 @@ + cs1_spidev = <&spidev2_1>,"status"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/spi2-2cs-pi5-overlay.dts b/arch/arm/boot/dts/overlays/spi2-2cs-pi5-overlay.dts +new file mode 100644 +index 000000000000..b37a2c21c7b4 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/spi2-2cs-pi5-overlay.dts +@@ -0,0 +1,44 @@ ++/dts-v1/; ++/plugin/; ++ ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&spi2>; ++ frag1: __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cs-gpios = <&gpio 0 1>, <&gpio 24 1>; ++ status = "okay"; ++ ++ spidev2_0: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ ++ spidev2_1: spidev@1 { ++ compatible = "spidev"; ++ reg = <1>; /* CE1 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ cs0_pin = <&frag1>,"cs-gpios:4"; ++ cs1_pin = <&frag1>,"cs-gpios:16"; ++ cs0_spidev = <&spidev2_0>,"status"; ++ cs1_spidev = <&spidev2_1>,"status"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts b/arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts new file mode 100644 index 000000000000..28d40c6c3c37 @@ -30947,10 +44369,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts b/arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts new file mode 100644 -index 000000000000..335af8637051 +index 000000000000..7abea6d86fd0 --- /dev/null +++ b/arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts -@@ -0,0 +1,44 @@ +@@ -0,0 +1,42 @@ +/dts-v1/; +/plugin/; + @@ -30973,8 +44395,6 @@ + #address-cells = <1>; + #size-cells = <0>; + -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi3_pins &spi3_cs_pins>; + cs-gpios = <&gpio 0 1>; + status = "okay"; + @@ -30995,12 +44415,51 @@ + cs0_spidev = <&spidev3_0>,"status"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/spi3-1cs-pi5-overlay.dts b/arch/arm/boot/dts/overlays/spi3-1cs-pi5-overlay.dts +new file mode 100644 +index 000000000000..a94e3a9f35ce +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/spi3-1cs-pi5-overlay.dts +@@ -0,0 +1,33 @@ ++/dts-v1/; ++/plugin/; ++ ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&spi3>; ++ frag1: __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cs-gpios = <&gpio 4 1>; ++ status = "okay"; ++ ++ spidev3_0: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ cs0_pin = <&frag1>,"cs-gpios:4"; ++ cs0_spidev = <&spidev3_0>,"status"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts b/arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts new file mode 100644 -index 000000000000..ce65da27f767 +index 000000000000..2f474ac769f5 --- /dev/null +++ b/arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts -@@ -0,0 +1,56 @@ +@@ -0,0 +1,54 @@ +/dts-v1/; +/plugin/; + @@ -31023,8 +44482,6 @@ + #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"; + @@ -31057,12 +44514,62 @@ + cs1_spidev = <&spidev3_1>,"status"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/spi3-2cs-pi5-overlay.dts b/arch/arm/boot/dts/overlays/spi3-2cs-pi5-overlay.dts +new file mode 100644 +index 000000000000..259548b37d5c +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/spi3-2cs-pi5-overlay.dts +@@ -0,0 +1,44 @@ ++/dts-v1/; ++/plugin/; ++ ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&spi3>; ++ frag1: __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cs-gpios = <&gpio 4 1>, <&gpio 25 1>; ++ status = "okay"; ++ ++ spidev3_0: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ ++ spidev3_1: spidev@1 { ++ compatible = "spidev"; ++ reg = <1>; /* CE1 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ cs0_pin = <&frag1>,"cs-gpios:4"; ++ cs1_pin = <&frag1>,"cs-gpios:16"; ++ cs0_spidev = <&spidev3_0>,"status"; ++ cs1_spidev = <&spidev3_1>,"status"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts b/arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts new file mode 100644 -index 000000000000..85d70b40352b +index 000000000000..66d89521124a --- /dev/null +++ b/arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts -@@ -0,0 +1,44 @@ +@@ -0,0 +1,42 @@ +/dts-v1/; +/plugin/; + @@ -31085,8 +44592,6 @@ + #address-cells = <1>; + #size-cells = <0>; + -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi4_pins &spi4_cs_pins>; + cs-gpios = <&gpio 4 1>; + status = "okay"; + @@ -31109,10 +44614,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts b/arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts new file mode 100644 -index 000000000000..8bc2215a6a7e +index 000000000000..83d8cb8b918c --- /dev/null +++ b/arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts -@@ -0,0 +1,56 @@ +@@ -0,0 +1,54 @@ +/dts-v1/; +/plugin/; + @@ -31135,8 +44640,6 @@ + #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"; + @@ -31171,10 +44674,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts b/arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts new file mode 100644 -index 000000000000..c0f8cb8510ee +index 000000000000..168b4825de34 --- /dev/null +++ b/arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts -@@ -0,0 +1,44 @@ +@@ -0,0 +1,42 @@ +/dts-v1/; +/plugin/; + @@ -31197,8 +44700,6 @@ + #address-cells = <1>; + #size-cells = <0>; + -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi5_pins &spi5_cs_pins>; + cs-gpios = <&gpio 12 1>; + status = "okay"; + @@ -31219,12 +44720,51 @@ + cs0_spidev = <&spidev5_0>,"status"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/spi5-1cs-pi5-overlay.dts b/arch/arm/boot/dts/overlays/spi5-1cs-pi5-overlay.dts +new file mode 100644 +index 000000000000..bde1837f26c0 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/spi5-1cs-pi5-overlay.dts +@@ -0,0 +1,33 @@ ++/dts-v1/; ++/plugin/; ++ ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&spi5>; ++ frag1: __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cs-gpios = <&gpio 12 1>; ++ status = "okay"; ++ ++ spidev5_0: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ cs0_pin = <&frag1>,"cs-gpios:4"; ++ cs0_spidev = <&spidev5_0>,"status"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts b/arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts new file mode 100644 -index 000000000000..7758b9c00b4e +index 000000000000..c2a239a34b35 --- /dev/null +++ b/arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts -@@ -0,0 +1,56 @@ +@@ -0,0 +1,54 @@ +/dts-v1/; +/plugin/; + @@ -31247,8 +44787,6 @@ + #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"; + @@ -31281,12 +44819,62 @@ + cs1_spidev = <&spidev5_1>,"status"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/spi5-2cs-pi5-overlay.dts b/arch/arm/boot/dts/overlays/spi5-2cs-pi5-overlay.dts +new file mode 100644 +index 000000000000..2c9eee2a9db8 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/spi5-2cs-pi5-overlay.dts +@@ -0,0 +1,44 @@ ++/dts-v1/; ++/plugin/; ++ ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&spi5>; ++ frag1: __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cs-gpios = <&gpio 12 1>, <&gpio 26 1>; ++ status = "okay"; ++ ++ spidev5_0: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ ++ spidev5_1: spidev@1 { ++ compatible = "spidev"; ++ reg = <1>; /* CE1 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ cs0_pin = <&frag1>,"cs-gpios:4"; ++ cs1_pin = <&frag1>,"cs-gpios:16"; ++ cs0_spidev = <&spidev5_0>,"status"; ++ cs1_spidev = <&spidev5_1>,"status"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts b/arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts new file mode 100644 -index 000000000000..8c8a953eca01 +index 000000000000..a784f8a17d23 --- /dev/null +++ b/arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts -@@ -0,0 +1,44 @@ +@@ -0,0 +1,42 @@ +/dts-v1/; +/plugin/; + @@ -31309,8 +44897,6 @@ + #address-cells = <1>; + #size-cells = <0>; + -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi6_pins &spi6_cs_pins>; + cs-gpios = <&gpio 18 1>; + status = "okay"; + @@ -31333,10 +44919,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts b/arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts new file mode 100644 -index 000000000000..2ff897f21aed +index 000000000000..8ef513814d2b --- /dev/null +++ b/arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts -@@ -0,0 +1,56 @@ +@@ -0,0 +1,54 @@ +/dts-v1/; +/plugin/; + @@ -31359,8 +44945,6 @@ + #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"; + @@ -31437,10 +45021,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts b/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts new file mode 100644 -index 000000000000..ffc90c7cecf6 +index 000000000000..679749fc3065 --- /dev/null +++ b/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts -@@ -0,0 +1,84 @@ +@@ -0,0 +1,85 @@ +/* + * Device Tree overlay for SSD1306 based SPI OLED display + * @@ -31523,6 +45107,7 @@ + reset_pin = <&ssd1306>,"reset-gpios:4", + <&ssd1306_pins>,"brcm,pins:0"; + height = <&ssd1306>,"solomon,height:0"; ++ inverted = <&ssd1306>,"solomon,com-invdir?"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/ssd1331-spi-overlay.dts b/arch/arm/boot/dts/overlays/ssd1331-spi-overlay.dts @@ -31705,7 +45290,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/superaudioboard-overlay.dts b/arch/arm/boot/dts/overlays/superaudioboard-overlay.dts new file mode 100755 -index 000000000000..bad61535981e +index 000000000000..1006d5fe9e06 --- /dev/null +++ b/arch/arm/boot/dts/overlays/superaudioboard-overlay.dts @@ -0,0 +1,73 @@ @@ -31720,7 +45305,7 @@ + target = <&sound>; + __overlay__ { + compatible = "simple-audio-card"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + + simple-audio-card,name = "SuperAudioBoard"; @@ -31743,7 +45328,7 @@ + simple-audio-card,frame-master = <&sound_master>; + + simple-audio-card,cpu { -+ sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_consumer>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; @@ -31756,7 +45341,7 @@ + }; + + fragment@1 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -33496,7 +47081,7 @@ + diff --git a/arch/arm/boot/dts/overlays/tc358743-audio-overlay.dts b/arch/arm/boot/dts/overlays/tc358743-audio-overlay.dts new file mode 100644 -index 000000000000..047695bb0c71 +index 000000000000..6bb3dceb0df3 --- /dev/null +++ b/arch/arm/boot/dts/overlays/tc358743-audio-overlay.dts @@ -0,0 +1,52 @@ @@ -33510,7 +47095,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -33533,16 +47118,16 @@ + compatible = "simple-audio-card"; + simple-audio-card,format = "i2s"; + simple-audio-card,name = "tc358743"; -+ simple-audio-card,bitclock-master = <&dailink0_slave>; -+ simple-audio-card,frame-master = <&dailink0_slave>; ++ simple-audio-card,bitclock-master = <&dailink0_master>; ++ simple-audio-card,frame-master = <&dailink0_master>; + status = "okay"; + + simple-audio-card,cpu { -+ sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_consumer>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; -+ dailink0_slave: simple-audio-card,codec { ++ dailink0_master: simple-audio-card,codec { + sound-dai = <&tc358743_codec>; + }; + }; @@ -33554,7 +47139,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/tc358743-overlay.dts b/arch/arm/boot/dts/overlays/tc358743-overlay.dts new file mode 100644 -index 000000000000..c3eebfd1f6ee +index 000000000000..2eb74d33b40d --- /dev/null +++ b/arch/arm/boot/dts/overlays/tc358743-overlay.dts @@ -0,0 +1,109 @@ @@ -33661,7 +47246,7 @@ + 4lane = <0>, "-2+3-7+8"; + link-frequency = <&tc358743_0>,"link-frequencies#0"; + media-controller = <&csi>,"brcm,media-controller?"; -+ cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&tc358743>, "clocks:0=",<&cam0_clk>; @@ -33669,7 +47254,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts b/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts new file mode 100644 -index 000000000000..a102b09e3ab5 +index 000000000000..edc5889b6f5f --- /dev/null +++ b/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts @@ -0,0 +1,222 @@ @@ -33796,7 +47381,7 @@ + spi-max-frequency = <2000000>; + interrupts = <5 2>; /* high-to-low edge triggered */ + interrupt-parent = <&gpio>; -+ pendown-gpio = <&gpio 5 0>; ++ pendown-gpio = <&gpio 5 1>; + ti,x-plate-ohms = /bits/ 16 <100>; + ti,pressure-max = /bits/ 16 <255>; + }; @@ -33945,9 +47530,65 @@ + }; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/tpm-slb9673-overlay.dts b/arch/arm/boot/dts/overlays/tpm-slb9673-overlay.dts +new file mode 100644 +index 000000000000..cba8c25c30e5 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/tpm-slb9673-overlay.dts +@@ -0,0 +1,50 @@ ++/* ++ * Device Tree overlay for the Infineon SLB9673 Trusted Platform Module add-on ++ * boards, which can be used as a secure key storage and hwrng. ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ /* Due to issue https://github.com/raspberrypi/linux/issues/4884 the ++ hardware I2C needs to be disabled and software I2C enabled */ ++ fragment@0 { ++ target = <&i2c_arm>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/"; ++ __overlay__ { ++ i2c1: i2c-gpio@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "i2c-gpio"; ++ gpios = <&gpio 2 6>, /* SDA GPIO_OPEN_DRAIN */ ++ <&gpio 3 6>; /* CLK GPIO_OPEN_DRAIN */ ++ clock-frequency = <400000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ /* Add the TPM */ ++ fragment@2 { ++ target = <&i2c1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ slb9673: slb9673@2e { ++ compatible = "infineon,slb9673", "tcg,tpm-tis-i2c"; ++ reg = <0x2e>; ++ status = "okay"; ++ }; ++ }; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/uart0-overlay.dts b/arch/arm/boot/dts/overlays/uart0-overlay.dts new file mode 100755 -index 000000000000..73d563bbaabf +index 000000000000..6bf2e0fd5c61 --- /dev/null +++ b/arch/arm/boot/dts/overlays/uart0-overlay.dts @@ -0,0 +1,32 @@ @@ -33969,7 +47610,7 @@ + fragment@1 { + target = <&gpio>; + __overlay__ { -+ uart0_pins: uart0_pins { ++ uart0_pins: uart0_ovl_pins { + brcm,pins = <14 15>; + brcm,function = <4>; /* alt0 */ + brcm,pull = <0 2>; @@ -33983,9 +47624,33 @@ + pin_func = <&uart0_pins>,"brcm,function:0"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/uart0-pi5-overlay.dts b/arch/arm/boot/dts/overlays/uart0-pi5-overlay.dts +new file mode 100755 +index 000000000000..3cc9843b812d +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/uart0-pi5-overlay.dts +@@ -0,0 +1,18 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&uart0>; ++ frag0: __overlay__ { ++ status = "okay"; ++ pinctrl-0 = <&uart0_pins>; ++ }; ++ }; ++ ++ __overrides__ { ++ ctsrts = <&frag0>,"pinctrl-0:4=",<&uart0_ctsrts_pins>; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/uart1-overlay.dts b/arch/arm/boot/dts/overlays/uart1-overlay.dts new file mode 100644 -index 000000000000..986d725a2652 +index 000000000000..64163bf932b7 --- /dev/null +++ b/arch/arm/boot/dts/overlays/uart1-overlay.dts @@ -0,0 +1,38 @@ @@ -34007,7 +47672,7 @@ + fragment@1 { + target = <&gpio>; + __overlay__ { -+ uart1_pins: uart1_pins { ++ uart1_pins: uart1_ovl_pins { + brcm,pins = <14 15>; + brcm,function = <2>; /* alt5 */ + brcm,pull = <0 2>; @@ -34027,12 +47692,36 @@ + rxd1_pin = <&uart1_pins>,"brcm,pins:4"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/uart1-pi5-overlay.dts b/arch/arm/boot/dts/overlays/uart1-pi5-overlay.dts +new file mode 100755 +index 000000000000..739f5a941ffa +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/uart1-pi5-overlay.dts +@@ -0,0 +1,18 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&uart1>; ++ frag0: __overlay__ { ++ status = "okay"; ++ pinctrl-0 = <&uart1_pins>; ++ }; ++ }; ++ ++ __overrides__ { ++ ctsrts = <&frag0>,"pinctrl-0:4=",<&uart1_ctsrts_pins>; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/uart2-overlay.dts b/arch/arm/boot/dts/overlays/uart2-overlay.dts new file mode 100644 -index 000000000000..9face240aca1 +index 000000000000..d98cb5795f6a --- /dev/null +++ b/arch/arm/boot/dts/overlays/uart2-overlay.dts -@@ -0,0 +1,27 @@ +@@ -0,0 +1,25 @@ +/dts-v1/; +/plugin/; + @@ -34042,8 +47731,6 @@ + fragment@0 { + target = <&uart2>; + __overlay__ { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart2_pins>; + status = "okay"; + }; + }; @@ -34060,12 +47747,36 @@ + ctsrts = <0>,"=1"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/uart2-pi5-overlay.dts b/arch/arm/boot/dts/overlays/uart2-pi5-overlay.dts +new file mode 100755 +index 000000000000..1df956425d3a +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/uart2-pi5-overlay.dts +@@ -0,0 +1,18 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&uart2>; ++ frag0: __overlay__ { ++ status = "okay"; ++ pinctrl-0 = <&uart2_pins>; ++ }; ++ }; ++ ++ __overrides__ { ++ ctsrts = <&frag0>,"pinctrl-0:4=",<&uart2_ctsrts_pins>; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/uart3-overlay.dts b/arch/arm/boot/dts/overlays/uart3-overlay.dts new file mode 100644 -index 000000000000..ae9f9fe5ea1d +index 000000000000..5751d5b1a29e --- /dev/null +++ b/arch/arm/boot/dts/overlays/uart3-overlay.dts -@@ -0,0 +1,27 @@ +@@ -0,0 +1,25 @@ +/dts-v1/; +/plugin/; + @@ -34075,8 +47786,6 @@ + fragment@0 { + target = <&uart3>; + __overlay__ { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart3_pins>; + status = "okay"; + }; + }; @@ -34093,12 +47802,36 @@ + ctsrts = <0>,"=1"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/uart3-pi5-overlay.dts b/arch/arm/boot/dts/overlays/uart3-pi5-overlay.dts +new file mode 100755 +index 000000000000..d8ef51b403dd +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/uart3-pi5-overlay.dts +@@ -0,0 +1,18 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&uart3>; ++ frag0: __overlay__ { ++ status = "okay"; ++ pinctrl-0 = <&uart3_pins>; ++ }; ++ }; ++ ++ __overrides__ { ++ ctsrts = <&frag0>,"pinctrl-0:4=",<&uart3_ctsrts_pins>; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/uart4-overlay.dts b/arch/arm/boot/dts/overlays/uart4-overlay.dts new file mode 100644 -index 000000000000..ac004ffbadbf +index 000000000000..99def557b779 --- /dev/null +++ b/arch/arm/boot/dts/overlays/uart4-overlay.dts -@@ -0,0 +1,27 @@ +@@ -0,0 +1,25 @@ +/dts-v1/; +/plugin/; + @@ -34108,8 +47841,6 @@ + fragment@0 { + target = <&uart4>; + __overlay__ { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart4_pins>; + status = "okay"; + }; + }; @@ -34126,12 +47857,36 @@ + ctsrts = <0>,"=1"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/uart4-pi5-overlay.dts b/arch/arm/boot/dts/overlays/uart4-pi5-overlay.dts +new file mode 100755 +index 000000000000..7ce5be8cc95c +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/uart4-pi5-overlay.dts +@@ -0,0 +1,18 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&uart4>; ++ frag0: __overlay__ { ++ status = "okay"; ++ pinctrl-0 = <&uart4_pins>; ++ }; ++ }; ++ ++ __overrides__ { ++ ctsrts = <&frag0>,"pinctrl-0:4=",<&uart4_ctsrts_pins>; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/uart5-overlay.dts b/arch/arm/boot/dts/overlays/uart5-overlay.dts new file mode 100644 -index 000000000000..04eaf376effe +index 000000000000..649daea52e6b --- /dev/null +++ b/arch/arm/boot/dts/overlays/uart5-overlay.dts -@@ -0,0 +1,27 @@ +@@ -0,0 +1,25 @@ +/dts-v1/; +/plugin/; + @@ -34141,8 +47896,6 @@ + fragment@0 { + target = <&uart5>; + __overlay__ { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart5_pins>; + status = "okay"; + }; + }; @@ -34161,7 +47914,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/udrc-overlay.dts b/arch/arm/boot/dts/overlays/udrc-overlay.dts new file mode 100644 -index 000000000000..ae7c37996894 +index 000000000000..701f28e811bb --- /dev/null +++ b/arch/arm/boot/dts/overlays/udrc-overlay.dts @@ -0,0 +1,128 @@ @@ -34176,7 +47929,7 @@ +/ { + compatible = "brcm,bcm2835"; + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + clocks = <&clocks BCM2835_CLOCK_PCM>; + clock-names = "pcm"; @@ -34238,7 +47991,7 @@ + target = <&sound>; + snd: __overlay__ { + compatible = "simple-audio-card"; -+ i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + + simple-audio-card,name = "udrc"; @@ -34260,7 +48013,7 @@ + "Line Out", "LOL"; + + dailink0_master: simple-audio-card,cpu { -+ sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + }; + + simple-audio-card,codec { @@ -34295,7 +48048,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/ugreen-dabboard-overlay.dts b/arch/arm/boot/dts/overlays/ugreen-dabboard-overlay.dts new file mode 100644 -index 000000000000..fc8d9b118068 +index 000000000000..234f1f38225b --- /dev/null +++ b/arch/arm/boot/dts/overlays/ugreen-dabboard-overlay.dts @@ -0,0 +1,49 @@ @@ -34307,7 +48060,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; @@ -34330,14 +48083,14 @@ + compatible = "simple-audio-card"; + simple-audio-card,format = "i2s"; + simple-audio-card,name = "dabboard"; -+ simple-audio-card,bitclock-master = <&dailink0_slave>; -+ simple-audio-card,frame-master = <&dailink0_slave>; ++ simple-audio-card,bitclock-master = <&dailink0_master>; ++ simple-audio-card,frame-master = <&dailink0_master>; + simple-audio-card,widgets = "Microphone", "Microphone Jack"; + status = "okay"; + simple-audio-card,cpu { -+ sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_consumer>; + }; -+ dailink0_slave: simple-audio-card,codec { ++ dailink0_master: simple-audio-card,codec { + #sound-dai-cells = <0>; + sound-dai = <&dmic_codec>; + }; @@ -34350,7 +48103,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/upstream-overlay.dts b/arch/arm/boot/dts/overlays/upstream-overlay.dts new file mode 100644 -index 000000000000..2852bea52309 +index 000000000000..55a99736a33b --- /dev/null +++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts @@ -0,0 +1,101 @@ @@ -34436,9 +48189,9 @@ + }; + }; + fragment@12 { -+ target = <&audio>; ++ target = <&chosen>; + __overlay__ { -+ brcm,disable-hdmi; ++ bootargs = "snd_bcm2835.enable_hdmi=0"; + }; + }; + fragment@13 { @@ -34457,7 +48210,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/upstream-pi4-overlay.dts b/arch/arm/boot/dts/overlays/upstream-pi4-overlay.dts new file mode 100644 -index 000000000000..f4328634542e +index 000000000000..1dc60ae6d967 --- /dev/null +++ b/arch/arm/boot/dts/overlays/upstream-pi4-overlay.dts @@ -0,0 +1,137 @@ @@ -34567,9 +48320,9 @@ + }; + }; + fragment@16 { -+ target = <&audio>; ++ target-path = "/chosen"; + __overlay__ { -+ brcm,disable-hdmi; ++ bootargs = "snd_bcm2835.enable_hdmi=0"; + }; + }; + fragment@17 { @@ -34600,10 +48353,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts b/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts new file mode 100644 -index 000000000000..ca344492bed8 +index 000000000000..d201edbe7003 --- /dev/null +++ b/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts -@@ -0,0 +1,40 @@ +@@ -0,0 +1,46 @@ +/* + * vc4-fkms-v3d-overlay.dts + */ @@ -34643,13 +48396,19 @@ + status = "okay"; + }; + }; ++ fragment@5 { ++ target-path = "/chosen"; ++ __overlay__ { ++ bootargs = "clk_ignore_unused"; ++ }; ++ }; +}; diff --git a/arch/arm/boot/dts/overlays/vc4-fkms-v3d-pi4-overlay.dts b/arch/arm/boot/dts/overlays/vc4-fkms-v3d-pi4-overlay.dts new file mode 100644 -index 000000000000..7792ead0cbb3 +index 000000000000..1e10203dfd86 --- /dev/null +++ b/arch/arm/boot/dts/overlays/vc4-fkms-v3d-pi4-overlay.dts -@@ -0,0 +1,44 @@ +@@ -0,0 +1,50 @@ +/* + * vc4-fkms-v3d-overlay.dts + */ @@ -34660,7 +48419,7 @@ +#include "cma-overlay.dts" + +&frag0 { -+ size = <((320-4)*1024*1024)>; ++ size = <((512-4)*1024*1024)>; +}; + +/ { @@ -34693,13 +48452,19 @@ + status = "okay"; + }; + }; ++ fragment@5 { ++ target-path = "/chosen"; ++ __overlay__ { ++ bootargs = "clk_ignore_unused"; ++ }; ++ }; +}; diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts new file mode 100644 -index 000000000000..1e5c5080592b +index 000000000000..8b006fcd9e58 --- /dev/null +++ b/arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts -@@ -0,0 +1,74 @@ +@@ -0,0 +1,81 @@ +/* + * vc4-kms-dpi-generic-overlay.dts + */ @@ -34714,7 +48479,7 @@ + + fragment@0 { + target = <&panel>; -+ __overlay__ { ++ panel_generic: __overlay__ { + compatible = "panel-dpi"; + + width-mm = <154>; @@ -34742,7 +48507,7 @@ + + fragment@1 { + target = <&dpi>; -+ __overlay__ { ++ dpi_node_generic: __overlay__ { + pinctrl-0 = <&dpi_18bit_gpio0>; + }; + }; @@ -34765,13 +48530,345 @@ + width-mm = <&panel>, "width-mm:0"; + height-mm = <&panel>, "height-mm:0"; + -+ rgb565 = <&panel>, "bus-format:0=0x1017", -+ <&dpi_node>, "pinctrl-0:0=",<&dpi_16bit_gpio0>; -+ rgb666-padhi = <&panel>, "bus-format:0=0x1015", -+ <&dpi_node>, "pinctrl-0:0=",<&dpi_18bit_cpadhi_gpio0>; -+ rgb888 = <&panel>, "bus-format:0=0x100a", -+ <&dpi_node>, "pinctrl-0:0=",<&dpi_gpio0>; -+ bus-format = <&panel>, "bus-format:0"; ++ rgb565 = <&panel_generic>, "bus-format:0=0x1017", ++ <&dpi_node_generic>, "pinctrl-0:0=",<&dpi_16bit_gpio0>; ++ rgb565-padhi = <&panel_generic>, "bus-format:0=0x1022", ++ <&dpi_node_generic>, "pinctrl-0:0=",<&dpi_16bit_cpadhi_gpio0>; ++ bgr666 = <&panel_generic>, "bus-format:0=0x1023"; ++ bgr666-padhi = <&panel_generic>, "bus-format:0=0x1024", ++ <&dpi_node_generic>, "pinctrl-0:0=",<&dpi_18bit_cpadhi_gpio0>; ++ rgb666-padhi = <&panel_generic>, "bus-format:0=0x1015", ++ <&dpi_node_generic>, "pinctrl-0:0=",<&dpi_18bit_cpadhi_gpio0>; ++ bgr888 = <&panel_generic>, "bus-format:0=0x1013", ++ <&dpi_node_generic>, "pinctrl-0:0=",<&dpi_gpio0>; ++ rgb888 = <&panel_generic>, "bus-format:0=0x100a", ++ <&dpi_node_generic>, "pinctrl-0:0=",<&dpi_gpio0>; ++ bus-format = <&panel_generic>, "bus-format:0"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel.dtsi b/arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel.dtsi +new file mode 100644 +index 000000000000..585402a3b9b4 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel.dtsi +@@ -0,0 +1,94 @@ ++/* ++ * vc4-kms-dpi-hyperpixel4.dtsi ++ * Commmon initialisation for HyperPixel DPI displays ++ */ ++ ++#include <dt-bindings/gpio/gpio.h> ++#include <dt-bindings/pinctrl/bcm2835.h> ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ spi { ++ compatible = "spi-gpio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ pinctrl-0 = <&spi_pins>; ++ pinctrl-names = "default"; ++ ++ sck-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>; ++ mosi-gpios = <&gpio 26 GPIO_ACTIVE_HIGH>; ++ cs-gpios = <&gpio 18 GPIO_ACTIVE_LOW>; ++ num-chipselects = <1>; ++ sck-idle-input; ++ ++ panel: display@0 { ++ reg = <0>; ++ /* 100 kHz */ ++ spi-max-frequency = <100000>; ++ backlight = <&backlight>; ++ rotation = <0>; ++ ++ port { ++ panel_in: endpoint { ++ remote-endpoint = <&dpi_out>; ++ }; ++ }; ++ }; ++ }; ++ ++ backlight: backlight { ++ compatible = "gpio-backlight"; ++ gpios = <&gpio 19 0>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&dpi>; ++ __overlay__ { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&dpi_18bit_cpadhi_gpio0>; ++ ++ port { ++ dpi_out: endpoint { ++ remote-endpoint = <&panel_in>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&gpio>; ++ __overlay__ { ++ spi_pins: hyperpixel4_spi_pins { ++ brcm,pins = <27 18 26>; ++ brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_UP BCM2835_PUD_OFF>; ++ brcm,function = <0>; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target-path = "/"; ++ __overlay__ { ++ i2c_gpio: i2c@0 { ++ compatible = "i2c-gpio"; ++ gpios = <&gpio 10 0 /* sda */ ++ &gpio 11 0>; /* scl */ ++ i2c-gpio,delay-us = <4>; /* ~100 kHz */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ rotate = <&panel>, "rotation:0"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel2r-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel2r-overlay.dts +new file mode 100644 +index 000000000000..4cd9d6a55c48 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel2r-overlay.dts +@@ -0,0 +1,114 @@ ++/* ++ * vc4-kms-dpi-hyperpixel2r-overlay.dts ++ */ ++ ++#include <dt-bindings/gpio/gpio.h> ++#include <dt-bindings/pinctrl/bcm2835.h> ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ spi { ++ compatible = "spi-gpio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ pinctrl-0 = <&spi_pins>; ++ pinctrl-names = "default"; ++ ++ sck-gpios = <&gpio 11 GPIO_ACTIVE_HIGH>; ++ mosi-gpios = <&gpio 10 GPIO_ACTIVE_HIGH>; ++ cs-gpios = <&gpio 18 GPIO_ACTIVE_LOW>; ++ num-chipselects = <1>; ++ ++ panel: display@0 { ++ compatible = "pimoroni,hyperpixel2round"; ++ reg = <0>; ++ /* 100 kHz */ ++ spi-max-frequency = <100000>; ++ backlight = <&backlight>; ++ rotation = <0>; ++ ++ port { ++ panel_in: endpoint { ++ remote-endpoint = <&dpi_out>; ++ }; ++ }; ++ }; ++ }; ++ ++ backlight: backlight { ++ compatible = "gpio-backlight"; ++ gpios = <&gpio 19 0>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&dpi>; ++ __overlay__ { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&dpi_18bit_cpadhi_gpio0>; ++ ++ port { ++ dpi_out: endpoint { ++ remote-endpoint = <&panel_in>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&gpio>; ++ __overlay__ { ++ spi_pins: hyperpixel4_spi_pins { ++ brcm,pins = <27 18 26>; ++ brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_UP BCM2835_PUD_OFF>; ++ brcm,function = <0>; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target-path = "/"; ++ __overlay__ { ++ i2c_gpio: i2c@0 { ++ compatible = "i2c-gpio"; ++ status = "disabled"; ++ ++ gpios = <&gpio 10 GPIO_ACTIVE_HIGH /* sda */ ++ &gpio 11 GPIO_ACTIVE_HIGH>; /* scl */ ++ i2c-gpio,delay-us = <4>; /* ~100 kHz */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ polytouch: edt-ft5x06@15 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "edt,edt-ft5406"; ++ reg = <0x15>; ++ interrupt-parent = <&gpio>; ++ interrupts = <27 0x02>; ++ touchscreen-size-x = <240>; ++ touchscreen-size-y = <240>; ++ }; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ disable-touch = <0>,"-3"; ++ touchscreen-inverted-x = <&polytouch>,"touchscreen-inverted-x?"; ++ touchscreen-inverted-y = <&polytouch>,"touchscreen-inverted-y!"; ++ touchscreen-swapped-x-y = <&polytouch>,"touchscreen-swapped-x-y!"; ++ rotate = <&panel>, "rotation:0"; ++ }; ++ ++}; +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel4-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel4-overlay.dts +new file mode 100644 +index 000000000000..eafc25ad79ff +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel4-overlay.dts +@@ -0,0 +1,57 @@ ++/* ++ * vc4-kms-dpi-hyperpixel4sq-overlay.dts ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++#include "vc4-kms-dpi-hyperpixel.dtsi" ++ ++&panel { ++ compatible = "pimoroni,hyperpixel4"; ++}; ++ ++/ { ++ fragment@11 { ++ target = <&i2c_gpio>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ft6236_14: ft6236@14 { ++ compatible = "goodix,gt911"; ++ reg = <0x14>; ++ interrupt-parent = <&gpio>; ++ interrupts = <27 2>; ++ touchscreen-size-x = <480>; ++ touchscreen-size-y = <800>; ++ touchscreen-x-mm = <51>; ++ touchscreen-y-mm = <85>; ++ touchscreen-inverted-y; ++ touchscreen-swapped-x-y; ++ }; ++ ft6236_5d: ft6236@5d { ++ compatible = "goodix,gt911"; ++ reg = <0x5d>; ++ interrupt-parent = <&gpio>; ++ interrupts = <27 2>; ++ touchscreen-size-x = <480>; ++ touchscreen-size-y = <800>; ++ touchscreen-x-mm = <51>; ++ touchscreen-y-mm = <85>; ++ touchscreen-inverted-y; ++ touchscreen-swapped-x-y; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ disable-touch = <0>,"-3-11"; ++ touchscreen-inverted-x = <&ft6236_14>,"touchscreen-inverted-x?", ++ <&ft6236_5d>,"touchscreen-inverted-x?"; ++ touchscreen-inverted-y = <&ft6236_14>,"touchscreen-inverted-y!", ++ <&ft6236_5d>,"touchscreen-inverted-y!"; ++ touchscreen-swapped-x-y = <&ft6236_14>,"touchscreen-swapped-x-y!", ++ <&ft6236_5d>,"touchscreen-swapped-x-y!"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel4sq-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel4sq-overlay.dts +new file mode 100644 +index 000000000000..700046348ecf +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel4sq-overlay.dts +@@ -0,0 +1,36 @@ ++/* ++ * vc4-kms-dpi-hyperpixel4-overlay.dts ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++#include "vc4-kms-dpi-hyperpixel.dtsi" ++ ++&panel { ++ compatible = "pimoroni,hyperpixel4square"; ++}; ++ ++/ { ++ fragment@11 { ++ target = <&i2c_gpio>; ++ __overlay__ { ++ polytouch: edt-ft5x06@48 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "edt,edt-ft5406"; ++ reg = <0x48>; ++ interrupt-parent = <&gpio>; ++ interrupts = <27 0x02>; ++ touchscreen-size-x = <720>; ++ touchscreen-size-y = <720>; ++ }; ++ }; ++ }; ++ __overrides__ { ++ disable-touch = <0>,"-3-11"; ++ touchscreen-inverted-x = <&polytouch>,"touchscreen-inverted-x?"; ++ touchscreen-inverted-y = <&polytouch>,"touchscreen-inverted-y!"; ++ touchscreen-swapped-x-y = <&polytouch>,"touchscreen-swapped-x-y!"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dpi-panel-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dpi-panel-overlay.dts @@ -34851,7 +48948,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dpi.dtsi b/arch/arm/boot/dts/overlays/vc4-kms-dpi.dtsi new file mode 100644 -index 000000000000..f78fa48b19f9 +index 000000000000..67c884de2a8d --- /dev/null +++ b/arch/arm/boot/dts/overlays/vc4-kms-dpi.dtsi @@ -0,0 +1,111 @@ @@ -34923,7 +49020,7 @@ + compatible = "pwm-backlight"; + brightness-levels = <0 6 8 12 16 24 32 40 48 64 96 128 160 192 224 255>; + default-brightness-level = <16>; -+ pwms = <&pwm 0 200000>; ++ pwms = <&pwm 0 200000 0>; + }; + }; + }; @@ -34949,9 +49046,9 @@ + }; + + fragment@108 { -+ target = <&audio>; ++ target = <&chosen>; + __dormant__ { -+ brcm,disable-headphones; ++ bootargs = "snd_bcm2835.enable_headphones=0"; + }; + }; + @@ -34968,10 +49065,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts new file mode 100644 -index 000000000000..5e1700d0367a +index 000000000000..302fa807d31d --- /dev/null +++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts -@@ -0,0 +1,118 @@ +@@ -0,0 +1,124 @@ +/* + * Device Tree overlay for RaspberryPi 7" Touchscreen panel + * @@ -34985,7 +49082,7 @@ +/ { + /* No compatible as it will have come from edt-ft5406.dtsi */ + -+ fragment@0 { ++ dsi_frag: fragment@0 { + target = <&dsi1>; + __overlay__ { + #address-cells = <1>; @@ -35025,8 +49122,8 @@ + fragment@1 { + target-path = "/"; + __overlay__ { -+ panel_disp1: panel_disp1@0 { -+ reg = <0>; ++ panel_disp: panel_disp@1 { ++ reg = <1>; + compatible = "raspberrypi,7inch-dsi", "simple-panel"; + backlight = <®_display>; + power-supply = <®_display>; @@ -35038,8 +49135,8 @@ + }; + }; + -+ reg_bridge: reg_bridge@0 { -+ reg = <0>; ++ reg_bridge: reg_bridge@1 { ++ reg = <1>; + compatible = "regulator-fixed"; + regulator-name = "bridge_reg"; + gpio = <®_display 0 0>; @@ -35049,7 +49146,7 @@ + }; + }; + -+ fragment@2 { ++ i2c_frag: fragment@2 { + target = <&i2c_csi_dsi>; + __overlay__ { + #address-cells = <1>; @@ -35087,7 +49184,381 @@ + }; + + __overrides__ { -+ disable_touch = <0>, "-10-11-12"; ++ dsi0 = <&dsi_frag>, "target:0=",<&dsi0>, ++ <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&ts_i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&panel_disp>, "reg:0=0", ++ <®_bridge>, "reg:0=0", ++ <®_bridge>, "regulator-name=bridge_reg_0"; ++ disable_touch = <&ft5406>, "status=disabled"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dsi-generic-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dsi-generic-overlay.dts +new file mode 100644 +index 000000000000..cf4ca5b6c75f +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-generic-overlay.dts +@@ -0,0 +1,106 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ dsi_frag: fragment@0 { ++ target = <&dsi1>; ++ __overlay__{ ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port { ++ dsi_out:endpoint { ++ remote-endpoint = <&panel_dsi_port>; ++ }; ++ }; ++ panel: panel-dsi-generic@0 { ++ // See panel-dsi.yaml binding ++ // Using dummy name for panel model ++ compatible = "Generic,panel-dsi","panel-dsi"; ++ reg = <0>; ++ power-supply = <0>; ++ backlight = <0>; ++ dsi-color-format = "RGB888"; ++ mode = "MODE_VIDEO"; ++ width-mm = <0>; ++ height-mm = <0>; ++ ++ port { ++ panel_dsi_port: endpoint { ++ data-lanes = <1>; ++ remote-endpoint = <&dsi_out>; ++ }; ++ }; ++ ++ timing: panel-timing { ++ clock-frequency = <30000000>; ++ hactive = <840>; ++ vactive = <480>; ++ hback-porch = <44>; ++ hfront-porch = <46>; ++ hsync-len = <2>; ++ vback-porch = <18>; ++ vfront-porch = <16>; ++ vsync-len = <2>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&panel_dsi_port>; ++ __dormant__ { ++ data-lanes = <1>; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&panel_dsi_port>; ++ __dormant__ { ++ data-lanes = <1 2>; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&panel_dsi_port>; ++ __dormant__ { ++ data-lanes = <1 2 3>; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&panel_dsi_port>; ++ __dormant__ { ++ data-lanes = <1 2 3 4>; ++ }; ++ }; ++ ++ __overrides__ { ++ dsi0 = <&dsi_frag>, "target:0=",<&dsi0>; ++ ++ clock-frequency = <&timing>, "clock-frequency:0"; ++ hactive = <&timing>, "hactive:0"; ++ hfp = <&timing>, "hfront-porch:0"; ++ hsync = <&timing>, "hsync-len:0"; ++ hbp = <&timing>, "hback-porch:0"; ++ vactive = <&timing>, "vactive:0"; ++ vfp = <&timing>, "vfront-porch:0"; ++ vsync = <&timing>, "vsync-len:0"; ++ vbp = <&timing>, "vback-porch:0"; ++ ++ width-mm = <&panel>, "width-mm:0"; ++ height-mm = <&panel>, "height-mm:0"; ++ ++ rgb565 = <&panel>, "dsi-color-format=RGB565"; ++ rgb666p = <&panel>, "dsi-color-format=RGB666_PACKED"; ++ rgb666 = <&panel>, "dsi-color-format=RGB666"; ++ rgb888 = <&panel>, "dsi-color-format=RGB888"; ++ one-lane = <0>,"+1"; ++ two-lane = <0>,"+2"; ++ three-lane = <0>,"+3"; ++ four-lane = <0>,"+4"; ++ }; ++ ++}; +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dsi-ili9881-5inch-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dsi-ili9881-5inch-overlay.dts +new file mode 100644 +index 000000000000..1985766c0e67 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-ili9881-5inch-overlay.dts +@@ -0,0 +1,122 @@ ++/* ++ * vc4-kms-dsi-ili9881-5inch-overlay.dts ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++#include <dt-bindings/gpio/gpio.h> ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ i2c_frag: fragment@0 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ display_mcu: display_mcu@45 ++ { ++ compatible = "raspberrypi,v2-touchscreen-panel-regulator"; ++ reg = <0x45>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gt911: gt911@5d { ++ compatible = "goodix,gt911"; ++ reg = <0x5d>; ++ AVDD28-supply = <&touch_reg>; ++ touchscreen-size-x = <720>; ++ touchscreen-size-y = <1280>; ++ touchscreen-x-mm = <62>; ++ touchscreen-y-mm = <110>; ++ }; ++ }; ++ }; ++ ++ dsi_frag: fragment@1 { ++ target = <&dsi1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ port { ++ dsi_out: endpoint { ++ remote-endpoint = <&panel_in>; ++ }; ++ }; ++ ++ dsi_panel: dsi_panel@0 { ++ reg = <0>; ++ compatible = "raspberrypi,dsi-5inch"; ++ reset-gpio = <&display_mcu 0 GPIO_ACTIVE_LOW>; ++ backlight = <&display_mcu>; ++ ++ port { ++ panel_in: endpoint { ++ remote-endpoint = <&dsi_out>; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@4 { ++ target-path = "/"; ++ __overlay__ { ++ touch_reg: touch_reg@1 { ++ reg = <1>; ++ compatible = "regulator-fixed"; ++ regulator-name = "touch_reg_1"; ++ gpio = <&display_mcu 1 GPIO_ACTIVE_HIGH>; ++ startup-delay-us = <50000>; ++ enable-active-high; ++ }; ++ }; ++ }; ++ ++ fragment@10 { ++ target = <>911>; ++ __dormant__ { ++ touchscreen-inverted-x; ++ }; ++ }; ++ ++ fragment@11 { ++ target = <>911>; ++ __dormant__ { ++ touchscreen-inverted-y; ++ }; ++ }; ++ ++ __overrides__ { ++ dsi0 = <&dsi_frag>, "target:0=",<&dsi0>, ++ <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&touch_reg>, "reg:0=0", ++ <&touch_reg>, "regulator-name=touch_reg_0"; ++ sizex = <>911>,"touchscreen-size-x:0"; ++ sizey = <>911>,"touchscreen-size-y:0"; ++ invx = <0>, "+10"; ++ invy = <0>, "+11"; ++ swapxy = <>911>,"touchscreen-swapped-x-y?"; ++ disable_touch = <>911>, "status=disabled"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dsi-ili9881-7inch-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dsi-ili9881-7inch-overlay.dts +new file mode 100644 +index 000000000000..d1eb31df1d69 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-ili9881-7inch-overlay.dts +@@ -0,0 +1,122 @@ ++/* ++ * vc4-kms-dsi-ili9881-5inch-overlay.dts ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++#include <dt-bindings/gpio/gpio.h> ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ i2c_frag: fragment@0 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ display_mcu: display_mcu@45 ++ { ++ compatible = "raspberrypi,v2-touchscreen-panel-regulator"; ++ reg = <0x45>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gt911: gt911@5d { ++ compatible = "goodix,gt911"; ++ reg = <0x5d>; ++ AVDD28-supply = <&touch_reg>; ++ touchscreen-size-x = <720>; ++ touchscreen-size-y = <1280>; ++ touchscreen-x-mm = <90>; ++ touchscreen-y-mm = <151>; ++ }; ++ }; ++ }; ++ ++ dsi_frag: fragment@1 { ++ target = <&dsi1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ port { ++ dsi_out: endpoint { ++ remote-endpoint = <&panel_in>; ++ }; ++ }; ++ ++ dsi_panel: dsi_panel@0 { ++ reg = <0>; ++ compatible = "raspberrypi,dsi-7inch"; ++ reset-gpio = <&display_mcu 0 GPIO_ACTIVE_LOW>; ++ backlight = <&display_mcu>; ++ ++ port { ++ panel_in: endpoint { ++ remote-endpoint = <&dsi_out>; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@4 { ++ target-path = "/"; ++ __overlay__ { ++ touch_reg: touch_reg@1 { ++ reg = <1>; ++ compatible = "regulator-fixed"; ++ regulator-name = "touch_reg_1"; ++ gpio = <&display_mcu 1 GPIO_ACTIVE_HIGH>; ++ startup-delay-us = <50000>; ++ enable-active-high; ++ }; ++ }; ++ }; ++ ++ fragment@10 { ++ target = <>911>; ++ __dormant__ { ++ touchscreen-inverted-x; ++ }; ++ }; ++ ++ fragment@11 { ++ target = <>911>; ++ __dormant__ { ++ touchscreen-inverted-y; ++ }; ++ }; ++ ++ __overrides__ { ++ dsi0 = <&dsi_frag>, "target:0=",<&dsi0>, ++ <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&touch_reg>, "reg:0=0", ++ <&touch_reg>, "regulator-name=touch_reg_0"; ++ sizex = <>911>,"touchscreen-size-x:0"; ++ sizey = <>911>,"touchscreen-size-y:0"; ++ invx = <0>, "+10"; ++ invy = <0>, "+11"; ++ swapxy = <>911>,"touchscreen-swapped-x-y?"; ++ disable_touch = <>911>, "status=disabled"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dsi-lt070me05000-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dsi-lt070me05000-overlay.dts @@ -35235,6 +49706,138 @@ + }; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts +new file mode 100644 +index 000000000000..dfc92726d1bc +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts +@@ -0,0 +1,126 @@ ++/* ++ * Device Tree overlay for Waveshare DSI Touchscreens ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ dsi_frag: fragment@0 { ++ target = <&dsi1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ port { ++ dsi_out: endpoint { ++ remote-endpoint = <&panel_in>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/"; ++ __overlay__ { ++ }; ++ }; ++ ++ i2c_frag: fragment@2 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ panel: panel_disp1@45 { ++ reg = <0x45>; ++ compatible = "waveshare,10.1inch-panel"; ++ ++ port { ++ panel_in: endpoint { ++ remote-endpoint = <&dsi_out>; ++ }; ++ }; ++ }; ++ ++ touch: goodix@14 { ++ reg = <0x14>; ++ compatible = "goodix,gt911"; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@5 { ++ target = <&i2c_arm>; ++ __dormant__ { ++ status = "okay"; ++ }; ++ }; ++ ++ __overrides__ { ++ 2_8_inch = <&panel>, "compatible=waveshare,2.8inch-panel", ++ <&touch>, "touchscreen-size-x:0=480", ++ <&touch>, "touchscreen-size-y:0=640", ++ <&touch>, "touchscreen-inverted-y?", ++ <&touch>, "touchscreen-swapped-x-y?"; ++ 3_4_inch = <&panel>, "compatible=waveshare,3.4inch-panel", ++ <&touch>, "touchscreen-size-x:0=800", ++ <&touch>, "touchscreen-size-y:0=800"; ++ 4_0_inch = <&panel>, "compatible=waveshare,4.0inch-panel", ++ <&touch>, "touchscreen-size-x:0=800", ++ <&touch>, "touchscreen-size-y:0=480", ++ <&touch>, "touchscreen-inverted-x?", ++ <&touch>, "touchscreen-swapped-x-y?"; ++ 7_0_inchC = <&panel>, "compatible=waveshare,7.0inch-c-panel", ++ <&touch>, "touchscreen-size-x:0=800", ++ <&touch>, "touchscreen-size-y:0=480"; ++ 7_9_inch = <&panel>, "compatible=waveshare,7.9inch-panel", ++ <&touch>, "touchscreen-size-x:0=4096", ++ <&touch>, "touchscreen-size-y:0=4096", ++ <&touch>, "touchscreen-inverted-x?", ++ <&touch>, "touchscreen-swapped-x-y?"; ++ 8_0_inch = <&panel>, "compatible=waveshare,8.0inch-panel", ++ <&touch>, "touchscreen-size-x:0=800", ++ <&touch>, "touchscreen-size-y:0=1280", ++ <&touch>, "touchscreen-inverted-x?", ++ <&touch>, "touchscreen-swapped-x-y?"; ++ 10_1_inch = <&panel>, "compatible=waveshare,10.1inch-panel", ++ <&touch>, "touchscreen-size-x:0=800", ++ <&touch>, "touchscreen-size-y:0=1280", ++ <&touch>, "touchscreen-inverted-x?", ++ <&touch>, "touchscreen-swapped-x-y?"; ++ 11_9_inch = <&panel>, "compatible=waveshare,11.9inch-panel", ++ <&touch>, "touchscreen-inverted-x?", ++ <&touch>, "touchscreen-swapped-x-y?"; ++ 4_0_inchC = <&panel>, "compatible=waveshare,4inch-panel", ++ <&touch>, "touchscreen-size-x:0=720", ++ <&touch>, "touchscreen-size-y:0=720"; ++ i2c1 = <&i2c_frag>, "target:0=",<&i2c1>, ++ <0>, "-3-4+5"; ++ disable_touch = <&touch>, "status=disabled"; ++ rotation = <&panel>, "rotation:0"; ++ invx = <&touch>,"touchscreen-inverted-x?"; ++ invy = <&touch>,"touchscreen-inverted-y?"; ++ swapxy = <&touch>,"touchscreen-swapped-x-y?"; ++ dsi0 = <&dsi_frag>, "target:0=",<&dsi0>, ++ <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/vc4-kms-kippah-7inch-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-kippah-7inch-overlay.dts new file mode 100644 index 000000000000..4c1aa1c70158 @@ -35269,10 +49872,10 @@ +}; diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts new file mode 100644 -index 000000000000..351fc160e803 +index 000000000000..26a5bd71945d --- /dev/null +++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts -@@ -0,0 +1,123 @@ +@@ -0,0 +1,124 @@ +/* + * vc4-kms-v3d-overlay.dts + */ @@ -35384,9 +49987,9 @@ + }; + + fragment@14 { -+ target = <&audio>; ++ target = <&chosen>; + __overlay__ { -+ brcm,disable-hdmi; ++ bootargs = "snd_bcm2835.enable_hdmi=0"; + }; + }; + @@ -35394,14 +49997,15 @@ + audio = <0>,"!13"; + noaudio = <0>,"=13"; + composite = <0>, "=11"; ++ nohdmi = <0>, "-1-7"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi4-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi4-overlay.dts new file mode 100644 -index 000000000000..76229cad7803 +index 000000000000..c1e53e3ed575 --- /dev/null +++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi4-overlay.dts -@@ -0,0 +1,197 @@ +@@ -0,0 +1,200 @@ +/* + * vc4-kms-v3d-pi4-overlay.dts + */ @@ -35414,7 +50018,7 @@ +#include "cma-overlay.dts" + +&frag0 { -+ size = <((320-4)*1024*1024)>; ++ size = <((512-4)*1024*1024)>; +}; + +/ { @@ -35547,9 +50151,9 @@ + }; + + fragment@19 { -+ target = <&audio>; ++ target-path = "/chosen"; + __overlay__ { -+ brcm,disable-hdmi; ++ bootargs = "snd_bcm2835.enable_hdmi=0"; + }; + }; + @@ -35597,44 +50201,200 @@ + <0>, "!16", + <0>, "=21", + <0>, "=22"; ++ nohdmi0 = <0>, "-1-3-8"; ++ nohdmi1 = <0>, "-2-4-10"; ++ nohdmi = <0>, "-1-2-3-4-8-10"; + }; +}; -diff --git a/arch/arm/boot/dts/overlays/vc4-kms-vga666-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-vga666-overlay.dts +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi5-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi5-overlay.dts new file mode 100644 -index 000000000000..6e787099e861 +index 000000000000..3e976b18e2f1 --- /dev/null -+++ b/arch/arm/boot/dts/overlays/vc4-kms-vga666-overlay.dts -@@ -0,0 +1,100 @@ -+/* -+ * 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. -+ */ ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi5-overlay.dts +@@ -0,0 +1,147 @@ ++// SPDX-License-Identifier: GPL-2.0 + -+/dts-v1/; -+/plugin/; ++#include "cma-overlay.dts" + -+#include <dt-bindings/pinctrl/bcm2835.h> ++&frag0 { ++ size = <((320-4)*1024*1024)>; ++}; + +/ { -+ compatible = "brcm,bcm2835"; ++ compatible = "brcm,bcm2712"; + -+ fragment@0 { -+ target-path = "/"; ++ fragment@1 { ++ target = <&fb>; + __overlay__ { -+ vga_connector: vga_connector { -+ compatible = "vga-connector"; -+ label = "vga"; ++ status = "disabled"; ++ }; ++ }; + -+ port { -+ vga_con_in: endpoint { -+ remote-endpoint = <&vga666_out>; -+ }; -+ }; -+ }; ++ fragment@2 { ++ target = <&aon_intr>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&ddc0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&ddc1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@5 { ++ target = <&hdmi0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@6 { ++ target = <&hdmi1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@7 { ++ target = <&hvs>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@8 { ++ target = <&mop>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@9 { ++ target = <&moplet>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@10 { ++ target = <&pixelvalve0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@11 { ++ target = <&pixelvalve1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@12 { ++ target = <&v3d>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@13 { ++ target = <&vec>; ++ frag13: __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@14 { ++ target = <&hdmi0>; ++ __dormant__ { ++ dmas; ++ }; ++ }; ++ ++ fragment@15 { ++ target = <&hdmi1>; ++ __dormant__ { ++ dmas; ++ }; ++ }; ++ ++ fragment@16 { ++ target = <&disp_intr>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@17 { ++ target = <&vc4>; ++ __overlay__ { ++ /* IOMMU attaches here, where we allocate DMA buffers */ ++ iommus = <&iommu4>; ++ }; ++ }; ++ ++ __overrides__ { ++ audio = <0>,"!14"; ++ audio1 = <0>,"!15"; ++ noaudio = <0>,"=14", <0>,"=15"; ++ composite = <0>, "!3", ++ <0>, "!4", ++ <0>, "!5", ++ <0>, "!6", ++ <0>, "!10", ++ <0>, "!11", ++ <&frag13>, "status"; ++ nohdmi0 = <0>, "-3-5-10"; ++ nohdmi1 = <0>, "-4-6-11"; ++ nohdmi = <0>, "-3-4-5-6-10-11"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-vga666-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-vga666-overlay.dts +new file mode 100644 +index 000000000000..c3a682d5b7d9 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/vc4-kms-vga666-overlay.dts +@@ -0,0 +1,107 @@ ++/* ++ * 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"; @@ -35701,8 +50461,15 @@ + }; + }; + ++ fragment@5 { ++ target = <&i2c_vc>; ++ __dormant__ { ++ status = "okay"; ++ }; ++ }; ++ + __overrides__ { -+ ddc = <0>,"=2", <0>,"=3", <0>,"=4"; ++ ddc = <0>,"=2", <0>,"=3", <0>,"=4", <0>,"=5"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/vga666-overlay.dts b/arch/arm/boot/dts/overlays/vga666-overlay.dts @@ -35811,6 +50578,27 @@ + pullup; // Silently ignore unneeded parameter + }; +}; +diff --git a/arch/arm/boot/dts/overlays/w1-gpio-pi5-overlay.dts b/arch/arm/boot/dts/overlays/w1-gpio-pi5-overlay.dts +new file mode 100644 +index 000000000000..a408d3d62d40 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/w1-gpio-pi5-overlay.dts +@@ -0,0 +1,15 @@ ++/dts-v1/; ++/plugin/; ++ ++#include "w1-gpio-overlay.dts" ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@2 { ++ target = <&w1>; ++ __overlay__ { ++ raspberrypi,delay-needs-poll; ++ }; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts b/arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts new file mode 100644 index 000000000000..953c6a1aeab9 @@ -35859,6 +50647,27 @@ + pullup; // Silently ignore unneeded parameter + }; +}; +diff --git a/arch/arm/boot/dts/overlays/w1-gpio-pullup-pi5-overlay.dts b/arch/arm/boot/dts/overlays/w1-gpio-pullup-pi5-overlay.dts +new file mode 100644 +index 000000000000..9d1fffb7e87c +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/w1-gpio-pullup-pi5-overlay.dts +@@ -0,0 +1,15 @@ ++/dts-v1/; ++/plugin/; ++ ++#include "w1-gpio-pullup-overlay.dts" ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@2 { ++ target = <&w1>; ++ __overlay__ { ++ raspberrypi,delay-needs-poll; ++ }; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/w5500-overlay.dts b/arch/arm/boot/dts/overlays/w5500-overlay.dts new file mode 100644 index 000000000000..4d3e66296753 @@ -35928,6 +50737,417 @@ + <0>, "!0=1"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/watterott-display-overlay.dts b/arch/arm/boot/dts/overlays/watterott-display-overlay.dts +new file mode 100644 +index 000000000000..4388706d2c38 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/watterott-display-overlay.dts +@@ -0,0 +1,150 @@ ++/* ++ * 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>; ++ }; ++ }; ++ }; ++ ++ fragment@10 { ++ target = <&rpidisplay>; ++ __dormant__ { ++ backlight = <&backlight_gpio>; ++ }; ++ }; ++ ++ fragment@11 { ++ target-path = "/"; ++ __dormant__ { ++ backlight_gpio: backlight_gpio { ++ compatible = "gpio-backlight"; ++ gpios = <&gpio 18 0>; /* GPIO_ACTIVE_HIGH */ ++ }; ++ }; ++ }; ++ ++ fragment@20 { ++ target = <&rpidisplay>; ++ __dormant__ { ++ backlight = <&backlight_pwm>; ++ }; ++ }; ++ ++ fragment@21 { ++ target-path = "/"; ++ __dormant__ { ++ backlight_pwm: backlight_pwm { ++ compatible = "pwm-backlight"; ++ brightness-levels = <0 6 8 12 16 24 32 40 48 64 96 128 160 192 224 255>; ++ default-brightness-level = <16>; ++ pwms = <&pwm 0 200000 0>; ++ }; ++ }; ++ }; ++ ++ fragment@22 { ++ target = <&pwm>; ++ __dormant__ { ++ assigned-clock-rates = <1000000>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@23 { ++ target = <&chosen>; ++ __dormant__ { ++ bootargs = "snd_bcm2835.enable_headphones=0"; ++ }; ++ }; ++ ++ __overrides__ { ++ speed = <&rpidisplay>,"spi-max-frequency:0"; ++ rotate = <&rpidisplay>,"rotate:0", /* fbtft */ ++ <&rpidisplay>,"rotation:0"; /* drm */ ++ 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"; ++ drm = <&rpidisplay>, "compatible=multi-inno,mi0283qt", ++ <&rpidisplay>, "spi-max-frequency:0=70000000", ++ <&rpidisplay>, "reset-gpios:8=0", /* GPIO_ACTIVE_HIGH */ ++ <0>, "+10+11"; ++ backlight-pwm = <0>, "-10-11+20+21+22+23", ++ <&rpi_display_pins>, "brcm,function:0=2"; /* Alt5 */ ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/waveshare-can-fd-hat-mode-a-overlay.dts b/arch/arm/boot/dts/overlays/waveshare-can-fd-hat-mode-a-overlay.dts +new file mode 100644 +index 000000000000..59388cc3b0b9 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/waveshare-can-fd-hat-mode-a-overlay.dts +@@ -0,0 +1,140 @@ ++// redo: ovmerge -c spi1-1cs-overlay.dts,cs0_pin=26,cs0_spidev=false mcp251xfd-overlay.dts,spi0-0,interrupt=25 mcp251xfd-overlay.dts,spi1-0,interrupt=16 ++ ++// Device tree overlay for https://www.waveshare.com/2-ch-can-fd-hat.htm ++// in "Mode A" (default) configuration ++// for details see https://www.waveshare.com/wiki/2-CH_CAN_FD_HAT ++ ++/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 = <26>; ++ 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 26 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 = <16>; ++ 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 = <16 IRQ_TYPE_LEVEL_LOW>; ++ clocks = <&clk_mcp251xfd_osc_1>; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/waveshare-can-fd-hat-mode-b-overlay.dts b/arch/arm/boot/dts/overlays/waveshare-can-fd-hat-mode-b-overlay.dts +new file mode 100644 +index 000000000000..b2504922c8de +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/waveshare-can-fd-hat-mode-b-overlay.dts +@@ -0,0 +1,103 @@ ++// redo: ovmerge -c mcp251xfd-overlay.dts,spi0-0,interrupt=25 mcp251xfd-overlay.dts,spi0-1,interrupt=16 ++ ++// Device tree overlay for https://www.waveshare.com/2-ch-can-fd-hat.htm ++// in "Mode B" (requried hardware modification) configuration ++// for details see https://www.waveshare.com/wiki/2-CH_CAN_FD_HAT ++ ++ ++/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 = <16>; ++ 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 = <16 IRQ_TYPE_LEVEL_LOW>; ++ clocks = <&clk_mcp251xfd_osc_1>; ++ }; ++ }; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/wittypi-overlay.dts b/arch/arm/boot/dts/overlays/wittypi-overlay.dts new file mode 100644 index 000000000000..71ce806186de @@ -35980,7 +51200,7 @@ +}; diff --git a/arch/arm/boot/dts/overlays/wm8960-soundcard-overlay.dts b/arch/arm/boot/dts/overlays/wm8960-soundcard-overlay.dts new file mode 100644 -index 000000000000..289fa4dacdf1 +index 000000000000..3dd0b384079d --- /dev/null +++ b/arch/arm/boot/dts/overlays/wm8960-soundcard-overlay.dts @@ -0,0 +1,82 @@ @@ -35992,7 +51212,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { -+ target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; @@ -36051,7 +51271,7 @@ + "RINPUT2", "Mic Jack"; + + simple-audio-card,cpu { -+ sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + }; + dailink0_slave: simple-audio-card,codec { + sound-dai = <&wm8960>; @@ -36068,10 +51288,10 @@ +}; diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig new file mode 100644 -index 000000000000..f2074da8a80d +index 000000000000..a45c2db93d69 --- /dev/null +++ b/arch/arm/configs/bcm2709_defconfig -@@ -0,0 +1,1533 @@ +@@ -0,0 +1,1583 @@ +CONFIG_LOCALVERSION="-v7" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y @@ -36079,6 +51299,7 @@ +CONFIG_GENERIC_IRQ_DEBUGFS=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y ++CONFIG_BPF_SYSCALL=y +CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y @@ -36086,6 +51307,8 @@ +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y ++CONFIG_PSI=y ++CONFIG_PSI_DEFAULT_DISABLED=y +CONFIG_IKCONFIG=m +CONFIG_IKCONFIG_PROC=y +CONFIG_MEMCG=y @@ -36102,9 +51325,7 @@ +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_EXPERT=y +CONFIG_PROFILING=y +CONFIG_ARCH_BCM=y +CONFIG_ARCH_BCM2835=y @@ -36130,31 +51351,28 @@ +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_MODULE_COMPRESS_XZ=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_COMPAT_BRK is not set ++CONFIG_CMA=y ++CONFIG_LRU_GEN=y ++CONFIG_LRU_GEN_ENABLED=y +CONFIG_NET=y +CONFIG_PACKET=y -+CONFIG_UNIX=y +CONFIG_XFRM_USER=y ++CONFIG_XFRM_INTERFACE=m ++CONFIG_XFRM_SUB_POLICY=y ++CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=m -+CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y @@ -36197,7 +51415,6 @@ +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 @@ -36218,7 +51435,6 @@ +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 @@ -36226,16 +51442,17 @@ +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_XFRM=m +CONFIG_NFT_SOCKET=m +CONFIG_NFT_OSF=m +CONFIG_NFT_TPROXY=m ++CONFIG_NFT_SYNPROXY=m +CONFIG_NFT_DUP_NETDEV=m +CONFIG_NFT_FWD_NETDEV=m +CONFIG_NFT_FIB_NETDEV=m @@ -36312,6 +51529,7 @@ +CONFIG_IP_SET_HASH_NETIFACE=m +CONFIG_IP_SET_LIST_SET=m +CONFIG_IP_VS=m ++CONFIG_IP_VS_IPV6=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y @@ -36332,8 +51550,8 @@ +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_NF_LOG_IPV4=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m @@ -36346,7 +51564,6 @@ +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 @@ -36355,7 +51572,6 @@ +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 @@ -36379,7 +51595,6 @@ +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 @@ -36416,10 +51631,8 @@ +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 @@ -36428,7 +51641,6 @@ +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 @@ -36443,13 +51655,10 @@ +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 @@ -36487,13 +51696,6 @@ +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_CAN_PEAK_USB=m +CONFIG_BT=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y @@ -36517,7 +51719,6 @@ +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 @@ -36525,21 +51726,22 @@ +CONFIG_UEVENT_HELPER=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y ++CONFIG_RASPBERRYPI_FIRMWARE=y +CONFIG_MTD=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK2MTD=m ++CONFIG_MTD_SPI_NAND=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_EEPROM_AT25=m +CONFIG_TI_ST=m +CONFIG_SCSI=y +# CONFIG_SCSI_PROC_FS is not set @@ -36550,6 +51752,7 @@ +CONFIG_SCSI_ISCSI_ATTRS=y +CONFIG_ISCSI_TCP=m +CONFIG_ISCSI_BOOT_SYSFS=m ++CONFIG_ATA=m +CONFIG_MD=y +CONFIG_MD_LINEAR=m +CONFIG_BLK_DEV_DM=m @@ -36561,7 +51764,9 @@ +CONFIG_DM_LOG_USERSPACE=m +CONFIG_DM_RAID=m +CONFIG_DM_ZERO=m ++CONFIG_DM_MULTIPATH=m +CONFIG_DM_DELAY=m ++CONFIG_DM_INTEGRITY=m +CONFIG_NETDEVICES=y +CONFIG_BONDING=m +CONFIG_DUMMY=m @@ -36579,6 +51784,14 @@ +CONFIG_QCA7000_UART=m +CONFIG_WIZNET_W5100=m +CONFIG_WIZNET_W5100_SPI=m ++CONFIG_CAN_VCAN=m ++CONFIG_CAN_SLCAN=m ++CONFIG_CAN_MCP251X=m ++CONFIG_CAN_MCP251XFD=m ++CONFIG_CAN_8DEV_USB=m ++CONFIG_CAN_EMS_USB=m ++CONFIG_CAN_GS_USB=m ++CONFIG_CAN_PEAK_USB=m +CONFIG_MDIO_BITBANG=m +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m @@ -36658,6 +51871,7 @@ +CONFIG_MT7601U=m +CONFIG_MT76x0U=m +CONFIG_MT76x2U=m ++CONFIG_MT7921U=m +CONFIG_RT2X00=m +CONFIG_RT2500USB=m +CONFIG_RT73USB=m @@ -36669,11 +51883,15 @@ +CONFIG_RTL8187=m +CONFIG_RTL8192CU=m +CONFIG_RTL8XXXU=m ++CONFIG_RTW88=m ++CONFIG_RTW88_8822BU=m ++CONFIG_RTW88_8822CU=m ++CONFIG_RTW88_8723DU=m ++CONFIG_RTW88_8821CU=m +CONFIG_USB_ZD1201=m +CONFIG_ZD1211RW=m -+CONFIG_MAC80211_HWSIM=m +CONFIG_USB_NET_RNDIS_WLAN=m -+CONFIG_WIMAX_I2400M_USB=m ++CONFIG_MAC80211_HWSIM=m +CONFIG_IEEE802154_AT86RF230=m +CONFIG_IEEE802154_MRF24J40=m +CONFIG_IEEE802154_CC2520=m @@ -36695,6 +51913,7 @@ +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_PSXPAD_SPI=m +CONFIG_JOYSTICK_PSXPAD_SPI_FF=y ++CONFIG_JOYSTICK_FSIA6B=m +CONFIG_JOYSTICK_RPISENSE=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m @@ -36705,7 +51924,10 @@ +CONFIG_TOUCHSCREEN_EDT_FT5X06=m +CONFIG_TOUCHSCREEN_RASPBERRYPI_FW=m +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m ++CONFIG_TOUCHSCREEN_TSC2007=m ++CONFIG_TOUCHSCREEN_TSC2007_IIO=y +CONFIG_TOUCHSCREEN_STMPE=m ++CONFIG_TOUCHSCREEN_IQS5XX=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_AD714X=m +CONFIG_INPUT_ATI_REMOTE2=m @@ -36720,11 +51942,8 @@ +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 @@ -36743,10 +51962,10 @@ +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_RANDOM_TRUST_BOOTLOADER=y ++CONFIG_TCG_TIS_I2C=m ++CONFIG_RASPBERRYPI_GPIOMEM=m +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_MUX_GPMUX=m @@ -36764,23 +51983,23 @@ +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_MAX7300=m +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_MAX7301=m +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 @@ -36800,24 +52019,30 @@ +CONFIG_RPI_POE_POWER=m +CONFIG_BATTERY_DS2760=m +CONFIG_BATTERY_MAX17040=m ++CONFIG_CHARGER_GPIO=m +CONFIG_BATTERY_GAUGE_LTC2941=m ++CONFIG_SENSORS_ADT7410=m ++CONFIG_SENSORS_AHT10=m ++CONFIG_SENSORS_DRIVETEMP=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_PWM_FAN=m +CONFIG_SENSORS_RASPBERRYPI_HWMON=m -+CONFIG_SENSORS_RPI_POE_FAN=m +CONFIG_SENSORS_SHT21=m +CONFIG_SENSORS_SHT3x=m ++CONFIG_SENSORS_SHT4x=m +CONFIG_SENSORS_SHTC1=m ++CONFIG_SENSORS_EMC2305=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_RASPBERRYPI_POE_HAT=m +CONFIG_MFD_STMPE=y +CONFIG_STMPE_SPI=y +CONFIG_MFD_ARIZONA_I2C=m @@ -36828,40 +52053,38 @@ +CONFIG_REGULATOR_ARIZONA_LDO1=m +CONFIG_REGULATOR_ARIZONA_MICSUPP=m +CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY=m ++CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_V2=m +CONFIG_RC_CORE=y -+CONFIG_LIRC=y +CONFIG_BPF_LIRC_MODE2=y ++CONFIG_LIRC=y +CONFIG_RC_DECODERS=y ++CONFIG_IR_IMON_DECODER=m ++CONFIG_IR_JVC_DECODER=m ++CONFIG_IR_MCE_KBD_DECODER=m +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_SONY_DECODER=m +CONFIG_IR_XMP_DECODER=m -+CONFIG_IR_IMON_DECODER=m +CONFIG_RC_DEVICES=y -+CONFIG_RC_ATI_REMOTE=m ++CONFIG_IR_GPIO_CIR=m ++CONFIG_IR_GPIO_TX=m ++CONFIG_IR_IGUANA=m +CONFIG_IR_IMON=m +CONFIG_IR_MCEUSB=m ++CONFIG_IR_PWM_TX=m +CONFIG_IR_REDRAT3=m +CONFIG_IR_STREAMZAP=m -+CONFIG_IR_IGUANA=m ++CONFIG_IR_TOY=m +CONFIG_IR_TTUSBIR=m ++CONFIG_RC_ATI_REMOTE=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=m +CONFIG_USB_GSPCA_BENQ=m +CONFIG_USB_GSPCA_CONEX=m +CONFIG_USB_GSPCA_CPIA1=m @@ -36886,13 +52109,13 @@ +CONFIG_USB_GSPCA_SN9C20X=m +CONFIG_USB_GSPCA_SONIXB=m +CONFIG_USB_GSPCA_SONIXJ=m ++CONFIG_USB_GSPCA_SPCA1528=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 @@ -36902,56 +52125,32 @@ +CONFIG_USB_GSPCA_SUNPLUS=m +CONFIG_USB_GSPCA_T613=m +CONFIG_USB_GSPCA_TOPRO=m ++CONFIG_USB_GSPCA_TOUPTEK=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_GL860=m ++CONFIG_USB_M5602=m ++CONFIG_USB_STV06XX=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_USB_VIDEO_CLASS=m +CONFIG_VIDEO_GO7007=m +CONFIG_VIDEO_GO7007_USB=m +CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m ++CONFIG_VIDEO_HDPVR=m ++CONFIG_VIDEO_PVRUSB2=m ++CONFIG_VIDEO_STK1160=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_AS102=m ++CONFIG_DVB_B2C2_FLEXCOP_USB=m +CONFIG_DVB_USB_V2=m +CONFIG_DVB_USB_AF9015=m +CONFIG_DVB_USB_AF9035=m @@ -36959,68 +52158,113 @@ +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_AZ6007=m +CONFIG_DVB_USB_CE6230=m ++CONFIG_DVB_USB_DVBSKY=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_DVB_USB=m ++CONFIG_DVB_USB_A800=m ++CONFIG_DVB_USB_AF9005=m ++CONFIG_DVB_USB_AF9005_REMOTE=m ++CONFIG_DVB_USB_AZ6027=m ++CONFIG_DVB_USB_CINERGY_T2=m ++CONFIG_DVB_USB_CXUSB=m ++CONFIG_DVB_USB_DIB0700=m ++CONFIG_DVB_USB_DIBUSB_MB=m ++CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y ++CONFIG_DVB_USB_DIBUSB_MC=m ++CONFIG_DVB_USB_DIGITV=m ++CONFIG_DVB_USB_DTT200U=m ++CONFIG_DVB_USB_DTV5100=m ++CONFIG_DVB_USB_DW2102=m ++CONFIG_DVB_USB_GP8PSK=m ++CONFIG_DVB_USB_M920X=m ++CONFIG_DVB_USB_NOVA_T_USB2=m ++CONFIG_DVB_USB_OPERA1=m ++CONFIG_DVB_USB_PCTV452E=m ++CONFIG_DVB_USB_TECHNISAT_USB2=m ++CONFIG_DVB_USB_TTUSB2=m ++CONFIG_DVB_USB_UMT_010=m ++CONFIG_DVB_USB_VP702X=m ++CONFIG_DVB_USB_VP7045=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_SAA7706H=m +CONFIG_RADIO_SHARK=m +CONFIG_RADIO_SHARK2=m -+CONFIG_USB_KEENE=m -+CONFIG_USB_MA901=m ++CONFIG_RADIO_SI4713=m +CONFIG_RADIO_TEA5764=m -+CONFIG_RADIO_SAA7706H=m +CONFIG_RADIO_TEF6862=m +CONFIG_RADIO_WL1273=m ++CONFIG_USB_DSBR=m ++CONFIG_USB_KEENE=m ++CONFIG_USB_MA901=m ++CONFIG_USB_MR800=m ++CONFIG_RADIO_SI470X=m ++CONFIG_USB_SI470X=m ++CONFIG_I2C_SI470X=m ++CONFIG_I2C_SI4713=m +CONFIG_RADIO_WL128X=m +CONFIG_V4L_PLATFORM_DRIVERS=y ++CONFIG_VIDEO_MUX=m +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_ARDUCAM_64MP=m ++CONFIG_VIDEO_ARDUCAM_PIVARIETY=m +CONFIG_VIDEO_IMX219=m ++CONFIG_VIDEO_IMX258=m +CONFIG_VIDEO_IMX290=m ++CONFIG_VIDEO_IMX296=m +CONFIG_VIDEO_IMX477=m +CONFIG_VIDEO_IMX519=m ++CONFIG_VIDEO_IMX708=m ++CONFIG_VIDEO_MT9V011=m ++CONFIG_VIDEO_OV2311=m +CONFIG_VIDEO_OV5647=m ++CONFIG_VIDEO_OV64A40=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV7640=m -+CONFIG_VIDEO_OV9281=m ++CONFIG_VIDEO_OV9282=m ++CONFIG_VIDEO_AD5398=m ++CONFIG_VIDEO_AK7375=m ++CONFIG_VIDEO_BU64754=m ++CONFIG_VIDEO_DW9807_VCM=m ++CONFIG_VIDEO_SONY_BTF_MPX=m ++CONFIG_VIDEO_UDA1342=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_IRS1125=m -+CONFIG_VIDEO_MT9V011=m ++CONFIG_VIDEO_I2C=m ++CONFIG_AUXDISPLAY=y ++CONFIG_HD44780=m +CONFIG_DRM=m +CONFIG_DRM_LOAD_EDID_FIRMWARE=y +CONFIG_DRM_UDL=m +CONFIG_DRM_PANEL_SIMPLE=m ++CONFIG_DRM_PANEL_ILITEK_ILI9806E=m +CONFIG_DRM_PANEL_JDI_LT070ME05000=m +CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m ++CONFIG_DRM_PANEL_SITRONIX_ST7701=m ++CONFIG_DRM_PANEL_TPO_Y17P=m ++CONFIG_DRM_PANEL_WAVESHARE_TOUCHSCREEN=m +CONFIG_DRM_DISPLAY_CONNECTOR=m +CONFIG_DRM_SIMPLE_BRIDGE=m +CONFIG_DRM_TOSHIBA_TC358762=m +CONFIG_DRM_VC4=m +CONFIG_DRM_VC4_HDMI_CEC=y ++CONFIG_DRM_PANEL_MIPI_DBI=m ++CONFIG_TINYDRM_HX8357D=m +CONFIG_TINYDRM_ILI9225=m +CONFIG_TINYDRM_ILI9341=m ++CONFIG_TINYDRM_ILI9486=m +CONFIG_TINYDRM_MI0283QT=m +CONFIG_TINYDRM_REPAPER=m +CONFIG_TINYDRM_ST7586=m @@ -37028,13 +52272,13 @@ +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_PWM=m +CONFIG_BACKLIGHT_RPI=m ++CONFIG_BACKLIGHT_LM3630A=m +CONFIG_BACKLIGHT_GPIO=m -+CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set @@ -37044,6 +52288,7 @@ +CONFIG_SND_OSSEMUL=y +CONFIG_SND_PCM_OSS=m +CONFIG_SND_HRTIMER=m ++CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_DUMMY=m @@ -37098,6 +52343,7 @@ +CONFIG_SND_BCM2708_SOC_ALLO_KATANA_DAC=m +CONFIG_SND_BCM2708_SOC_FE_PI_AUDIO=m +CONFIG_SND_PISOUND=m ++CONFIG_SND_DACBERRY400=m +CONFIG_SND_SOC_AD193X_SPI=m +CONFIG_SND_SOC_AD193X_I2C=m +CONFIG_SND_SOC_ADAU1701=m @@ -37108,6 +52354,7 @@ +CONFIG_SND_SOC_MA120X0P=m +CONFIG_SND_SOC_MAX98357A=m +CONFIG_SND_SOC_SPDIF=m ++CONFIG_SND_SOC_TLV320AIC23_I2C=m +CONFIG_SND_SOC_WM8804_I2C=m +CONFIG_SND_SOC_WM8960=m +CONFIG_SND_SIMPLE_CARD=m @@ -37148,11 +52395,15 @@ +CONFIG_HID_MICROSOFT=m +CONFIG_HID_MONTEREY=m +CONFIG_HID_MULTITOUCH=m ++CONFIG_HID_NINTENDO=m ++CONFIG_NINTENDO_FF=y +CONFIG_HID_NTRIG=m +CONFIG_HID_ORTEK=m +CONFIG_HID_PANTHERLORD=m +CONFIG_HID_PETALYNX=m +CONFIG_HID_PICOLCD=m ++CONFIG_HID_PLAYSTATION=m ++CONFIG_PLAYSTATION_FF=y +CONFIG_HID_ROCCAT=m +CONFIG_HID_SAMSUNG=m +CONFIG_HID_SONY=m @@ -37172,7 +52423,6 @@ +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 @@ -37241,7 +52491,6 @@ +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 @@ -37259,7 +52508,6 @@ +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 @@ -37272,7 +52520,8 @@ +CONFIG_USB_CXACRU=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_XUSBATM=m -+CONFIG_USB_GADGET=m ++CONFIG_NOP_USB_XCEIV=y ++CONFIG_USB_GADGET=y +CONFIG_USB_CONFIGFS=m +CONFIG_USB_CONFIGFS_SERIAL=y +CONFIG_USB_CONFIGFS_ACM=y @@ -37313,6 +52562,7 @@ +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SPI=m +CONFIG_LEDS_CLASS=y ++CONFIG_LEDS_CLASS_MULTICOLOR=m +CONFIG_LEDS_PCA9532=m +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_PCA955X=m @@ -37324,7 +52574,6 @@ +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 @@ -37359,6 +52608,8 @@ +CONFIG_RTC_DRV_RX8025=m +CONFIG_RTC_DRV_EM3027=m +CONFIG_RTC_DRV_RV3028=m ++CONFIG_RTC_DRV_RV3032=m ++CONFIG_RTC_DRV_RV8803=m +CONFIG_RTC_DRV_SD3078=m +CONFIG_RTC_DRV_M41T93=m +CONFIG_RTC_DRV_M41T94=m @@ -37379,16 +52630,14 @@ +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_STAGING_MEDIA_DEPRECATED=y +CONFIG_FB_TFT=m +CONFIG_FB_TFT_AGM1264K_FL=m +CONFIG_FB_TFT_BD663474=m @@ -37416,9 +52665,9 @@ +CONFIG_FB_TFT_ST7789V=m +CONFIG_FB_TFT_TINYLCD=m +CONFIG_FB_TFT_TLS8204=m ++CONFIG_FB_TFT_UC1611=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 @@ -37429,32 +52678,40 @@ +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_IIO_SW_TRIGGER=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_SPS30_I2C=m +CONFIG_MAX30102=m +CONFIG_DHT11=m +CONFIG_HDC100X=m +CONFIG_HTU21=m ++CONFIG_SI7020=m ++CONFIG_BOSCH_BNO055_I2C=m +CONFIG_INV_MPU6050_I2C=m +CONFIG_APDS9960=m +CONFIG_BH1750=m +CONFIG_TSL4531=m +CONFIG_VEML6070=m ++CONFIG_IIO_HRTIMER_TRIGGER=m ++CONFIG_IIO_INTERRUPT_TRIGGER=m ++CONFIG_IIO_SYSFS_TRIGGER=m +CONFIG_BMP280=m ++CONFIG_MS5637=m +CONFIG_MAXIM_THERMOCOUPLE=m +CONFIG_MAX31856=m ++CONFIG_PWM=y +CONFIG_PWM_BCM2835=m +CONFIG_PWM_PCA9685=m ++CONFIG_PWM_RASPBERRYPI_POE=m +CONFIG_RPI_AXIPERF=m ++CONFIG_MUX_GPIO=m +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y @@ -37481,13 +52738,12 @@ +CONFIG_FANOTIFY=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m -+CONFIG_AUTOFS4_FS=y ++CONFIG_AUTOFS_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 @@ -37499,6 +52755,7 @@ +CONFIG_EXFAT_FS=m +CONFIG_NTFS_FS=m +CONFIG_NTFS_RW=y ++CONFIG_NTFS3_FS=m +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ECRYPT_FS=m @@ -37511,6 +52768,9 @@ +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y ++CONFIG_PSTORE=y ++CONFIG_PSTORE_CONSOLE=y ++CONFIG_PSTORE_RAM=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y @@ -37520,14 +52780,17 @@ +CONFIG_ROOT_NFS=y +CONFIG_NFS_FSCACHE=y +CONFIG_NFSD=m ++CONFIG_NFSD_V2=y ++CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y ++CONFIG_CEPH_FS=m +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_SMB_SERVER=m +CONFIG_9P_FS=m +CONFIG_9P_FS_POSIX_ACL=y +CONFIG_NLS_DEFAULT="utf8" @@ -37569,29 +52832,37 @@ +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_DLM=m ++CONFIG_KEY_DH_OPERATIONS=y +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_TWOFISH=m ++CONFIG_CRYPTO_ADIANTUM=m ++CONFIG_CRYPTO_CHACHA20POLY1305=m ++CONFIG_CRYPTO_MD4=m ++CONFIG_CRYPTO_SHA512=m ++CONFIG_CRYPTO_WP512=m ++CONFIG_CRYPTO_XCBC=m +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_SHA1_ARM_NEON=m ++CONFIG_CRYPTO_AES_ARM=m ++CONFIG_CRYPTO_AES_ARM_BS=m +# CONFIG_CRYPTO_HW is not set ++CONFIG_PKCS8_PRIVATE_KEY_PARSER=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_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1f6 +CONFIG_KGDB=y +CONFIG_KGDB_KDB=y +CONFIG_KDB_KEYBOARD=y @@ -37601,16 +52872,15 @@ +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 --git a/arch/arm/configs/bcm2711_defconfig b/arch/arm/configs/bcm2711_defconfig new file mode 100644 -index 000000000000..8f4ae82cade4 +index 000000000000..2bf13fd55bed --- /dev/null +++ b/arch/arm/configs/bcm2711_defconfig -@@ -0,0 +1,1557 @@ +@@ -0,0 +1,1610 @@ +CONFIG_LOCALVERSION="-v7l" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y @@ -37618,6 +52888,7 @@ +CONFIG_GENERIC_IRQ_DEBUGFS=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y ++CONFIG_BPF_SYSCALL=y +CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y @@ -37625,6 +52896,8 @@ +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y ++CONFIG_PSI=y ++CONFIG_PSI_DEFAULT_DISABLED=y +CONFIG_IKCONFIG=m +CONFIG_IKCONFIG_PROC=y +CONFIG_MEMCG=y @@ -37641,9 +52914,7 @@ +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_EXPERT=y +CONFIG_PROFILING=y +CONFIG_ARCH_BCM=y +CONFIG_ARCH_BCM2835=y @@ -37669,32 +52940,28 @@ +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_MODULE_COMPRESS_XZ=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_COMPAT_BRK is not set ++CONFIG_CMA=y ++CONFIG_LRU_GEN=y +CONFIG_NET=y +CONFIG_PACKET=y -+CONFIG_UNIX=y +CONFIG_XFRM_USER=y ++CONFIG_XFRM_INTERFACE=m ++CONFIG_XFRM_SUB_POLICY=y ++CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=m -+CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y @@ -37734,10 +53001,10 @@ +CONFIG_IPV6_MROUTE=y +CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y +CONFIG_IPV6_PIMSM_V2=y ++CONFIG_NETWORK_PHY_TIMESTAMPING=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 @@ -37758,7 +53025,6 @@ +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 @@ -37766,16 +53032,17 @@ +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_XFRM=m +CONFIG_NFT_SOCKET=m +CONFIG_NFT_OSF=m +CONFIG_NFT_TPROXY=m ++CONFIG_NFT_SYNPROXY=m +CONFIG_NFT_DUP_NETDEV=m +CONFIG_NFT_FWD_NETDEV=m +CONFIG_NFT_FIB_NETDEV=m @@ -37852,6 +53119,7 @@ +CONFIG_IP_SET_HASH_NETIFACE=m +CONFIG_IP_SET_LIST_SET=m +CONFIG_IP_VS=m ++CONFIG_IP_VS_IPV6=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y @@ -37872,8 +53140,8 @@ +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_NF_LOG_IPV4=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m @@ -37886,7 +53154,6 @@ +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 @@ -37895,7 +53162,6 @@ +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 @@ -37919,7 +53185,6 @@ +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 @@ -37956,10 +53221,8 @@ +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 @@ -37968,7 +53231,6 @@ +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 @@ -37983,13 +53245,10 @@ +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 @@ -38027,13 +53286,6 @@ +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_CAN_PEAK_USB=m +CONFIG_BT=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y @@ -38057,7 +53309,6 @@ +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 @@ -38070,22 +53321,23 @@ +CONFIG_UEVENT_HELPER=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y ++CONFIG_RASPBERRYPI_FIRMWARE=y +CONFIG_MTD=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK2MTD=m ++CONFIG_MTD_SPI_NAND=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_EEPROM_AT25=m +CONFIG_TI_ST=m +CONFIG_SCSI=y +# CONFIG_SCSI_PROC_FS is not set @@ -38106,11 +53358,14 @@ +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_THIN_PROVISIONING=m +CONFIG_DM_CACHE=m ++CONFIG_DM_WRITECACHE=m +CONFIG_DM_MIRROR=m +CONFIG_DM_LOG_USERSPACE=m +CONFIG_DM_RAID=m +CONFIG_DM_ZERO=m ++CONFIG_DM_MULTIPATH=m +CONFIG_DM_DELAY=m ++CONFIG_DM_INTEGRITY=m +CONFIG_NETDEVICES=y +CONFIG_BONDING=m +CONFIG_DUMMY=m @@ -38125,12 +53380,21 @@ +CONFIG_NET_VRF=m +CONFIG_BCMGENET=y +CONFIG_ENC28J60=m ++CONFIG_LAN743X=m +CONFIG_QCA7000_SPI=m +CONFIG_QCA7000_UART=m +CONFIG_R8169=m +CONFIG_WIZNET_W5100=m +CONFIG_WIZNET_W5100_SPI=m +CONFIG_MICREL_PHY=y ++CONFIG_CAN_VCAN=m ++CONFIG_CAN_SLCAN=m ++CONFIG_CAN_MCP251X=m ++CONFIG_CAN_MCP251XFD=m ++CONFIG_CAN_8DEV_USB=m ++CONFIG_CAN_EMS_USB=m ++CONFIG_CAN_GS_USB=m ++CONFIG_CAN_PEAK_USB=m +CONFIG_MDIO_BITBANG=m +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m @@ -38210,6 +53474,7 @@ +CONFIG_MT7601U=m +CONFIG_MT76x0U=m +CONFIG_MT76x2U=m ++CONFIG_MT7921U=m +CONFIG_RT2X00=m +CONFIG_RT2500USB=m +CONFIG_RT73USB=m @@ -38221,11 +53486,15 @@ +CONFIG_RTL8187=m +CONFIG_RTL8192CU=m +CONFIG_RTL8XXXU=m ++CONFIG_RTW88=m ++CONFIG_RTW88_8822BU=m ++CONFIG_RTW88_8822CU=m ++CONFIG_RTW88_8723DU=m ++CONFIG_RTW88_8821CU=m +CONFIG_USB_ZD1201=m +CONFIG_ZD1211RW=m -+CONFIG_MAC80211_HWSIM=m +CONFIG_USB_NET_RNDIS_WLAN=m -+CONFIG_WIMAX_I2400M_USB=m ++CONFIG_MAC80211_HWSIM=m +CONFIG_IEEE802154_AT86RF230=m +CONFIG_IEEE802154_MRF24J40=m +CONFIG_IEEE802154_CC2520=m @@ -38247,6 +53516,7 @@ +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_PSXPAD_SPI=m +CONFIG_JOYSTICK_PSXPAD_SPI_FF=y ++CONFIG_JOYSTICK_FSIA6B=m +CONFIG_JOYSTICK_RPISENSE=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m @@ -38257,7 +53527,10 @@ +CONFIG_TOUCHSCREEN_EDT_FT5X06=m +CONFIG_TOUCHSCREEN_RASPBERRYPI_FW=m +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m ++CONFIG_TOUCHSCREEN_TSC2007=m ++CONFIG_TOUCHSCREEN_TSC2007_IIO=y +CONFIG_TOUCHSCREEN_STMPE=m ++CONFIG_TOUCHSCREEN_IQS5XX=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_AD714X=m +CONFIG_INPUT_ATI_REMOTE2=m @@ -38272,18 +53545,14 @@ +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_NR_UARTS=5 +CONFIG_SERIAL_8250_RUNTIME_UARTS=0 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_SHARE_IRQ=y @@ -38296,10 +53565,13 @@ +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_RANDOM_TRUST_BOOTLOADER=y ++CONFIG_TCG_TIS_I2C=m ++CONFIG_XILLYBUS=m ++CONFIG_XILLYBUS_PCIE=m ++CONFIG_XILLYUSB=m ++CONFIG_RASPBERRYPI_GPIOMEM=m +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_MUX_GPMUX=m @@ -38317,23 +53589,23 @@ +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_MAX7300=m +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_MAX7301=m +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 @@ -38353,24 +53625,30 @@ +CONFIG_RPI_POE_POWER=m +CONFIG_BATTERY_DS2760=m +CONFIG_BATTERY_MAX17040=m ++CONFIG_CHARGER_GPIO=m +CONFIG_BATTERY_GAUGE_LTC2941=m ++CONFIG_SENSORS_ADT7410=m ++CONFIG_SENSORS_AHT10=m ++CONFIG_SENSORS_DRIVETEMP=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_PWM_FAN=m +CONFIG_SENSORS_RASPBERRYPI_HWMON=m -+CONFIG_SENSORS_RPI_POE_FAN=m +CONFIG_SENSORS_SHT21=m +CONFIG_SENSORS_SHT3x=m ++CONFIG_SENSORS_SHT4x=m +CONFIG_SENSORS_SHTC1=m ++CONFIG_SENSORS_EMC2305=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_RASPBERRYPI_POE_HAT=m +CONFIG_MFD_STMPE=y +CONFIG_STMPE_SPI=y +CONFIG_MFD_ARIZONA_I2C=m @@ -38382,40 +53660,38 @@ +CONFIG_REGULATOR_ARIZONA_MICSUPP=m +CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY=m ++CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_V2=m +CONFIG_RC_CORE=y -+CONFIG_LIRC=y +CONFIG_BPF_LIRC_MODE2=y ++CONFIG_LIRC=y +CONFIG_RC_DECODERS=y ++CONFIG_IR_IMON_DECODER=m ++CONFIG_IR_JVC_DECODER=m ++CONFIG_IR_MCE_KBD_DECODER=m +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_SONY_DECODER=m +CONFIG_IR_XMP_DECODER=m -+CONFIG_IR_IMON_DECODER=m +CONFIG_RC_DEVICES=y -+CONFIG_RC_ATI_REMOTE=m ++CONFIG_IR_GPIO_CIR=m ++CONFIG_IR_GPIO_TX=m ++CONFIG_IR_IGUANA=m +CONFIG_IR_IMON=m +CONFIG_IR_MCEUSB=m ++CONFIG_IR_PWM_TX=m +CONFIG_IR_REDRAT3=m +CONFIG_IR_STREAMZAP=m -+CONFIG_IR_IGUANA=m ++CONFIG_IR_TOY=m +CONFIG_IR_TTUSBIR=m ++CONFIG_RC_ATI_REMOTE=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=m +CONFIG_USB_GSPCA_BENQ=m +CONFIG_USB_GSPCA_CONEX=m +CONFIG_USB_GSPCA_CPIA1=m @@ -38440,13 +53716,13 @@ +CONFIG_USB_GSPCA_SN9C20X=m +CONFIG_USB_GSPCA_SONIXB=m +CONFIG_USB_GSPCA_SONIXJ=m ++CONFIG_USB_GSPCA_SPCA1528=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 @@ -38456,56 +53732,32 @@ +CONFIG_USB_GSPCA_SUNPLUS=m +CONFIG_USB_GSPCA_T613=m +CONFIG_USB_GSPCA_TOPRO=m ++CONFIG_USB_GSPCA_TOUPTEK=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_GL860=m ++CONFIG_USB_M5602=m ++CONFIG_USB_STV06XX=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_USB_VIDEO_CLASS=m +CONFIG_VIDEO_GO7007=m +CONFIG_VIDEO_GO7007_USB=m +CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m ++CONFIG_VIDEO_HDPVR=m ++CONFIG_VIDEO_PVRUSB2=m ++CONFIG_VIDEO_STK1160=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_AS102=m ++CONFIG_DVB_B2C2_FLEXCOP_USB=m +CONFIG_DVB_USB_V2=m +CONFIG_DVB_USB_AF9015=m +CONFIG_DVB_USB_AF9035=m @@ -38513,70 +53765,115 @@ +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_AZ6007=m +CONFIG_DVB_USB_CE6230=m ++CONFIG_DVB_USB_DVBSKY=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_DVB_USB=m ++CONFIG_DVB_USB_A800=m ++CONFIG_DVB_USB_AF9005=m ++CONFIG_DVB_USB_AF9005_REMOTE=m ++CONFIG_DVB_USB_AZ6027=m ++CONFIG_DVB_USB_CINERGY_T2=m ++CONFIG_DVB_USB_CXUSB=m ++CONFIG_DVB_USB_DIB0700=m ++CONFIG_DVB_USB_DIBUSB_MB=m ++CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y ++CONFIG_DVB_USB_DIBUSB_MC=m ++CONFIG_DVB_USB_DIGITV=m ++CONFIG_DVB_USB_DTT200U=m ++CONFIG_DVB_USB_DTV5100=m ++CONFIG_DVB_USB_DW2102=m ++CONFIG_DVB_USB_GP8PSK=m ++CONFIG_DVB_USB_M920X=m ++CONFIG_DVB_USB_NOVA_T_USB2=m ++CONFIG_DVB_USB_OPERA1=m ++CONFIG_DVB_USB_PCTV452E=m ++CONFIG_DVB_USB_TECHNISAT_USB2=m ++CONFIG_DVB_USB_TTUSB2=m ++CONFIG_DVB_USB_UMT_010=m ++CONFIG_DVB_USB_VP702X=m ++CONFIG_DVB_USB_VP7045=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_SAA7706H=m +CONFIG_RADIO_SHARK=m +CONFIG_RADIO_SHARK2=m -+CONFIG_USB_KEENE=m -+CONFIG_USB_MA901=m ++CONFIG_RADIO_SI4713=m +CONFIG_RADIO_TEA5764=m -+CONFIG_RADIO_SAA7706H=m +CONFIG_RADIO_TEF6862=m +CONFIG_RADIO_WL1273=m ++CONFIG_USB_DSBR=m ++CONFIG_USB_KEENE=m ++CONFIG_USB_MA901=m ++CONFIG_USB_MR800=m ++CONFIG_RADIO_SI470X=m ++CONFIG_USB_SI470X=m ++CONFIG_I2C_SI470X=m ++CONFIG_I2C_SI4713=m +CONFIG_RADIO_WL128X=m +CONFIG_V4L_PLATFORM_DRIVERS=y ++CONFIG_VIDEO_MUX=m +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_ARDUCAM_64MP=m ++CONFIG_VIDEO_ARDUCAM_PIVARIETY=m +CONFIG_VIDEO_IMX219=m ++CONFIG_VIDEO_IMX258=m +CONFIG_VIDEO_IMX290=m ++CONFIG_VIDEO_IMX296=m +CONFIG_VIDEO_IMX477=m +CONFIG_VIDEO_IMX519=m ++CONFIG_VIDEO_IMX708=m ++CONFIG_VIDEO_MT9V011=m ++CONFIG_VIDEO_OV2311=m +CONFIG_VIDEO_OV5647=m ++CONFIG_VIDEO_OV64A40=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV7640=m -+CONFIG_VIDEO_OV9281=m ++CONFIG_VIDEO_OV9282=m ++CONFIG_VIDEO_AD5398=m ++CONFIG_VIDEO_AK7375=m ++CONFIG_VIDEO_BU64754=m ++CONFIG_VIDEO_DW9807_VCM=m ++CONFIG_VIDEO_SONY_BTF_MPX=m ++CONFIG_VIDEO_UDA1342=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_IRS1125=m -+CONFIG_VIDEO_MT9V011=m ++CONFIG_VIDEO_I2C=m ++CONFIG_AUXDISPLAY=y ++CONFIG_HD44780=m +CONFIG_DRM=m +CONFIG_DRM_LOAD_EDID_FIRMWARE=y +CONFIG_DRM_UDL=m +CONFIG_DRM_PANEL_SIMPLE=m ++CONFIG_DRM_PANEL_ILITEK_ILI9806E=m +CONFIG_DRM_PANEL_ILITEK_ILI9881C=m +CONFIG_DRM_PANEL_JDI_LT070ME05000=m +CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m ++CONFIG_DRM_PANEL_SITRONIX_ST7701=m ++CONFIG_DRM_PANEL_TPO_Y17P=m ++CONFIG_DRM_PANEL_WAVESHARE_TOUCHSCREEN=m +CONFIG_DRM_DISPLAY_CONNECTOR=m +CONFIG_DRM_SIMPLE_BRIDGE=m +CONFIG_DRM_TOSHIBA_TC358762=m +CONFIG_DRM_V3D=m +CONFIG_DRM_VC4=m +CONFIG_DRM_VC4_HDMI_CEC=y ++CONFIG_DRM_PANEL_MIPI_DBI=m ++CONFIG_TINYDRM_HX8357D=m +CONFIG_TINYDRM_ILI9225=m +CONFIG_TINYDRM_ILI9341=m ++CONFIG_TINYDRM_ILI9486=m +CONFIG_TINYDRM_MI0283QT=m +CONFIG_TINYDRM_REPAPER=m +CONFIG_TINYDRM_ST7586=m @@ -38584,14 +53881,13 @@ +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_PWM=m +CONFIG_BACKLIGHT_RPI=m ++CONFIG_BACKLIGHT_LM3630A=m +CONFIG_BACKLIGHT_GPIO=m -+CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set @@ -38601,6 +53897,7 @@ +CONFIG_SND_OSSEMUL=y +CONFIG_SND_PCM_OSS=m +CONFIG_SND_HRTIMER=m ++CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_DUMMY=m @@ -38655,6 +53952,7 @@ +CONFIG_SND_BCM2708_SOC_ALLO_KATANA_DAC=m +CONFIG_SND_BCM2708_SOC_FE_PI_AUDIO=m +CONFIG_SND_PISOUND=m ++CONFIG_SND_DACBERRY400=m +CONFIG_SND_SOC_AD193X_SPI=m +CONFIG_SND_SOC_AD193X_I2C=m +CONFIG_SND_SOC_ADAU1701=m @@ -38665,6 +53963,7 @@ +CONFIG_SND_SOC_MA120X0P=m +CONFIG_SND_SOC_MAX98357A=m +CONFIG_SND_SOC_SPDIF=m ++CONFIG_SND_SOC_TLV320AIC23_I2C=m +CONFIG_SND_SOC_WM8804_I2C=m +CONFIG_SND_SOC_WM8960=m +CONFIG_SND_SIMPLE_CARD=m @@ -38705,11 +54004,15 @@ +CONFIG_HID_MICROSOFT=m +CONFIG_HID_MONTEREY=m +CONFIG_HID_MULTITOUCH=m ++CONFIG_HID_NINTENDO=m ++CONFIG_NINTENDO_FF=y +CONFIG_HID_NTRIG=m +CONFIG_HID_ORTEK=m +CONFIG_HID_PANTHERLORD=m +CONFIG_HID_PETALYNX=m +CONFIG_HID_PICOLCD=m ++CONFIG_HID_PLAYSTATION=m ++CONFIG_PLAYSTATION_FF=y +CONFIG_HID_ROCCAT=m +CONFIG_HID_SAMSUNG=m +CONFIG_HID_SONY=m @@ -38729,7 +54032,6 @@ +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 @@ -38800,7 +54102,6 @@ +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 @@ -38818,7 +54119,6 @@ +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 @@ -38874,6 +54174,7 @@ +CONFIG_MMC_SDHCI_IPROC=y +CONFIG_MMC_SPI=m +CONFIG_LEDS_CLASS=y ++CONFIG_LEDS_CLASS_MULTICOLOR=m +CONFIG_LEDS_PCA9532=m +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_PCA955X=m @@ -38885,7 +54186,6 @@ +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 @@ -38920,6 +54220,8 @@ +CONFIG_RTC_DRV_RX8025=m +CONFIG_RTC_DRV_EM3027=m +CONFIG_RTC_DRV_RV3028=m ++CONFIG_RTC_DRV_RV3032=m ++CONFIG_RTC_DRV_RV8803=m +CONFIG_RTC_DRV_SD3078=m +CONFIG_RTC_DRV_M41T93=m +CONFIG_RTC_DRV_M41T94=m @@ -38940,17 +54242,15 @@ +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_STAGING_MEDIA_DEPRECATED=y +CONFIG_FB_TFT=m +CONFIG_FB_TFT_AGM1264K_FL=m +CONFIG_FB_TFT_BD663474=m @@ -38978,9 +54278,9 @@ +CONFIG_FB_TFT_ST7789V=m +CONFIG_FB_TFT_TINYLCD=m +CONFIG_FB_TFT_TLS8204=m ++CONFIG_FB_TFT_UC1611=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 @@ -38991,32 +54291,41 @@ +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_IIO_SW_TRIGGER=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_SPS30_I2C=m +CONFIG_MAX30102=m +CONFIG_DHT11=m +CONFIG_HDC100X=m +CONFIG_HTU21=m ++CONFIG_SI7020=m ++CONFIG_BOSCH_BNO055_I2C=m +CONFIG_INV_MPU6050_I2C=m +CONFIG_APDS9960=m +CONFIG_BH1750=m +CONFIG_TSL4531=m +CONFIG_VEML6070=m ++CONFIG_IIO_HRTIMER_TRIGGER=m ++CONFIG_IIO_INTERRUPT_TRIGGER=m ++CONFIG_IIO_SYSFS_TRIGGER=m +CONFIG_BMP280=m ++CONFIG_MS5637=m +CONFIG_MAXIM_THERMOCOUPLE=m +CONFIG_MAX31856=m ++CONFIG_PWM=y +CONFIG_PWM_BCM2835=m +CONFIG_PWM_PCA9685=m ++CONFIG_PWM_RASPBERRYPI_POE=m +CONFIG_RPI_AXIPERF=m +CONFIG_NVMEM_RMEM=m ++CONFIG_MUX_GPIO=m +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y @@ -39043,13 +54352,12 @@ +CONFIG_FANOTIFY=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m -+CONFIG_AUTOFS4_FS=y ++CONFIG_AUTOFS_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 @@ -39061,6 +54369,7 @@ +CONFIG_EXFAT_FS=m +CONFIG_NTFS_FS=m +CONFIG_NTFS_RW=y ++CONFIG_NTFS3_FS=m +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ECRYPT_FS=m @@ -39073,6 +54382,9 @@ +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y ++CONFIG_PSTORE=y ++CONFIG_PSTORE_CONSOLE=y ++CONFIG_PSTORE_RAM=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y @@ -39082,15 +54394,18 @@ +CONFIG_ROOT_NFS=y +CONFIG_NFS_FSCACHE=y +CONFIG_NFSD=m ++CONFIG_NFSD_V2=y ++CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y ++CONFIG_CEPH_FS=m +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_SMB_SERVER=m +CONFIG_9P_FS=m +CONFIG_9P_FS_POSIX_ACL=y +CONFIG_NLS_DEFAULT="utf8" @@ -39132,29 +54447,38 @@ +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_DLM=m ++CONFIG_KEY_DH_OPERATIONS=y +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_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_DES=y ++CONFIG_CRYPTO_TWOFISH=m ++CONFIG_CRYPTO_ADIANTUM=m ++CONFIG_CRYPTO_CHACHA20POLY1305=m ++CONFIG_CRYPTO_MD4=m ++CONFIG_CRYPTO_SHA512=m ++CONFIG_CRYPTO_WP512=m ++CONFIG_CRYPTO_XCBC=m +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_SHA1_ARM_NEON=m ++CONFIG_CRYPTO_AES_ARM=m ++CONFIG_CRYPTO_AES_ARM_BS=m +# CONFIG_CRYPTO_HW is not set ++CONFIG_PKCS8_PRIVATE_KEY_PARSER=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_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1f6 +CONFIG_KGDB=y +CONFIG_KGDB_KDB=y +CONFIG_KDB_KEYBOARD=y @@ -39164,22 +54488,22 @@ +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 --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig new file mode 100644 -index 000000000000..b3ea44509d98 +index 000000000000..1c1ffb4ae498 --- /dev/null +++ b/arch/arm/configs/bcmrpi_defconfig -@@ -0,0 +1,1528 @@ +@@ -0,0 +1,1576 @@ +# 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_BPF_SYSCALL=y +CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y @@ -39187,6 +54511,8 @@ +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y ++CONFIG_PSI=y ++CONFIG_PSI_DEFAULT_DISABLED=y +CONFIG_IKCONFIG=m +CONFIG_IKCONFIG_PROC=y +CONFIG_MEMCG=y @@ -39202,9 +54528,7 @@ +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_EXPERT=y +CONFIG_PROFILING=y +CONFIG_ARCH_MULTI_V6=y +# CONFIG_ARCH_MULTI_V7 is not set @@ -39227,30 +54551,28 @@ +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_MODULE_COMPRESS_XZ=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_COMPAT_BRK is not set ++CONFIG_CMA=y ++CONFIG_LRU_GEN=y ++CONFIG_LRU_GEN_ENABLED=y +CONFIG_NET=y +CONFIG_PACKET=y -+CONFIG_UNIX=y +CONFIG_XFRM_USER=y ++CONFIG_XFRM_INTERFACE=m ++CONFIG_XFRM_SUB_POLICY=y ++CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=m -+CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y @@ -39293,7 +54615,6 @@ +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 @@ -39314,7 +54635,6 @@ +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 @@ -39322,16 +54642,17 @@ +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_XFRM=m +CONFIG_NFT_SOCKET=m +CONFIG_NFT_OSF=m +CONFIG_NFT_TPROXY=m ++CONFIG_NFT_SYNPROXY=m +CONFIG_NFT_DUP_NETDEV=m +CONFIG_NFT_FWD_NETDEV=m +CONFIG_NFT_FIB_NETDEV=m @@ -39408,6 +54729,7 @@ +CONFIG_IP_SET_HASH_NETIFACE=m +CONFIG_IP_SET_LIST_SET=m +CONFIG_IP_VS=m ++CONFIG_IP_VS_IPV6=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y @@ -39428,8 +54750,8 @@ +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_NF_LOG_IPV4=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m @@ -39442,7 +54764,6 @@ +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 @@ -39451,7 +54772,6 @@ +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 @@ -39475,7 +54795,6 @@ +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 @@ -39512,10 +54831,8 @@ +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 @@ -39524,7 +54841,6 @@ +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 @@ -39539,13 +54855,10 @@ +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 @@ -39583,13 +54896,6 @@ +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_CAN_PEAK_USB=m +CONFIG_BT=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y @@ -39613,7 +54919,6 @@ +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 @@ -39621,21 +54926,22 @@ +CONFIG_UEVENT_HELPER=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y ++CONFIG_RASPBERRYPI_FIRMWARE=y +CONFIG_MTD=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK2MTD=m ++CONFIG_MTD_SPI_NAND=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_EEPROM_AT25=m +CONFIG_TI_ST=m +CONFIG_SCSI=y +# CONFIG_SCSI_PROC_FS is not set @@ -39646,6 +54952,7 @@ +CONFIG_SCSI_ISCSI_ATTRS=y +CONFIG_ISCSI_TCP=m +CONFIG_ISCSI_BOOT_SYSFS=m ++CONFIG_ATA=m +CONFIG_MD=y +CONFIG_MD_LINEAR=m +CONFIG_BLK_DEV_DM=m @@ -39657,7 +54964,9 @@ +CONFIG_DM_LOG_USERSPACE=m +CONFIG_DM_RAID=m +CONFIG_DM_ZERO=m ++CONFIG_DM_MULTIPATH=m +CONFIG_DM_DELAY=m ++CONFIG_DM_INTEGRITY=m +CONFIG_NETDEVICES=y +CONFIG_BONDING=m +CONFIG_DUMMY=m @@ -39675,6 +54984,14 @@ +CONFIG_QCA7000_UART=m +CONFIG_WIZNET_W5100=m +CONFIG_WIZNET_W5100_SPI=m ++CONFIG_CAN_VCAN=m ++CONFIG_CAN_SLCAN=m ++CONFIG_CAN_MCP251X=m ++CONFIG_CAN_MCP251XFD=m ++CONFIG_CAN_8DEV_USB=m ++CONFIG_CAN_EMS_USB=m ++CONFIG_CAN_GS_USB=m ++CONFIG_CAN_PEAK_USB=m +CONFIG_MDIO_BITBANG=m +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m @@ -39754,6 +55071,7 @@ +CONFIG_MT7601U=m +CONFIG_MT76x0U=m +CONFIG_MT76x2U=m ++CONFIG_MT7921U=m +CONFIG_RT2X00=m +CONFIG_RT2500USB=m +CONFIG_RT73USB=m @@ -39765,11 +55083,15 @@ +CONFIG_RTL8187=m +CONFIG_RTL8192CU=m +CONFIG_RTL8XXXU=m ++CONFIG_RTW88=m ++CONFIG_RTW88_8822BU=m ++CONFIG_RTW88_8822CU=m ++CONFIG_RTW88_8723DU=m ++CONFIG_RTW88_8821CU=m +CONFIG_USB_ZD1201=m +CONFIG_ZD1211RW=m -+CONFIG_MAC80211_HWSIM=m +CONFIG_USB_NET_RNDIS_WLAN=m -+CONFIG_WIMAX_I2400M_USB=m ++CONFIG_MAC80211_HWSIM=m +CONFIG_IEEE802154_AT86RF230=m +CONFIG_IEEE802154_MRF24J40=m +CONFIG_IEEE802154_CC2520=m @@ -39791,6 +55113,7 @@ +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_PSXPAD_SPI=m +CONFIG_JOYSTICK_PSXPAD_SPI_FF=y ++CONFIG_JOYSTICK_FSIA6B=m +CONFIG_JOYSTICK_RPISENSE=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m @@ -39801,7 +55124,10 @@ +CONFIG_TOUCHSCREEN_EDT_FT5X06=m +CONFIG_TOUCHSCREEN_RASPBERRYPI_FW=m +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m ++CONFIG_TOUCHSCREEN_TSC2007=m ++CONFIG_TOUCHSCREEN_TSC2007_IIO=y +CONFIG_TOUCHSCREEN_STMPE=m ++CONFIG_TOUCHSCREEN_IQS5XX=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_AD714X=m +CONFIG_INPUT_ATI_REMOTE2=m @@ -39816,11 +55142,8 @@ +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 @@ -39839,10 +55162,10 @@ +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_RANDOM_TRUST_BOOTLOADER=y ++CONFIG_TCG_TIS_I2C=m ++CONFIG_RASPBERRYPI_GPIOMEM=m +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_MUX_GPMUX=m @@ -39860,22 +55183,22 @@ +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_MAX7300=m +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_MAX7301=m +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 @@ -39895,24 +55218,30 @@ +CONFIG_RPI_POE_POWER=m +CONFIG_BATTERY_DS2760=m +CONFIG_BATTERY_MAX17040=m ++CONFIG_CHARGER_GPIO=m +CONFIG_BATTERY_GAUGE_LTC2941=m ++CONFIG_SENSORS_ADT7410=m ++CONFIG_SENSORS_AHT10=m ++CONFIG_SENSORS_DRIVETEMP=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_PWM_FAN=m +CONFIG_SENSORS_RASPBERRYPI_HWMON=m -+CONFIG_SENSORS_RPI_POE_FAN=m +CONFIG_SENSORS_SHT21=m +CONFIG_SENSORS_SHT3x=m ++CONFIG_SENSORS_SHT4x=m +CONFIG_SENSORS_SHTC1=m ++CONFIG_SENSORS_EMC2305=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_RASPBERRYPI_POE_HAT=m +CONFIG_MFD_STMPE=y +CONFIG_STMPE_SPI=y +CONFIG_MFD_ARIZONA_I2C=m @@ -39923,40 +55252,38 @@ +CONFIG_REGULATOR_ARIZONA_LDO1=m +CONFIG_REGULATOR_ARIZONA_MICSUPP=m +CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY=m ++CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_V2=m +CONFIG_RC_CORE=y -+CONFIG_LIRC=y +CONFIG_BPF_LIRC_MODE2=y ++CONFIG_LIRC=y +CONFIG_RC_DECODERS=y ++CONFIG_IR_IMON_DECODER=m ++CONFIG_IR_JVC_DECODER=m ++CONFIG_IR_MCE_KBD_DECODER=m +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_SONY_DECODER=m +CONFIG_IR_XMP_DECODER=m -+CONFIG_IR_IMON_DECODER=m +CONFIG_RC_DEVICES=y -+CONFIG_RC_ATI_REMOTE=m ++CONFIG_IR_GPIO_CIR=m ++CONFIG_IR_GPIO_TX=m ++CONFIG_IR_IGUANA=m +CONFIG_IR_IMON=m +CONFIG_IR_MCEUSB=m ++CONFIG_IR_PWM_TX=m +CONFIG_IR_REDRAT3=m +CONFIG_IR_STREAMZAP=m -+CONFIG_IR_IGUANA=m ++CONFIG_IR_TOY=m +CONFIG_IR_TTUSBIR=m ++CONFIG_RC_ATI_REMOTE=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=m +CONFIG_USB_GSPCA_BENQ=m +CONFIG_USB_GSPCA_CONEX=m +CONFIG_USB_GSPCA_CPIA1=m @@ -39981,13 +55308,13 @@ +CONFIG_USB_GSPCA_SN9C20X=m +CONFIG_USB_GSPCA_SONIXB=m +CONFIG_USB_GSPCA_SONIXJ=m ++CONFIG_USB_GSPCA_SPCA1528=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 @@ -39997,56 +55324,32 @@ +CONFIG_USB_GSPCA_SUNPLUS=m +CONFIG_USB_GSPCA_T613=m +CONFIG_USB_GSPCA_TOPRO=m ++CONFIG_USB_GSPCA_TOUPTEK=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_GL860=m ++CONFIG_USB_M5602=m ++CONFIG_USB_STV06XX=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_USB_VIDEO_CLASS=m +CONFIG_VIDEO_GO7007=m +CONFIG_VIDEO_GO7007_USB=m +CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m ++CONFIG_VIDEO_HDPVR=m ++CONFIG_VIDEO_PVRUSB2=m ++CONFIG_VIDEO_STK1160=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_AS102=m ++CONFIG_DVB_B2C2_FLEXCOP_USB=m +CONFIG_DVB_USB_V2=m +CONFIG_DVB_USB_AF9015=m +CONFIG_DVB_USB_AF9035=m @@ -40054,68 +55357,113 @@ +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_AZ6007=m +CONFIG_DVB_USB_CE6230=m ++CONFIG_DVB_USB_DVBSKY=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_DVB_USB=m ++CONFIG_DVB_USB_A800=m ++CONFIG_DVB_USB_AF9005=m ++CONFIG_DVB_USB_AF9005_REMOTE=m ++CONFIG_DVB_USB_AZ6027=m ++CONFIG_DVB_USB_CINERGY_T2=m ++CONFIG_DVB_USB_CXUSB=m ++CONFIG_DVB_USB_DIB0700=m ++CONFIG_DVB_USB_DIBUSB_MB=m ++CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y ++CONFIG_DVB_USB_DIBUSB_MC=m ++CONFIG_DVB_USB_DIGITV=m ++CONFIG_DVB_USB_DTT200U=m ++CONFIG_DVB_USB_DTV5100=m ++CONFIG_DVB_USB_DW2102=m ++CONFIG_DVB_USB_GP8PSK=m ++CONFIG_DVB_USB_M920X=m ++CONFIG_DVB_USB_NOVA_T_USB2=m ++CONFIG_DVB_USB_OPERA1=m ++CONFIG_DVB_USB_PCTV452E=m ++CONFIG_DVB_USB_TECHNISAT_USB2=m ++CONFIG_DVB_USB_TTUSB2=m ++CONFIG_DVB_USB_UMT_010=m ++CONFIG_DVB_USB_VP702X=m ++CONFIG_DVB_USB_VP7045=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_SAA7706H=m +CONFIG_RADIO_SHARK=m +CONFIG_RADIO_SHARK2=m -+CONFIG_USB_KEENE=m -+CONFIG_USB_MA901=m ++CONFIG_RADIO_SI4713=m +CONFIG_RADIO_TEA5764=m -+CONFIG_RADIO_SAA7706H=m +CONFIG_RADIO_TEF6862=m +CONFIG_RADIO_WL1273=m ++CONFIG_USB_DSBR=m ++CONFIG_USB_KEENE=m ++CONFIG_USB_MA901=m ++CONFIG_USB_MR800=m ++CONFIG_RADIO_SI470X=m ++CONFIG_USB_SI470X=m ++CONFIG_I2C_SI470X=m ++CONFIG_I2C_SI4713=m +CONFIG_RADIO_WL128X=m +CONFIG_V4L_PLATFORM_DRIVERS=y ++CONFIG_VIDEO_MUX=m +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_ARDUCAM_64MP=m ++CONFIG_VIDEO_ARDUCAM_PIVARIETY=m +CONFIG_VIDEO_IMX219=m ++CONFIG_VIDEO_IMX258=m +CONFIG_VIDEO_IMX290=m ++CONFIG_VIDEO_IMX296=m +CONFIG_VIDEO_IMX477=m +CONFIG_VIDEO_IMX519=m ++CONFIG_VIDEO_IMX708=m ++CONFIG_VIDEO_MT9V011=m ++CONFIG_VIDEO_OV2311=m +CONFIG_VIDEO_OV5647=m ++CONFIG_VIDEO_OV64A40=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV7640=m -+CONFIG_VIDEO_OV9281=m ++CONFIG_VIDEO_OV9282=m ++CONFIG_VIDEO_AD5398=m ++CONFIG_VIDEO_AK7375=m ++CONFIG_VIDEO_BU64754=m ++CONFIG_VIDEO_DW9807_VCM=m ++CONFIG_VIDEO_SONY_BTF_MPX=m ++CONFIG_VIDEO_UDA1342=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_IRS1125=m -+CONFIG_VIDEO_MT9V011=m ++CONFIG_VIDEO_I2C=m ++CONFIG_AUXDISPLAY=y ++CONFIG_HD44780=m +CONFIG_DRM=m +CONFIG_DRM_LOAD_EDID_FIRMWARE=y +CONFIG_DRM_UDL=m +CONFIG_DRM_PANEL_SIMPLE=m ++CONFIG_DRM_PANEL_ILITEK_ILI9806E=m +CONFIG_DRM_PANEL_JDI_LT070ME05000=m +CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m ++CONFIG_DRM_PANEL_SITRONIX_ST7701=m ++CONFIG_DRM_PANEL_TPO_Y17P=m ++CONFIG_DRM_PANEL_WAVESHARE_TOUCHSCREEN=m +CONFIG_DRM_DISPLAY_CONNECTOR=m +CONFIG_DRM_SIMPLE_BRIDGE=m +CONFIG_DRM_TOSHIBA_TC358762=m +CONFIG_DRM_VC4=m +CONFIG_DRM_VC4_HDMI_CEC=y ++CONFIG_DRM_PANEL_MIPI_DBI=m ++CONFIG_TINYDRM_HX8357D=m +CONFIG_TINYDRM_ILI9225=m +CONFIG_TINYDRM_ILI9341=m ++CONFIG_TINYDRM_ILI9486=m +CONFIG_TINYDRM_MI0283QT=m +CONFIG_TINYDRM_REPAPER=m +CONFIG_TINYDRM_ST7586=m @@ -40123,13 +55471,13 @@ +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_PWM=m +CONFIG_BACKLIGHT_RPI=m ++CONFIG_BACKLIGHT_LM3630A=m +CONFIG_BACKLIGHT_GPIO=m -+CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set @@ -40139,6 +55487,7 @@ +CONFIG_SND_OSSEMUL=y +CONFIG_SND_PCM_OSS=m +CONFIG_SND_HRTIMER=m ++CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_DUMMY=m @@ -40203,6 +55552,7 @@ +CONFIG_SND_SOC_MA120X0P=m +CONFIG_SND_SOC_MAX98357A=m +CONFIG_SND_SOC_SPDIF=m ++CONFIG_SND_SOC_TLV320AIC23_I2C=m +CONFIG_SND_SOC_WM8804_I2C=m +CONFIG_SND_SOC_WM8960=m +CONFIG_SND_SIMPLE_CARD=m @@ -40243,11 +55593,15 @@ +CONFIG_HID_MICROSOFT=m +CONFIG_HID_MONTEREY=m +CONFIG_HID_MULTITOUCH=m ++CONFIG_HID_NINTENDO=m ++CONFIG_NINTENDO_FF=y +CONFIG_HID_NTRIG=m +CONFIG_HID_ORTEK=m +CONFIG_HID_PANTHERLORD=m +CONFIG_HID_PETALYNX=m +CONFIG_HID_PICOLCD=m ++CONFIG_HID_PLAYSTATION=m ++CONFIG_PLAYSTATION_FF=y +CONFIG_HID_ROCCAT=m +CONFIG_HID_SAMSUNG=m +CONFIG_HID_SONY=m @@ -40267,7 +55621,6 @@ +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 @@ -40336,7 +55689,6 @@ +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 @@ -40354,7 +55706,6 @@ +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 @@ -40367,7 +55718,8 @@ +CONFIG_USB_CXACRU=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_XUSBATM=m -+CONFIG_USB_GADGET=m ++CONFIG_NOP_USB_XCEIV=y ++CONFIG_USB_GADGET=y +CONFIG_USB_CONFIGFS=m +CONFIG_USB_CONFIGFS_SERIAL=y +CONFIG_USB_CONFIGFS_ACM=y @@ -40408,6 +55760,7 @@ +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SPI=m +CONFIG_LEDS_CLASS=y ++CONFIG_LEDS_CLASS_MULTICOLOR=m +CONFIG_LEDS_PCA9532=m +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_PCA955X=m @@ -40419,7 +55772,6 @@ +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 @@ -40454,6 +55806,8 @@ +CONFIG_RTC_DRV_RX8025=m +CONFIG_RTC_DRV_EM3027=m +CONFIG_RTC_DRV_RV3028=m ++CONFIG_RTC_DRV_RV3032=m ++CONFIG_RTC_DRV_RV8803=m +CONFIG_RTC_DRV_SD3078=m +CONFIG_RTC_DRV_M41T93=m +CONFIG_RTC_DRV_M41T94=m @@ -40474,16 +55828,14 @@ +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_STAGING_MEDIA_DEPRECATED=y +CONFIG_FB_TFT=m +CONFIG_FB_TFT_AGM1264K_FL=m +CONFIG_FB_TFT_BD663474=m @@ -40511,9 +55863,9 @@ +CONFIG_FB_TFT_ST7789V=m +CONFIG_FB_TFT_TINYLCD=m +CONFIG_FB_TFT_TLS8204=m ++CONFIG_FB_TFT_UC1611=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 @@ -40524,32 +55876,40 @@ +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_IIO_SW_TRIGGER=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_SPS30_I2C=m +CONFIG_MAX30102=m +CONFIG_DHT11=m +CONFIG_HDC100X=m +CONFIG_HTU21=m ++CONFIG_SI7020=m ++CONFIG_BOSCH_BNO055_I2C=m +CONFIG_INV_MPU6050_I2C=m +CONFIG_APDS9960=m +CONFIG_BH1750=m +CONFIG_TSL4531=m +CONFIG_VEML6070=m ++CONFIG_IIO_HRTIMER_TRIGGER=m ++CONFIG_IIO_INTERRUPT_TRIGGER=m ++CONFIG_IIO_SYSFS_TRIGGER=m +CONFIG_BMP280=m ++CONFIG_MS5637=m +CONFIG_MAXIM_THERMOCOUPLE=m +CONFIG_MAX31856=m ++CONFIG_PWM=y +CONFIG_PWM_BCM2835=m +CONFIG_PWM_PCA9685=m ++CONFIG_PWM_RASPBERRYPI_POE=m +CONFIG_RPI_AXIPERF=m ++CONFIG_MUX_GPIO=m +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y @@ -40575,13 +55935,12 @@ +CONFIG_FANOTIFY=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m -+CONFIG_AUTOFS4_FS=y ++CONFIG_AUTOFS_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 @@ -40593,6 +55952,7 @@ +CONFIG_EXFAT_FS=m +CONFIG_NTFS_FS=m +CONFIG_NTFS_RW=y ++CONFIG_NTFS3_FS=m +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ECRYPT_FS=m @@ -40605,6 +55965,9 @@ +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y ++CONFIG_PSTORE=y ++CONFIG_PSTORE_CONSOLE=y ++CONFIG_PSTORE_RAM=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y @@ -40614,14 +55977,17 @@ +CONFIG_ROOT_NFS=y +CONFIG_NFS_FSCACHE=y +CONFIG_NFSD=m ++CONFIG_NFSD_V2=y ++CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y ++CONFIG_CEPH_FS=m +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_SMB_SERVER=m +CONFIG_9P_FS=m +CONFIG_9P_FS_POSIX_ACL=y +CONFIG_NLS_DEFAULT="utf8" @@ -40663,33 +56029,39 @@ +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_DLM=m ++CONFIG_KEY_DH_OPERATIONS=y +CONFIG_SECURITY=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_LSM="" +CONFIG_CRYPTO_USER=m +CONFIG_CRYPTO_CRYPTD=m -+CONFIG_CRYPTO_CHACHA20POLY1305=m ++CONFIG_CRYPTO_CAST5=m ++CONFIG_CRYPTO_DES=y ++CONFIG_CRYPTO_TWOFISH=m ++CONFIG_CRYPTO_ADIANTUM=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_CHACHA20POLY1305=m ++CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_WP512=m -+CONFIG_CRYPTO_CAST5=m -+CONFIG_CRYPTO_DES=y ++CONFIG_CRYPTO_XCBC=m +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_SHA1_ARM=m ++CONFIG_CRYPTO_AES_ARM=m +# CONFIG_CRYPTO_HW is not set ++CONFIG_PKCS8_PRIVATE_KEY_PARSER=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_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1f6 +CONFIG_KGDB=y +CONFIG_KGDB_KDB=y +CONFIG_KDB_KEYBOARD=y @@ -40698,24 +56070,11 @@ +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 --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig -index a611b0c1e540..ea2715c9f923 100644 ---- a/arch/arm/configs/multi_v7_defconfig -+++ b/arch/arm/configs/multi_v7_defconfig -@@ -1089,6 +1089,7 @@ CONFIG_ROCKCHIP_EFUSE=m - 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 --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h -index 2e24e765e6d3..3c285a257e89 100644 +index 1075534b0a2e..34c020563133 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -91,6 +91,21 @@ @@ -40826,10 +56185,10 @@ + #endif diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h -index da2a9e5fc59b..5e13b677fadd 100644 +index 2162ebc6c77a..e766a121555a 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h -@@ -509,6 +509,9 @@ do { \ +@@ -500,6 +500,9 @@ do { \ extern unsigned long __must_check arm_copy_from_user(void *to, const void __user *from, unsigned long n); @@ -40840,10 +56199,10 @@ raw_copy_from_user(void *to, const void __user *from, unsigned long n) { diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c -index 91e37dfe0396..6f2cc6978443 100644 +index 9b51562b1f86..d7a1048763a2 100644 --- a/arch/arm/kernel/fiq.c +++ b/arch/arm/kernel/fiq.c -@@ -63,6 +63,8 @@ +@@ -64,6 +64,8 @@ static unsigned long dfl_fiq_insn; static struct pt_regs dfl_fiq_regs; @@ -40852,7 +56211,7 @@ /* Default reacquire function * - we always relinquish FIQ control * - we always reacquire FIQ control -@@ -147,6 +149,8 @@ static int fiq_start; +@@ -148,6 +150,8 @@ static int fiq_start; void enable_fiq(int fiq) { @@ -40874,7 +56233,7 @@ + mov pc, r8 +ENDPROC(__FIQ_Branch) diff --git a/arch/arm/kernel/reboot.c b/arch/arm/kernel/reboot.c -index 0ce388f15422..63373adab475 100644 +index 3f0d5c3dae11..cfdbcc9826c0 100644 --- a/arch/arm/kernel/reboot.c +++ b/arch/arm/kernel/reboot.c @@ -102,9 +102,7 @@ void machine_shutdown(void) @@ -40889,10 +56248,10 @@ /* diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c -index d7ae50b32c7b..fd6e4580d621 100644 +index 5cfc9c5056a7..0ea30401beaa 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c -@@ -1257,6 +1257,8 @@ static int c_show(struct seq_file *m, void *v) +@@ -1277,6 +1277,8 @@ static int c_show(struct seq_file *m, void *v) { int i, j; u32 cpuid; @@ -40901,7 +56260,7 @@ for_each_online_cpu(i) { /* -@@ -1316,6 +1318,14 @@ static int c_show(struct seq_file *m, void *v) +@@ -1336,6 +1338,14 @@ static int c_show(struct seq_file *m, void *v) seq_printf(m, "Revision\t: %04x\n", system_rev); seq_printf(m, "Serial\t\t: %s\n", system_serial); @@ -40917,7 +56276,7 @@ } diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile -index 6d2ba454f25b..8271cde92dec 100644 +index 650404be6768..7fd404d75064 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -7,8 +7,8 @@ @@ -41114,10 +56473,10 @@ +92: +.endm diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S -index f8016e3db65d..ab7bf28dbec0 100644 +index 270de7debd0f..2eda93fc22e6 100644 --- a/arch/arm/lib/copy_from_user.S +++ b/arch/arm/lib/copy_from_user.S -@@ -107,7 +107,8 @@ +@@ -104,7 +104,8 @@ UNWIND( .save {r0, r2, r3, \regs} ) .text @@ -41125,9 +56484,9 @@ +ENTRY(__copy_from_user_std) +WEAK(arm_copy_from_user) #ifdef CONFIG_CPU_SPECTRE - get_thread_info r3 - ldr r3, r3, #TI_ADDR_LIMIT -@@ -117,6 +118,7 @@ ENTRY(arm_copy_from_user) + ldr r3, =TASK_SIZE + uaccess_mask_range_ptr r1, r2, r3, ip +@@ -113,6 +114,7 @@ ENTRY(arm_copy_from_user) #include "copy_template.S" ENDPROC(arm_copy_from_user) @@ -41471,10 +56830,10 @@ +ENDPROC(memcmp) diff --git a/arch/arm/lib/memcpy_rpi.S b/arch/arm/lib/memcpy_rpi.S new file mode 100644 -index 000000000000..77a1dbe28a18 +index 000000000000..d246f9f3903a --- /dev/null +++ b/arch/arm/lib/memcpy_rpi.S -@@ -0,0 +1,63 @@ +@@ -0,0 +1,65 @@ +/* +Copyright (c) 2013, Raspberry Pi Foundation +Copyright (c) 2013, RISC OS Open Ltd @@ -41535,7 +56894,9 @@ + +ENTRY(mmiocpy) +ENTRY(memcpy) ++ENTRY(__memcpy) + memcpy 0 ++ENDPROC(__memcpy) +ENDPROC(memcpy) +ENDPROC(mmiocpy) diff --git a/arch/arm/lib/memcpymove.h b/arch/arm/lib/memcpymove.h @@ -42103,10 +57464,10 @@ +ENDPROC(memmove) diff --git a/arch/arm/lib/memset_rpi.S b/arch/arm/lib/memset_rpi.S new file mode 100644 -index 000000000000..2a2d86759397 +index 000000000000..087d68ea5d18 --- /dev/null +++ b/arch/arm/lib/memset_rpi.S -@@ -0,0 +1,130 @@ +@@ -0,0 +1,132 @@ +/* +Copyright (c) 2013, Raspberry Pi Foundation +Copyright (c) 2013, RISC OS Open Ltd @@ -42161,6 +57522,7 @@ + */ +ENTRY(mmioset) +ENTRY(memset) ++ENTRY(__memset) + + S .req a1 + DAT0 .req a2 @@ -42235,10 +57597,11 @@ + .unreq DAT3 +ENDPROC(__memset64) +ENDPROC(__memset32) ++ENDPROC(__memset) +ENDPROC(memset) +ENDPROC(mmioset) diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c -index 106f83a5ea6d..b483e5713039 100644 +index 2f6163f05e93..f5a5e2e1084a 100644 --- a/arch/arm/lib/uaccess_with_memcpy.c +++ b/arch/arm/lib/uaccess_with_memcpy.c @@ -19,6 +19,14 @@ @@ -42265,7 +57628,7 @@ return 0; /* -@@ -86,7 +94,46 @@ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp) +@@ -89,7 +97,46 @@ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp) return 1; } @@ -42313,7 +57676,7 @@ __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n) { unsigned long ua_flags; -@@ -139,6 +186,57 @@ __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n) +@@ -137,6 +184,52 @@ __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n) return n; } @@ -42323,11 +57686,6 @@ + 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(); + @@ -42371,7 +57729,7 @@ unsigned long arm_copy_to_user(void __user *to, const void *from, unsigned long n) { -@@ -149,7 +247,7 @@ arm_copy_to_user(void __user *to, const void *from, unsigned long n) +@@ -147,7 +240,7 @@ arm_copy_to_user(void __user *to, const void *from, unsigned long n) * With frame pointer disabled, tail call optimization kicks in * as well making this test almost invisible. */ @@ -42380,7 +57738,7 @@ unsigned long ua_flags = uaccess_save_and_enable(); n = __copy_to_user_std(to, from, n); uaccess_restore(ua_flags); -@@ -159,6 +257,32 @@ arm_copy_to_user(void __user *to, const void *from, unsigned long n) +@@ -157,6 +250,32 @@ arm_copy_to_user(void __user *to, const void *from, unsigned long n) } return n; } @@ -42414,14 +57772,13 @@ static unsigned long noinline __clear_user_memset(void __user *addr, unsigned long n) diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig -index ae790908fc74..822125c5707a 100644 +index 8789d93a7c04..d3206a2a257b 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig -@@ -161,9 +161,12 @@ config ARCH_BCM2835 +@@ -159,9 +159,11 @@ config ARCH_BCM2835 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 @@ -42430,10 +57787,27 @@ help This enables support for the Broadcom BCM2711 and BCM283x SoCs. This SoC is used in the Raspberry Pi and Roku 2 devices. -@@ -182,6 +185,13 @@ config ARCH_BCM_53573 +@@ -180,6 +182,30 @@ config ARCH_BCM_53573 The base chip is BCM53573 and there are some packaging modifications like BCM47189 and BCM47452. ++config ARCH_BCM_63XX ++ bool "Broadcom BCM63xx DSL SoC" ++ depends on ARCH_MULTI_V7 ++ select ARCH_HAS_RESET_CONTROLLER ++ select ARM_ERRATA_754322 ++ select ARM_ERRATA_764369 if SMP ++ select ARM_GIC ++ select ARM_GLOBAL_TIMER ++ select CACHE_L2X0 ++ select HAVE_ARM_ARCH_TIMER ++ select HAVE_ARM_TWD if SMP ++ select HAVE_ARM_SCU if SMP ++ help ++ This enables support for systems based on Broadcom DSL SoCs. ++ It currently supports the 'BCM63XX' ARM-based family, which includes ++ the BCM63138 variant. ++ +config BCM2835_FAST_MEMCPY + bool "Enable optimized __copy_to_user and __copy_from_user" + depends on ARCH_BCM2835 && ARCH_MULTI_V6 @@ -42441,8 +57815,8 @@ + help + Optimized versions of __copy_to_user and __copy_from_user for Pi1. + - config ARCH_BCM_63XX - bool "Broadcom BCM63xx DSL SoC" + config ARCH_BRCMSTB + bool "Broadcom BCM7XXX based boards" depends on ARCH_MULTI_V7 diff --git a/arch/arm/mach-bcm/board_bcm2835.c b/arch/arm/mach-bcm/board_bcm2835.c index bfc556f76720..91a758c61f48 100644 @@ -42579,10 +57953,10 @@ + .smp = smp_ops(bcm2836_smp_ops), +MACHINE_END diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S -index f0f65eb073e4..868011801521 100644 +index 250c83bf7158..abae7ff5defc 100644 --- a/arch/arm/mm/cache-v6.S +++ b/arch/arm/mm/cache-v6.S -@@ -198,7 +198,7 @@ ENTRY(v6_flush_kern_dcache_area) +@@ -200,7 +200,7 @@ ENTRY(v6_flush_kern_dcache_area) * - start - virtual start address of region * - end - virtual end address of region */ @@ -42591,7 +57965,7 @@ #ifdef CONFIG_DMA_CACHE_RWFO ldrb r2, r0 @ read for ownership strb r2, r0 @ write for ownership -@@ -243,7 +243,7 @@ v6_dma_inv_range: +@@ -245,7 +245,7 @@ v6_dma_inv_range: * - start - virtual start address of region * - end - virtual end address of region */ @@ -42601,10 +57975,10 @@ 1: #ifdef CONFIG_DMA_CACHE_RWFO diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S -index 307f381eee71..b97282e76bca 100644 +index 127afe2096ba..6a16d88e2d36 100644 --- a/arch/arm/mm/cache-v7.S +++ b/arch/arm/mm/cache-v7.S -@@ -364,7 +364,8 @@ ENDPROC(v7_flush_kern_dcache_area) +@@ -361,7 +361,8 @@ ENDPROC(v7_flush_kern_dcache_area) * - start - virtual start address of region * - end - virtual end address of region */ @@ -42614,7 +57988,7 @@ dcache_line_size r2, r3 sub r3, r2, #1 tst r0, r3 -@@ -394,7 +395,8 @@ ENDPROC(v7_dma_inv_range) +@@ -391,7 +392,8 @@ ENDPROC(v7_dma_inv_range) * - start - virtual start address of region * - end - virtual end address of region */ @@ -42625,7 +57999,7 @@ sub r3, r2, #1 bic r0, r0, r3 diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S -index d9f7dfe2a7ed..687d126d1c6c 100644 +index e43f6d716b4b..05d9b19b6b2e 100644 --- a/arch/arm/mm/proc-macros.S +++ b/arch/arm/mm/proc-macros.S @@ -334,6 +334,8 @@ ENTRY(\name\()_cache_fns) @@ -42652,10 +58026,10 @@ EXPORT_SYMBOL(cpu_cache); #endif diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S -index a0618f3e6836..b3a2fce22eac 100644 +index 203dff89ab1a..9290ae13a5bb 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S -@@ -70,10 +70,19 @@ ENDPROC(cpu_v6_reset) +@@ -72,10 +72,19 @@ ENDPROC(cpu_v6_reset) * * IRQs are already disabled. */ @@ -42679,7 +58053,7 @@ ENTRY(cpu_v6_dcache_clean_area) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c -index 2cb355c1b5b7..1e2dcf81aefa 100644 +index 7e8773a2d99d..a1ff693e49bf 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -176,8 +176,11 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v) @@ -42695,7 +58069,7 @@ #endif /* -@@ -454,13 +457,16 @@ static int vfp_pm_suspend(void) +@@ -451,13 +454,16 @@ static int vfp_pm_suspend(void) /* if vfp is on, then save state for resumption */ if (fpexc & FPEXC_EN) { pr_debug("%s: saving vfp state\n", __func__); @@ -42713,7 +58087,7 @@ vfp_save_state(vfp_current_hw_stateti->cpu, fpexc); fmxr(FPEXC, fpexc); #endif -@@ -523,7 +529,8 @@ void vfp_sync_hwstate(struct thread_info *thread) +@@ -522,7 +528,8 @@ void vfp_sync_hwstate(struct thread_info *thread) /* * Save the last VFP state on this CPU. */ @@ -42746,8 +58120,8 @@ hwstate->fpexc = fpexc; hwstate->fpinst = ufp_exc->fpinst; -@@ -726,7 +738,8 @@ void kernel_neon_begin(void) - cpu = get_cpu(); +@@ -830,7 +842,8 @@ void kernel_neon_begin(void) + cpu = __smp_processor_id(); fpexc = fmrx(FPEXC) | FPEXC_EN; - fmxr(FPEXC, fpexc); @@ -42756,49 +58130,52 @@ /* * Save the userland NEON/VFP state. Under UP, -diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms -index dd6b7466fe28..2a7abe568db7 100644 ---- a/arch/arm64/Kconfig.platforms -+++ b/arch/arm64/Kconfig.platforms -@@ -39,6 +39,7 @@ config ARCH_BCM2835 - 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 --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig +index 8def51744a10..942cc2f5340f 100644 +--- a/arch/arm64/Kconfig ++++ b/arch/arm64/Kconfig +@@ -123,7 +123,8 @@ config ARM64 + select CRC32 + select DCACHE_WORD_ACCESS + select DYNAMIC_FTRACE if FUNCTION_TRACER +- select DMA_BOUNCE_UNALIGNED_KMALLOC ++ # Disable this to save 64MB when DMA controllers can reach all of RAM ++ # select DMA_BOUNCE_UNALIGNED_KMALLOC + select DMA_DIRECT_REMAP + select EDAC_SUPPORT + select FRAME_POINTER diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile -index 9b1170658d60..cc6c25629057 100644 +index 30dd6347a929..a30874eddeae 100644 --- a/arch/arm64/boot/dts/Makefile +++ b/arch/arm64/boot/dts/Makefile -@@ -30,3 +30,5 @@ subdir-y += ti +@@ -33,3 +33,5 @@ subdir-y += tesla + subdir-y += ti subdir-y += toshiba subdir-y += xilinx - subdir-y += zte + +subdir-y += overlays diff --git a/arch/arm64/boot/dts/broadcom/Makefile b/arch/arm64/boot/dts/broadcom/Makefile -index cb7de8d99223..e7c2c4fd59a8 100644 +index 8b4591ddd27c..6dd8659a7d8a 100644 --- a/arch/arm64/boot/dts/broadcom/Makefile +++ b/arch/arm64/boot/dts/broadcom/Makefile -@@ -1,9 +1,21 @@ - # 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 +@@ -12,6 +12,24 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-400.dtb \ + bcm2837-rpi-cm3-io3.dtb \ + bcm2837-rpi-zero-2-w.dtb + +dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-zero-2.dtb ++dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-zero-2-w.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 - ++dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-cm4s.dtb ++dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-5-b.dtb ++dtb-$(CONFIG_ARCH_BCM2835) += bcm2712d0-rpi-5-b.dtb ++dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5-cm5io.dtb ++dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5-cm4io.dtb ++ + subdir-y += bcmbca subdir-y += northstar2 subdir-y += stingray + @@ -42808,61 +58185,92 @@ +endif diff --git a/arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts new file mode 100644 -index 000000000000..36ecea71f0ef +index 000000000000..9b2c0120842a --- /dev/null +++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts @@ -0,0 +1 @@ -+#include "../../../../arm/boot/dts/bcm2710-rpi-2-b.dts" ++#include "arm/broadcom/bcm2710-rpi-2-b.dts" diff --git a/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts new file mode 100644 -index 000000000000..22fc6a82f2a9 +index 000000000000..bc869aeaee9b --- /dev/null +++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts @@ -0,0 +1 @@ -+#include "../../../../arm/boot/dts/bcm2710-rpi-3-b-plus.dts" ++#include "arm/broadcom/bcm2710-rpi-3-b-plus.dts" diff --git a/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dts b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dts new file mode 100644 -index 000000000000..4cacc5b72ae3 +index 000000000000..263fc8db863a --- /dev/null +++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dts @@ -0,0 +1 @@ -+#include "../../../../arm/boot/dts/bcm2710-rpi-3-b.dts" ++#include "arm/broadcom/bcm2710-rpi-3-b.dts" diff --git a/arch/arm64/boot/dts/broadcom/bcm2710-rpi-cm3.dts b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-cm3.dts new file mode 100644 -index 000000000000..e1e13784cff6 +index 000000000000..6beee41b0077 --- /dev/null +++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-cm3.dts @@ -0,0 +1 @@ -+#include "../../../../arm/boot/dts/bcm2710-rpi-cm3.dts" -diff --git a/arch/arm64/boot/dts/broadcom/bcm2710-rpi-zero-2.dts b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-zero-2.dts ++#include "arm/broadcom/bcm2710-rpi-cm3.dts" +diff --git a/arch/arm64/boot/dts/broadcom/bcm2710-rpi-zero-2-w.dts b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-zero-2-w.dts new file mode 100644 -index 000000000000..f76f553599ef +index 000000000000..65fa59a939b7 --- /dev/null -+++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-zero-2.dts ++++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-zero-2-w.dts @@ -0,0 +1 @@ -+#include "../../../../arm/boot/dts/bcm2710-rpi-zero-2.dts" -diff --git a/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts b/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts -index d24c53682e44..bf69a4b0b172 100644 ---- a/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts -+++ b/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts -@@ -1,2 +1 @@ --// SPDX-License-Identifier: GPL-2.0 --#include "arm/bcm2711-rpi-4-b.dts" -+#include "../../../../arm/boot/dts/bcm2711-rpi-4-b.dts" -diff --git a/arch/arm64/boot/dts/broadcom/bcm2711-rpi-400.dts b/arch/arm64/boot/dts/broadcom/bcm2711-rpi-400.dts ++#include "arm/broadcom/bcm2710-rpi-zero-2-w.dts" +diff --git a/arch/arm64/boot/dts/broadcom/bcm2710-rpi-zero-2.dts b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-zero-2.dts new file mode 100644 -index 000000000000..90c2b5a195d4 +index 000000000000..65fa59a939b7 --- /dev/null -+++ b/arch/arm64/boot/dts/broadcom/bcm2711-rpi-400.dts ++++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-zero-2.dts @@ -0,0 +1 @@ -+#include "../../../../arm/boot/dts/bcm2711-rpi-400.dts" ++#include "arm/broadcom/bcm2710-rpi-zero-2-w.dts" diff --git a/arch/arm64/boot/dts/broadcom/bcm2711-rpi-cm4.dts b/arch/arm64/boot/dts/broadcom/bcm2711-rpi-cm4.dts new file mode 100644 -index 000000000000..8064a58155f1 +index 000000000000..3e25a0e1797f --- /dev/null +++ b/arch/arm64/boot/dts/broadcom/bcm2711-rpi-cm4.dts @@ -0,0 +1 @@ -+#include "../../../../arm/boot/dts/bcm2711-rpi-cm4.dts" ++#include "arm/broadcom/bcm2711-rpi-cm4.dts" +diff --git a/arch/arm64/boot/dts/broadcom/bcm2711-rpi-cm4s.dts b/arch/arm64/boot/dts/broadcom/bcm2711-rpi-cm4s.dts +new file mode 100644 +index 000000000000..c72d752e7400 +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2711-rpi-cm4s.dts +@@ -0,0 +1 @@ ++#include "arm/broadcom/bcm2711-rpi-cm4s.dts" +diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts +new file mode 100644 +index 000000000000..1457e696f968 +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts +@@ -0,0 +1,2 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include "arm/broadcom/bcm2712-rpi-5-b.dts" +diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts +new file mode 100644 +index 000000000000..3815e40cc0aa +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts +@@ -0,0 +1,2 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include "arm/broadcom/bcm2712-rpi-cm5-cm4io.dts" +diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts +new file mode 100644 +index 000000000000..e2215a3f6276 +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts +@@ -0,0 +1,2 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include "arm/broadcom/bcm2712-rpi-cm5-cm5io.dts" +diff --git a/arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts b/arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts +new file mode 100644 +index 000000000000..9b3ddbb8dafd +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts +@@ -0,0 +1,2 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include "../../../../arm/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts" diff --git a/arch/arm64/boot/dts/broadcom/bcm283x-rpi-csi1-2lane.dtsi b/arch/arm64/boot/dts/broadcom/bcm283x-rpi-csi1-2lane.dtsi new file mode 120000 index 000000000000..e5c400284467 @@ -42889,10 +58297,10 @@ \ No newline at end of file diff --git a/arch/arm64/configs/bcm2711_defconfig b/arch/arm64/configs/bcm2711_defconfig new file mode 100644 -index 000000000000..75333e69ef74 +index 000000000000..6ac8c83f6842 --- /dev/null +++ b/arch/arm64/configs/bcm2711_defconfig -@@ -0,0 +1,1566 @@ +@@ -0,0 +1,1672 @@ +CONFIG_LOCALVERSION="-v8" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y @@ -42900,11 +58308,17 @@ +CONFIG_GENERIC_IRQ_DEBUGFS=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y ++CONFIG_BPF_SYSCALL=y ++CONFIG_BPF_JIT=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_PSI=y ++CONFIG_PSI_DEFAULT_DISABLED=y +CONFIG_IKCONFIG=m +CONFIG_IKCONFIG_PROC=y +CONFIG_MEMCG=y @@ -42919,13 +58333,14 @@ +CONFIG_CGROUP_BPF=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y ++CONFIG_CHECKPOINT_RESTORE=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y -+CONFIG_BPF_SYSCALL=y -+CONFIG_EMBEDDED=y -+# CONFIG_COMPAT_BRK is not set ++CONFIG_EXPERT=y +CONFIG_PROFILING=y ++CONFIG_ARCH_BCM=y +CONFIG_ARCH_BCM2835=y ++CONFIG_ARCH_BRCMSTB=y +# CONFIG_CAVIUM_ERRATUM_22375 is not set +# CONFIG_CAVIUM_ERRATUM_23154 is not set +# CONFIG_CAVIUM_ERRATUM_27456 is not set @@ -42934,11 +58349,12 @@ +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_PM_DEBUG=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 @@ -42949,31 +58365,31 @@ +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_MODULE_COMPRESS_XZ=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_COMPAT_BRK is not set ++CONFIG_CMA=y ++CONFIG_LRU_GEN=y ++CONFIG_LRU_GEN_ENABLED=y +CONFIG_NET=y +CONFIG_PACKET=y -+CONFIG_UNIX=y -+CONFIG_XFRM_USER=y ++CONFIG_XFRM_USER=m ++CONFIG_XFRM_INTERFACE=m ++CONFIG_XFRM_SUB_POLICY=y ++CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=m -+CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y @@ -43013,10 +58429,11 @@ +CONFIG_IPV6_MROUTE=y +CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y +CONFIG_IPV6_PIMSM_V2=y ++CONFIG_MPTCP=y ++CONFIG_NETWORK_PHY_TIMESTAMPING=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 @@ -43037,7 +58454,6 @@ +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 @@ -43045,21 +58461,23 @@ +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_XFRM=m +CONFIG_NFT_SOCKET=m +CONFIG_NFT_OSF=m +CONFIG_NFT_TPROXY=m ++CONFIG_NFT_SYNPROXY=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_XTABLES_COMPAT=y +CONFIG_NETFILTER_XT_SET=m +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m @@ -43131,6 +58549,7 @@ +CONFIG_IP_SET_HASH_NETIFACE=m +CONFIG_IP_SET_LIST_SET=m +CONFIG_IP_VS=m ++CONFIG_IP_VS_IPV6=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y @@ -43151,8 +58570,8 @@ +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_NF_LOG_IPV4=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m @@ -43165,7 +58584,6 @@ +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 @@ -43174,7 +58592,6 @@ +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 @@ -43198,7 +58615,6 @@ +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 @@ -43235,10 +58651,8 @@ +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 @@ -43247,7 +58661,6 @@ +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 @@ -43262,15 +58675,13 @@ +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_CLS_BPF=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m @@ -43307,13 +58718,6 @@ +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_CAN_PEAK_USB=m +CONFIG_BT=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y @@ -43337,32 +58741,38 @@ +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_PCIEPORTBUS=y ++CONFIG_PCIEAER=y ++CONFIG_PCIEASPM_POWERSAVE=y ++CONFIG_PCIE_DPC=y +CONFIG_UEVENT_HELPER=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y ++# CONFIG_BRCMSTB_GISB_ARB is not set ++CONFIG_RASPBERRYPI_FIRMWARE=y ++# CONFIG_EFI_VARS_PSTORE is not set +CONFIG_MTD=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK2MTD=m ++CONFIG_MTD_SPI_NAND=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_NVME_HWMON=y +CONFIG_EEPROM_AT24=m ++CONFIG_EEPROM_AT25=m +CONFIG_TI_ST=m +CONFIG_SCSI=y +# CONFIG_SCSI_PROC_FS is not set @@ -43383,11 +58793,14 @@ +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_THIN_PROVISIONING=m +CONFIG_DM_CACHE=m ++CONFIG_DM_WRITECACHE=m +CONFIG_DM_MIRROR=m +CONFIG_DM_LOG_USERSPACE=m +CONFIG_DM_RAID=m +CONFIG_DM_ZERO=m ++CONFIG_DM_MULTIPATH=m +CONFIG_DM_DELAY=m ++CONFIG_DM_INTEGRITY=m +CONFIG_NETDEVICES=y +CONFIG_BONDING=m +CONFIG_DUMMY=m @@ -43403,13 +58816,23 @@ +CONFIG_NET_VRF=m +CONFIG_VSOCKMON=m +CONFIG_BCMGENET=y ++CONFIG_MACB=y +CONFIG_ENC28J60=m ++CONFIG_LAN743X=m +CONFIG_QCA7000_SPI=m +CONFIG_QCA7000_UART=m +CONFIG_R8169=m +CONFIG_WIZNET_W5100=m +CONFIG_WIZNET_W5100_SPI=m +CONFIG_MICREL_PHY=y ++CONFIG_CAN_VCAN=m ++CONFIG_CAN_SLCAN=m ++CONFIG_CAN_MCP251X=m ++CONFIG_CAN_MCP251XFD=m ++CONFIG_CAN_8DEV_USB=m ++CONFIG_CAN_EMS_USB=m ++CONFIG_CAN_GS_USB=m ++CONFIG_CAN_PEAK_USB=m +CONFIG_MDIO_BITBANG=m +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m @@ -43489,6 +58912,7 @@ +CONFIG_MT7601U=m +CONFIG_MT76x0U=m +CONFIG_MT76x2U=m ++CONFIG_MT7921U=m +CONFIG_RT2X00=m +CONFIG_RT2500USB=m +CONFIG_RT73USB=m @@ -43500,11 +58924,15 @@ +CONFIG_RTL8187=m +CONFIG_RTL8192CU=m +CONFIG_RTL8XXXU=m ++CONFIG_RTW88=m ++CONFIG_RTW88_8822BU=m ++CONFIG_RTW88_8822CU=m ++CONFIG_RTW88_8723DU=m ++CONFIG_RTW88_8821CU=m +CONFIG_USB_ZD1201=m +CONFIG_ZD1211RW=m -+CONFIG_MAC80211_HWSIM=m +CONFIG_USB_NET_RNDIS_WLAN=m -+CONFIG_WIMAX_I2400M_USB=m ++CONFIG_MAC80211_HWSIM=m +CONFIG_IEEE802154_AT86RF230=m +CONFIG_IEEE802154_MRF24J40=m +CONFIG_IEEE802154_CC2520=m @@ -43526,6 +58954,7 @@ +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_PSXPAD_SPI=m +CONFIG_JOYSTICK_PSXPAD_SPI_FF=y ++CONFIG_JOYSTICK_FSIA6B=m +CONFIG_JOYSTICK_RPISENSE=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m @@ -43536,7 +58965,10 @@ +CONFIG_TOUCHSCREEN_EDT_FT5X06=m +CONFIG_TOUCHSCREEN_RASPBERRYPI_FW=m +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m ++CONFIG_TOUCHSCREEN_TSC2007=m ++CONFIG_TOUCHSCREEN_TSC2007_IIO=y +CONFIG_TOUCHSCREEN_STMPE=m ++CONFIG_TOUCHSCREEN_IQS5XX=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_AD714X=m +CONFIG_INPUT_ATI_REMOTE2=m @@ -43551,18 +58983,14 @@ +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_NR_UARTS=5 +CONFIG_SERIAL_8250_RUNTIME_UARTS=0 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_SHARE_IRQ=y @@ -43575,10 +59003,13 @@ +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_RANDOM_TRUST_BOOTLOADER=y ++CONFIG_TCG_TIS_I2C=m ++CONFIG_XILLYBUS=m ++CONFIG_XILLYBUS_PCIE=m ++CONFIG_XILLYUSB=m ++CONFIG_RASPBERRYPI_GPIOMEM=m +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_MUX_GPMUX=m @@ -43587,32 +59018,38 @@ +CONFIG_I2C_BCM2708=m +CONFIG_I2C_BCM2835=m +CONFIG_I2C_BRCMSTB=m ++CONFIG_I2C_DESIGNWARE_PLATFORM=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_DESIGNWARE=m ++CONFIG_SPI_DW_DMA=y ++CONFIG_SPI_DW_MMIO=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_PINCTRL_RP1=y ++CONFIG_PINCTRL_BCM2712=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_BCM_VIRT=y ++CONFIG_GPIO_MAX7300=m +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_MAX7301=m +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 @@ -43627,75 +59064,82 @@ +CONFIG_W1_SLAVE_DS2781=m +CONFIG_W1_SLAVE_DS28E04=m +CONFIG_W1_SLAVE_DS28E17=m ++# CONFIG_POWER_RESET_BRCMSTB is not set +CONFIG_POWER_RESET_GPIO=y +CONFIG_RPI_POE_POWER=m +CONFIG_BATTERY_DS2760=m +CONFIG_BATTERY_MAX17040=m ++CONFIG_CHARGER_GPIO=m +CONFIG_BATTERY_GAUGE_LTC2941=m ++CONFIG_SENSORS_ADT7410=m ++CONFIG_SENSORS_AHT10=m ++CONFIG_SENSORS_DRIVETEMP=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_PWM_FAN=m +CONFIG_SENSORS_RASPBERRYPI_HWMON=m -+CONFIG_SENSORS_RPI_POE_FAN=m +CONFIG_SENSORS_SHT21=m +CONFIG_SENSORS_SHT3x=m ++CONFIG_SENSORS_SHT4x=m +CONFIG_SENSORS_SHTC1=m ++CONFIG_SENSORS_EMC2305=m +CONFIG_SENSORS_INA2XX=m +CONFIG_SENSORS_TMP102=m -+CONFIG_THERMAL=y ++CONFIG_SENSORS_RP1_ADC=m +CONFIG_BCM2711_THERMAL=y +CONFIG_BCM2835_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_GPIO_WATCHDOG=m +CONFIG_BCM2835_WDT=y ++CONFIG_MFD_RASPBERRYPI_POE_HAT=m +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_MFD_RP1=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_ARIZONA_LDO1=m +CONFIG_REGULATOR_ARIZONA_MICSUPP=m +CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY=m ++CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_V2=m +CONFIG_RC_CORE=y -+CONFIG_LIRC=y +CONFIG_BPF_LIRC_MODE2=y ++CONFIG_LIRC=y +CONFIG_RC_DECODERS=y ++CONFIG_IR_IMON_DECODER=m ++CONFIG_IR_JVC_DECODER=m ++CONFIG_IR_MCE_KBD_DECODER=m +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_SONY_DECODER=m +CONFIG_IR_XMP_DECODER=m -+CONFIG_IR_IMON_DECODER=m +CONFIG_RC_DEVICES=y -+CONFIG_RC_ATI_REMOTE=m ++CONFIG_IR_GPIO_CIR=m ++CONFIG_IR_GPIO_TX=m ++CONFIG_IR_IGUANA=m +CONFIG_IR_IMON=m +CONFIG_IR_MCEUSB=m ++CONFIG_IR_PWM_TX=m +CONFIG_IR_REDRAT3=m +CONFIG_IR_STREAMZAP=m -+CONFIG_IR_IGUANA=m ++CONFIG_IR_TOY=m +CONFIG_IR_TTUSBIR=m ++CONFIG_RC_ATI_REMOTE=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=m +CONFIG_USB_GSPCA_BENQ=m +CONFIG_USB_GSPCA_CONEX=m +CONFIG_USB_GSPCA_CPIA1=m @@ -43720,13 +59164,13 @@ +CONFIG_USB_GSPCA_SN9C20X=m +CONFIG_USB_GSPCA_SONIXB=m +CONFIG_USB_GSPCA_SONIXJ=m ++CONFIG_USB_GSPCA_SPCA1528=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 @@ -43736,56 +59180,1713 @@ +CONFIG_USB_GSPCA_SUNPLUS=m +CONFIG_USB_GSPCA_T613=m +CONFIG_USB_GSPCA_TOPRO=m ++CONFIG_USB_GSPCA_TOUPTEK=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_GL860=m ++CONFIG_USB_M5602=m ++CONFIG_USB_STV06XX=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_USB_VIDEO_CLASS=m +CONFIG_VIDEO_GO7007=m +CONFIG_VIDEO_GO7007_USB=m +CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m ++CONFIG_VIDEO_HDPVR=m ++CONFIG_VIDEO_PVRUSB2=m ++CONFIG_VIDEO_STK1160=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_AS102=m ++CONFIG_DVB_B2C2_FLEXCOP_USB=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_DVBSKY=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=m +CONFIG_DVB_USB_A800=m ++CONFIG_DVB_USB_AF9005=m ++CONFIG_DVB_USB_AF9005_REMOTE=m ++CONFIG_DVB_USB_AZ6027=m ++CONFIG_DVB_USB_CINERGY_T2=m ++CONFIG_DVB_USB_CXUSB=m ++CONFIG_DVB_USB_DIB0700=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_DTT200U=m ++CONFIG_DVB_USB_DTV5100=m ++CONFIG_DVB_USB_DW2102=m +CONFIG_DVB_USB_GP8PSK=m ++CONFIG_DVB_USB_M920X=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_TTUSB2=m ++CONFIG_DVB_USB_UMT_010=m ++CONFIG_DVB_USB_VP702X=m ++CONFIG_DVB_USB_VP7045=m ++CONFIG_SMS_USB_DRV=m ++CONFIG_VIDEO_EM28XX=m ++CONFIG_VIDEO_EM28XX_V4L2=m ++CONFIG_VIDEO_EM28XX_ALSA=m ++CONFIG_VIDEO_EM28XX_DVB=m ++CONFIG_RADIO_SAA7706H=m ++CONFIG_RADIO_SHARK=m ++CONFIG_RADIO_SHARK2=m ++CONFIG_RADIO_SI4713=m ++CONFIG_RADIO_TEA5764=m ++CONFIG_RADIO_TEF6862=m ++CONFIG_RADIO_WL1273=m ++CONFIG_USB_DSBR=m ++CONFIG_USB_KEENE=m ++CONFIG_USB_MA901=m ++CONFIG_USB_MR800=m ++CONFIG_RADIO_SI470X=m ++CONFIG_USB_SI470X=m ++CONFIG_I2C_SI470X=m ++CONFIG_I2C_SI4713=m ++CONFIG_RADIO_WL128X=m ++CONFIG_V4L_PLATFORM_DRIVERS=y ++CONFIG_VIDEO_MUX=m ++CONFIG_VIDEO_BCM2835_UNICAM=m ++CONFIG_VIDEO_RASPBERRYPI_PISP_BE=m ++CONFIG_VIDEO_RP1_CFE=m ++CONFIG_V4L_TEST_DRIVERS=y ++CONFIG_VIDEO_VIM2M=m ++CONFIG_VIDEO_VICODEC=m ++CONFIG_VIDEO_VIMC=m ++CONFIG_VIDEO_VIVID=m ++CONFIG_VIDEO_ARDUCAM_64MP=m ++CONFIG_VIDEO_ARDUCAM_PIVARIETY=m ++CONFIG_VIDEO_IMX219=m ++CONFIG_VIDEO_IMX258=m ++CONFIG_VIDEO_IMX290=m ++CONFIG_VIDEO_IMX296=m ++CONFIG_VIDEO_IMX477=m ++CONFIG_VIDEO_IMX519=m ++CONFIG_VIDEO_IMX708=m ++CONFIG_VIDEO_MT9V011=m ++CONFIG_VIDEO_OV2311=m ++CONFIG_VIDEO_OV5647=m ++CONFIG_VIDEO_OV64A40=m ++CONFIG_VIDEO_OV7251=m ++CONFIG_VIDEO_OV7640=m ++CONFIG_VIDEO_OV9282=m ++CONFIG_VIDEO_AD5398=m ++CONFIG_VIDEO_AK7375=m ++CONFIG_VIDEO_BU64754=m ++CONFIG_VIDEO_DW9807_VCM=m ++CONFIG_VIDEO_SONY_BTF_MPX=m ++CONFIG_VIDEO_UDA1342=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_IRS1125=m ++CONFIG_VIDEO_I2C=m ++CONFIG_AUXDISPLAY=y ++CONFIG_HD44780=m ++CONFIG_DRM=m ++CONFIG_DRM_LOAD_EDID_FIRMWARE=y ++CONFIG_DRM_UDL=m ++CONFIG_DRM_PANEL_SIMPLE=m ++CONFIG_DRM_PANEL_ILITEK_ILI9806E=m ++CONFIG_DRM_PANEL_ILITEK_ILI9881C=m ++CONFIG_DRM_PANEL_JDI_LT070ME05000=m ++CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m ++CONFIG_DRM_PANEL_SITRONIX_ST7701=m ++CONFIG_DRM_PANEL_TPO_Y17P=m ++CONFIG_DRM_PANEL_WAVESHARE_TOUCHSCREEN=m ++CONFIG_DRM_DISPLAY_CONNECTOR=m ++CONFIG_DRM_SIMPLE_BRIDGE=m ++CONFIG_DRM_TOSHIBA_TC358762=m ++CONFIG_DRM_V3D=m ++CONFIG_DRM_VC4=m ++CONFIG_DRM_VC4_HDMI_CEC=y ++CONFIG_DRM_RP1_DSI=m ++CONFIG_DRM_RP1_DPI=m ++CONFIG_DRM_RP1_VEC=m ++CONFIG_DRM_PANEL_MIPI_DBI=m ++CONFIG_TINYDRM_HX8357D=m ++CONFIG_TINYDRM_ILI9225=m ++CONFIG_TINYDRM_ILI9341=m ++CONFIG_TINYDRM_ILI9486=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_SIMPLE=y ++CONFIG_FB_SSD1307=m ++CONFIG_FB_RPISENSE=m ++CONFIG_BACKLIGHT_PWM=m ++CONFIG_BACKLIGHT_RPI=m ++CONFIG_BACKLIGHT_LM3630A=m ++CONFIG_BACKLIGHT_GPIO=m ++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_DYNAMIC_MINORS=y ++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_USB_TONEPORT=m ++CONFIG_SND_SOC=m ++CONFIG_SND_BCM2835_SOC_I2S=m ++CONFIG_SND_BCM2708_SOC_CHIPDIP_DAC=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_DACBERRY400=m ++CONFIG_SND_DESIGNWARE_I2S=m ++CONFIG_SND_DESIGNWARE_PCM=y ++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_TLV320AIC23_I2C=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_NINTENDO=m ++CONFIG_NINTENDO_FF=y ++CONFIG_HID_NTRIG=m ++CONFIG_HID_ORTEK=m ++CONFIG_HID_PANTHERLORD=m ++CONFIG_HID_PETALYNX=m ++CONFIG_HID_PICOLCD=m ++CONFIG_HID_PLAYSTATION=m ++CONFIG_PLAYSTATION_FF=y ++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_USB=y ++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y ++CONFIG_USB_MON=m ++CONFIG_USB_XHCI_HCD=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_DWC3=y ++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_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_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_OF_DWCMSHC=m ++CONFIG_MMC_SDHCI_IPROC=y ++CONFIG_MMC_SPI=m ++CONFIG_LEDS_CLASS=y ++CONFIG_LEDS_CLASS_MULTICOLOR=m ++CONFIG_LEDS_PCA9532=m ++CONFIG_LEDS_GPIO=y ++CONFIG_LEDS_PCA955X=m ++CONFIG_LEDS_PCA963X=m ++CONFIG_LEDS_PWM=y ++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_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_PATTERN=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_RV3032=m ++CONFIG_RTC_DRV_RV8803=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_DW_AXI_DMAC=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_VHOST_NET=m ++CONFIG_VHOST_VSOCK=m ++CONFIG_VHOST_CROSS_ENDIAN_LEGACY=y ++CONFIG_STAGING=y ++CONFIG_PRISM2_USB=m ++CONFIG_R8712U=m ++CONFIG_VT6656=m ++CONFIG_STAGING_MEDIA=y ++CONFIG_VIDEO_RPIVID=m ++CONFIG_STAGING_MEDIA_DEPRECATED=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_UC1611=m ++CONFIG_FB_TFT_UC1701=m ++CONFIG_FB_TFT_UPD161704=m ++CONFIG_BCM2835_VCHIQ=y ++CONFIG_SND_BCM2835=m ++CONFIG_VIDEO_BCM2835=m ++CONFIG_VIDEO_CODEC_BCM2835=m ++CONFIG_VIDEO_ISP_BCM2835=m ++CONFIG_COMMON_CLK_RP1=y ++CONFIG_COMMON_CLK_RP1_SDIO=y ++CONFIG_CLK_RASPBERRYPI=y ++CONFIG_MAILBOX=y ++CONFIG_BCM2835_MBOX=y ++CONFIG_BCM2712_IOMMU=y ++CONFIG_RASPBERRYPI_POWER=y ++CONFIG_IIO=m ++CONFIG_IIO_BUFFER_CB=m ++CONFIG_IIO_SW_TRIGGER=m ++CONFIG_MCP320X=m ++CONFIG_MCP3422=m ++CONFIG_TI_ADS1015=m ++CONFIG_BME680=m ++CONFIG_CCS811=m ++CONFIG_SENSIRION_SGP30=m ++CONFIG_SPS30_I2C=m ++CONFIG_MAX30102=m ++CONFIG_DHT11=m ++CONFIG_HDC100X=m ++CONFIG_HTU21=m ++CONFIG_SI7020=m ++CONFIG_BOSCH_BNO055_I2C=m ++CONFIG_INV_MPU6050_I2C=m ++CONFIG_APDS9960=m ++CONFIG_BH1750=m ++CONFIG_TSL4531=m ++CONFIG_VEML6070=m ++CONFIG_IIO_HRTIMER_TRIGGER=m ++CONFIG_IIO_INTERRUPT_TRIGGER=m ++CONFIG_IIO_SYSFS_TRIGGER=m ++CONFIG_BMP280=m ++CONFIG_MS5637=m ++CONFIG_MAXIM_THERMOCOUPLE=m ++CONFIG_MAX31856=m ++CONFIG_PWM=y ++CONFIG_PWM_BCM2835=m ++CONFIG_PWM_BRCMSTB=y ++CONFIG_PWM_PCA9685=m ++CONFIG_PWM_RASPBERRYPI_POE=m ++CONFIG_PWM_RP1=y ++CONFIG_BCM2712_MIP=y ++CONFIG_RPI_AXIPERF=m ++CONFIG_ANDROID_BINDER_IPC=y ++CONFIG_ANDROID_BINDERFS=y ++CONFIG_NVMEM_RMEM=m ++CONFIG_MUX_GPIO=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_F2FS_FS_SECURITY=y ++CONFIG_FS_ENCRYPTION=y ++CONFIG_FANOTIFY=y ++CONFIG_QFMT_V1=m ++CONFIG_QFMT_V2=m ++CONFIG_AUTOFS_FS=y ++CONFIG_FUSE_FS=m ++CONFIG_CUSE=m ++CONFIG_OVERLAY_FS=m ++CONFIG_FSCACHE=y ++CONFIG_FSCACHE_STATS=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_NTFS3_FS=m ++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_PSTORE=y ++CONFIG_PSTORE_CONSOLE=y ++CONFIG_PSTORE_RAM=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_V2=y ++CONFIG_NFSD_V2_ACL=y ++CONFIG_NFSD_V3_ACL=y ++CONFIG_NFSD_V4=y ++CONFIG_CEPH_FS=m ++CONFIG_CIFS=m ++CONFIG_CIFS_UPCALL=y ++CONFIG_CIFS_XATTR=y ++CONFIG_CIFS_POSIX=y ++CONFIG_CIFS_DFS_UPCALL=y ++CONFIG_CIFS_FSCACHE=y ++CONFIG_SMB_SERVER=m ++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_KEY_DH_OPERATIONS=y ++CONFIG_SECURITY=y ++CONFIG_SECURITY_APPARMOR=y ++CONFIG_LSM="" ++CONFIG_CRYPTO_USER=m ++CONFIG_CRYPTO_CRYPTD=m ++CONFIG_CRYPTO_AES=m ++CONFIG_CRYPTO_CAST5=m ++CONFIG_CRYPTO_DES=y ++CONFIG_CRYPTO_TWOFISH=m ++CONFIG_CRYPTO_ADIANTUM=m ++CONFIG_CRYPTO_CBC=m ++CONFIG_CRYPTO_CHACHA20POLY1305=m ++CONFIG_CRYPTO_MD4=m ++CONFIG_CRYPTO_SHA512=m ++CONFIG_CRYPTO_WP512=m ++CONFIG_CRYPTO_XCBC=m ++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_GHASH_ARM64_CE=m ++CONFIG_CRYPTO_SHA1_ARM64_CE=m ++CONFIG_CRYPTO_SHA2_ARM64_CE=m ++CONFIG_CRYPTO_SHA512_ARM64_CE=m ++CONFIG_CRYPTO_SHA3_ARM64=m ++CONFIG_CRYPTO_SM3_ARM64_CE=m ++CONFIG_CRYPTO_AES_ARM64=m ++CONFIG_CRYPTO_AES_ARM64_CE_BLK=m ++CONFIG_CRYPTO_AES_ARM64_BS=m ++CONFIG_CRYPTO_SM4_ARM64_CE=m ++CONFIG_CRYPTO_AES_ARM64_CE_CCM=m ++# CONFIG_CRYPTO_HW is not set ++CONFIG_PKCS8_PRIVATE_KEY_PARSER=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_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1f6 ++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_SCHED_TRACER=y ++CONFIG_BLK_DEV_IO_TRACE=y ++# CONFIG_UPROBE_EVENTS is not set ++# CONFIG_STRICT_DEVMEM is not set +diff --git a/arch/arm64/configs/bcm2712_defconfig b/arch/arm64/configs/bcm2712_defconfig +new file mode 100644 +index 000000000000..875b905be102 +--- /dev/null ++++ b/arch/arm64/configs/bcm2712_defconfig +@@ -0,0 +1,1675 @@ ++CONFIG_LOCALVERSION="-v8-16k" ++# 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_BPF_SYSCALL=y ++CONFIG_BPF_JIT=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_PSI=y ++CONFIG_PSI_DEFAULT_DISABLED=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_CHECKPOINT_RESTORE=y ++CONFIG_SCHED_AUTOGROUP=y ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_EXPERT=y ++CONFIG_PROFILING=y ++CONFIG_ARCH_BCM=y ++CONFIG_ARCH_BCM2835=y ++CONFIG_ARCH_BRCMSTB=y ++# CONFIG_CAVIUM_ERRATUM_22375 is not set ++# CONFIG_CAVIUM_ERRATUM_23154 is not set ++# CONFIG_CAVIUM_ERRATUM_27456 is not set ++CONFIG_ARM64_16K_PAGES=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_PM_DEBUG=y ++CONFIG_CPU_IDLE=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_VIRTUALIZATION=y ++CONFIG_KVM=y ++CONFIG_JUMP_LABEL=y ++CONFIG_ARCH_MMAP_RND_BITS=18 ++CONFIG_ARCH_MMAP_RND_COMPAT_BITS=11 ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++CONFIG_MODVERSIONS=y ++CONFIG_MODULE_SRCVERSION_ALL=y ++CONFIG_MODULE_COMPRESS_XZ=y ++CONFIG_BLK_DEV_THROTTLING=y ++CONFIG_PARTITION_ADVANCED=y ++CONFIG_MAC_PARTITION=y ++CONFIG_BINFMT_MISC=m ++CONFIG_ZSWAP=y ++CONFIG_Z3FOLD=m ++# CONFIG_COMPAT_BRK is not set ++CONFIG_CMA=y ++CONFIG_LRU_GEN=y ++CONFIG_LRU_GEN_ENABLED=y ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_XFRM_USER=m ++CONFIG_XFRM_INTERFACE=m ++CONFIG_XFRM_SUB_POLICY=y ++CONFIG_XFRM_STATISTICS=y ++CONFIG_NET_KEY=m ++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_MPTCP=y ++CONFIG_NETWORK_PHY_TIMESTAMPING=y ++CONFIG_NETFILTER=y ++CONFIG_BRIDGE_NETFILTER=m ++CONFIG_NF_CONNTRACK=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_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_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_XFRM=m ++CONFIG_NFT_SOCKET=m ++CONFIG_NFT_OSF=m ++CONFIG_NFT_TPROXY=m ++CONFIG_NFT_SYNPROXY=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_XTABLES_COMPAT=y ++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_IPV6=y ++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_LOG_ARP=m ++CONFIG_NF_LOG_IPV4=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_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_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_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_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_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_ROUTE4=m ++CONFIG_NET_CLS_FW=m ++CONFIG_NET_CLS_U32=m ++CONFIG_CLS_U32_MARK=y ++CONFIG_NET_CLS_FLOW=m ++CONFIG_NET_CLS_CGROUP=m ++CONFIG_NET_CLS_BPF=y ++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_VSOCKETS=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_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_RFKILL=m ++CONFIG_RFKILL_INPUT=y ++CONFIG_NET_9P=m ++CONFIG_NFC=m ++CONFIG_PCI=y ++CONFIG_PCIEPORTBUS=y ++CONFIG_PCIEAER=y ++CONFIG_PCIEASPM_POWERSAVE=y ++CONFIG_PCIE_DPC=y ++CONFIG_UEVENT_HELPER=y ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y ++# CONFIG_BRCMSTB_GISB_ARB is not set ++CONFIG_RASPBERRYPI_FIRMWARE=y ++# CONFIG_EFI_VARS_PSTORE is not set ++CONFIG_MTD=m ++CONFIG_MTD_BLOCK=m ++CONFIG_MTD_BLOCK2MTD=m ++CONFIG_MTD_SPI_NAND=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_DRBD=m ++CONFIG_BLK_DEV_NBD=m ++CONFIG_BLK_DEV_RAM=y ++CONFIG_ATA_OVER_ETH=m ++CONFIG_BLK_DEV_NVME=y ++CONFIG_NVME_HWMON=y ++CONFIG_EEPROM_AT24=m ++CONFIG_EEPROM_AT25=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_WRITECACHE=m ++CONFIG_DM_MIRROR=m ++CONFIG_DM_LOG_USERSPACE=m ++CONFIG_DM_RAID=m ++CONFIG_DM_ZERO=m ++CONFIG_DM_MULTIPATH=m ++CONFIG_DM_DELAY=m ++CONFIG_DM_INTEGRITY=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_VSOCKMON=m ++CONFIG_BCMGENET=y ++CONFIG_MACB=y ++CONFIG_ENC28J60=m ++CONFIG_LAN743X=m ++CONFIG_QCA7000_SPI=m ++CONFIG_QCA7000_UART=m ++CONFIG_R8169=m ++CONFIG_WIZNET_W5100=m ++CONFIG_WIZNET_W5100_SPI=m ++CONFIG_MICREL_PHY=y ++CONFIG_CAN_VCAN=m ++CONFIG_CAN_SLCAN=m ++CONFIG_CAN_MCP251X=m ++CONFIG_CAN_MCP251XFD=m ++CONFIG_CAN_8DEV_USB=m ++CONFIG_CAN_EMS_USB=m ++CONFIG_CAN_GS_USB=m ++CONFIG_CAN_PEAK_USB=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=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_MT7921U=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_RTW88=m ++CONFIG_RTW88_8822BU=m ++CONFIG_RTW88_8822CU=m ++CONFIG_RTW88_8723DU=m ++CONFIG_RTW88_8821CU=m ++CONFIG_USB_ZD1201=m ++CONFIG_ZD1211RW=m ++CONFIG_USB_NET_RNDIS_WLAN=m ++CONFIG_MAC80211_HWSIM=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_TCA6416=m ++CONFIG_KEYBOARD_TCA8418=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_FSIA6B=m ++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_TSC2007=m ++CONFIG_TOUCHSCREEN_TSC2007_IIO=y ++CONFIG_TOUCHSCREEN_STMPE=m ++CONFIG_TOUCHSCREEN_IQS5XX=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_BRCM_CHAR_DRIVERS=y ++CONFIG_BCM_VCIO=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=5 ++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_TCG_TPM=m ++CONFIG_TCG_TIS_SPI=m ++CONFIG_TCG_TIS_I2C=m ++CONFIG_XILLYBUS=m ++CONFIG_XILLYBUS_PCIE=m ++CONFIG_XILLYUSB=m ++CONFIG_RASPBERRYPI_GPIOMEM=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_DESIGNWARE_PLATFORM=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_DESIGNWARE=m ++CONFIG_SPI_DW_DMA=y ++CONFIG_SPI_DW_MMIO=m ++CONFIG_SPI_GPIO=m ++CONFIG_SPI_SPIDEV=m ++CONFIG_SPI_SLAVE=y ++CONFIG_PPS_CLIENT_LDISC=m ++CONFIG_PPS_CLIENT_GPIO=m ++CONFIG_PINCTRL_MCP23S08=m ++CONFIG_PINCTRL_RP1=y ++CONFIG_PINCTRL_BCM2712=y ++CONFIG_GPIO_SYSFS=y ++CONFIG_GPIO_BCM_VIRT=y ++CONFIG_GPIO_MAX7300=m ++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_MAX7301=m ++CONFIG_GPIO_MOCKUP=m ++CONFIG_W1=m ++CONFIG_W1_MASTER_DS2490=m ++CONFIG_W1_MASTER_DS2482=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_BRCMSTB is not set ++CONFIG_POWER_RESET_GPIO=y ++CONFIG_RPI_POE_POWER=m ++CONFIG_BATTERY_DS2760=m ++CONFIG_BATTERY_MAX17040=m ++CONFIG_CHARGER_GPIO=m ++CONFIG_BATTERY_GAUGE_LTC2941=m ++CONFIG_SENSORS_ADT7410=m ++CONFIG_SENSORS_AHT10=m ++CONFIG_SENSORS_DRIVETEMP=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_PWM_FAN=m ++CONFIG_SENSORS_RASPBERRYPI_HWMON=m ++CONFIG_SENSORS_SHT21=m ++CONFIG_SENSORS_SHT3x=m ++CONFIG_SENSORS_SHT4x=m ++CONFIG_SENSORS_SHTC1=m ++CONFIG_SENSORS_EMC2305=m ++CONFIG_SENSORS_INA2XX=m ++CONFIG_SENSORS_TMP102=m ++CONFIG_SENSORS_RP1_ADC=m ++CONFIG_BCM2711_THERMAL=y ++CONFIG_BCM2835_THERMAL=y ++CONFIG_WATCHDOG=y ++CONFIG_GPIO_WATCHDOG=m ++CONFIG_BCM2835_WDT=y ++CONFIG_MFD_RASPBERRYPI_POE_HAT=m ++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_MFD_RP1=y ++CONFIG_REGULATOR=y ++CONFIG_REGULATOR_FIXED_VOLTAGE=y ++CONFIG_REGULATOR_ARIZONA_LDO1=m ++CONFIG_REGULATOR_ARIZONA_MICSUPP=m ++CONFIG_REGULATOR_GPIO=y ++CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY=m ++CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_V2=m ++CONFIG_RC_CORE=y ++CONFIG_BPF_LIRC_MODE2=y ++CONFIG_LIRC=y ++CONFIG_RC_DECODERS=y ++CONFIG_IR_IMON_DECODER=m ++CONFIG_IR_JVC_DECODER=m ++CONFIG_IR_MCE_KBD_DECODER=m ++CONFIG_IR_NEC_DECODER=m ++CONFIG_IR_RC5_DECODER=m ++CONFIG_IR_RC6_DECODER=m ++CONFIG_IR_SANYO_DECODER=m ++CONFIG_IR_SHARP_DECODER=m ++CONFIG_IR_SONY_DECODER=m ++CONFIG_IR_XMP_DECODER=m ++CONFIG_RC_DEVICES=y ++CONFIG_IR_GPIO_CIR=m ++CONFIG_IR_GPIO_TX=m ++CONFIG_IR_IGUANA=m ++CONFIG_IR_IMON=m ++CONFIG_IR_MCEUSB=m ++CONFIG_IR_PWM_TX=m ++CONFIG_IR_REDRAT3=m ++CONFIG_IR_STREAMZAP=m ++CONFIG_IR_TOY=m ++CONFIG_IR_TTUSBIR=m ++CONFIG_RC_ATI_REMOTE=m ++CONFIG_RC_LOOPBACK=m ++CONFIG_MEDIA_CEC_RC=y ++CONFIG_MEDIA_SUPPORT=m ++CONFIG_MEDIA_USB_SUPPORT=y ++CONFIG_USB_GSPCA=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_SPCA1528=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_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_TOUPTEK=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_GL860=m ++CONFIG_USB_M5602=m ++CONFIG_USB_STV06XX=m ++CONFIG_USB_PWC=m ++CONFIG_USB_S2255=m ++CONFIG_VIDEO_USBTV=m ++CONFIG_USB_VIDEO_CLASS=m ++CONFIG_VIDEO_GO7007=m ++CONFIG_VIDEO_GO7007_USB=m ++CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m ++CONFIG_VIDEO_HDPVR=m ++CONFIG_VIDEO_PVRUSB2=m ++CONFIG_VIDEO_STK1160=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_DVB_AS102=m ++CONFIG_DVB_B2C2_FLEXCOP_USB=m +CONFIG_DVB_USB_V2=m +CONFIG_DVB_USB_AF9015=m +CONFIG_DVB_USB_AF9035=m @@ -43793,75 +60894,125 @@ +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_AZ6007=m +CONFIG_DVB_USB_CE6230=m ++CONFIG_DVB_USB_DVBSKY=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_DVB_USB=m ++CONFIG_DVB_USB_A800=m ++CONFIG_DVB_USB_AF9005=m ++CONFIG_DVB_USB_AF9005_REMOTE=m ++CONFIG_DVB_USB_AZ6027=m ++CONFIG_DVB_USB_CINERGY_T2=m ++CONFIG_DVB_USB_CXUSB=m ++CONFIG_DVB_USB_DIB0700=m ++CONFIG_DVB_USB_DIBUSB_MB=m ++CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y ++CONFIG_DVB_USB_DIBUSB_MC=m ++CONFIG_DVB_USB_DIGITV=m ++CONFIG_DVB_USB_DTT200U=m ++CONFIG_DVB_USB_DTV5100=m ++CONFIG_DVB_USB_DW2102=m ++CONFIG_DVB_USB_GP8PSK=m ++CONFIG_DVB_USB_M920X=m ++CONFIG_DVB_USB_NOVA_T_USB2=m ++CONFIG_DVB_USB_OPERA1=m ++CONFIG_DVB_USB_PCTV452E=m ++CONFIG_DVB_USB_TECHNISAT_USB2=m ++CONFIG_DVB_USB_TTUSB2=m ++CONFIG_DVB_USB_UMT_010=m ++CONFIG_DVB_USB_VP702X=m ++CONFIG_DVB_USB_VP7045=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_SAA7706H=m +CONFIG_RADIO_SHARK=m +CONFIG_RADIO_SHARK2=m -+CONFIG_USB_KEENE=m -+CONFIG_USB_MA901=m ++CONFIG_RADIO_SI4713=m +CONFIG_RADIO_TEA5764=m -+CONFIG_RADIO_SAA7706H=m +CONFIG_RADIO_TEF6862=m +CONFIG_RADIO_WL1273=m ++CONFIG_USB_DSBR=m ++CONFIG_USB_KEENE=m ++CONFIG_USB_MA901=m ++CONFIG_USB_MR800=m ++CONFIG_RADIO_SI470X=m ++CONFIG_USB_SI470X=m ++CONFIG_I2C_SI470X=m ++CONFIG_I2C_SI4713=m +CONFIG_RADIO_WL128X=m +CONFIG_V4L_PLATFORM_DRIVERS=y ++CONFIG_VIDEO_MUX=m +CONFIG_VIDEO_BCM2835_UNICAM=m ++CONFIG_VIDEO_RASPBERRYPI_PISP_BE=m ++CONFIG_VIDEO_RP1_CFE=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_VIMC=m ++CONFIG_VIDEO_VIVID=m ++CONFIG_VIDEO_ARDUCAM_64MP=m ++CONFIG_VIDEO_ARDUCAM_PIVARIETY=m +CONFIG_VIDEO_IMX219=m ++CONFIG_VIDEO_IMX258=m +CONFIG_VIDEO_IMX290=m ++CONFIG_VIDEO_IMX296=m +CONFIG_VIDEO_IMX477=m +CONFIG_VIDEO_IMX519=m ++CONFIG_VIDEO_IMX708=m ++CONFIG_VIDEO_MT9V011=m ++CONFIG_VIDEO_OV2311=m +CONFIG_VIDEO_OV5647=m ++CONFIG_VIDEO_OV64A40=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV7640=m -+CONFIG_VIDEO_OV9281=m ++CONFIG_VIDEO_OV9282=m ++CONFIG_VIDEO_AD5398=m ++CONFIG_VIDEO_AK7375=m ++CONFIG_VIDEO_BU64754=m ++CONFIG_VIDEO_DW9807_VCM=m ++CONFIG_VIDEO_SONY_BTF_MPX=m ++CONFIG_VIDEO_UDA1342=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_IRS1125=m -+CONFIG_VIDEO_MT9V011=m ++CONFIG_VIDEO_I2C=m ++CONFIG_AUXDISPLAY=y ++CONFIG_HD44780=m +CONFIG_DRM=m +CONFIG_DRM_LOAD_EDID_FIRMWARE=y +CONFIG_DRM_UDL=m +CONFIG_DRM_PANEL_SIMPLE=m ++CONFIG_DRM_PANEL_ILITEK_ILI9806E=m +CONFIG_DRM_PANEL_ILITEK_ILI9881C=m +CONFIG_DRM_PANEL_JDI_LT070ME05000=m +CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m ++CONFIG_DRM_PANEL_SITRONIX_ST7701=m ++CONFIG_DRM_PANEL_TPO_Y17P=m ++CONFIG_DRM_PANEL_WAVESHARE_TOUCHSCREEN=m +CONFIG_DRM_DISPLAY_CONNECTOR=m +CONFIG_DRM_SIMPLE_BRIDGE=m +CONFIG_DRM_TOSHIBA_TC358762=m +CONFIG_DRM_V3D=m +CONFIG_DRM_VC4=m +CONFIG_DRM_VC4_HDMI_CEC=y ++CONFIG_DRM_RP1_DSI=m ++CONFIG_DRM_RP1_DPI=m ++CONFIG_DRM_RP1_VEC=m ++CONFIG_DRM_PANEL_MIPI_DBI=m ++CONFIG_TINYDRM_HX8357D=m +CONFIG_TINYDRM_ILI9225=m +CONFIG_TINYDRM_ILI9341=m ++CONFIG_TINYDRM_ILI9486=m +CONFIG_TINYDRM_MI0283QT=m +CONFIG_TINYDRM_REPAPER=m +CONFIG_TINYDRM_ST7586=m @@ -43869,14 +61020,13 @@ +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_PWM=m +CONFIG_BACKLIGHT_RPI=m ++CONFIG_BACKLIGHT_LM3630A=m +CONFIG_BACKLIGHT_GPIO=m -+CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set @@ -43886,6 +61036,7 @@ +CONFIG_SND_OSSEMUL=y +CONFIG_SND_PCM_OSS=m +CONFIG_SND_HRTIMER=m ++CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_DUMMY=m @@ -43940,6 +61091,9 @@ +CONFIG_SND_BCM2708_SOC_ALLO_KATANA_DAC=m +CONFIG_SND_BCM2708_SOC_FE_PI_AUDIO=m +CONFIG_SND_PISOUND=m ++CONFIG_SND_DACBERRY400=m ++CONFIG_SND_DESIGNWARE_I2S=m ++CONFIG_SND_DESIGNWARE_PCM=y +CONFIG_SND_SOC_AD193X_SPI=m +CONFIG_SND_SOC_AD193X_I2C=m +CONFIG_SND_SOC_ADAU1701=m @@ -43950,6 +61104,7 @@ +CONFIG_SND_SOC_MA120X0P=m +CONFIG_SND_SOC_MAX98357A=m +CONFIG_SND_SOC_SPDIF=m ++CONFIG_SND_SOC_TLV320AIC23_I2C=m +CONFIG_SND_SOC_WM8804_I2C=m +CONFIG_SND_SOC_WM8960=m +CONFIG_SND_SIMPLE_CARD=m @@ -43990,11 +61145,15 @@ +CONFIG_HID_MICROSOFT=m +CONFIG_HID_MONTEREY=m +CONFIG_HID_MULTITOUCH=m ++CONFIG_HID_NINTENDO=m ++CONFIG_NINTENDO_FF=y +CONFIG_HID_NTRIG=m +CONFIG_HID_ORTEK=m +CONFIG_HID_PANTHERLORD=m +CONFIG_HID_PETALYNX=m +CONFIG_HID_PICOLCD=m ++CONFIG_HID_PLAYSTATION=m ++CONFIG_PLAYSTATION_FF=y +CONFIG_HID_ROCCAT=m +CONFIG_HID_SAMSUNG=m +CONFIG_HID_SONY=m @@ -44014,12 +61173,10 @@ +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 @@ -44044,6 +61201,7 @@ +CONFIG_USBIP_VHCI_HCD=m +CONFIG_USBIP_HOST=m +CONFIG_USBIP_VUDC=m ++CONFIG_USB_DWC3=y +CONFIG_USB_DWC2=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y @@ -44085,7 +61243,6 @@ +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 @@ -44103,7 +61260,6 @@ +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 @@ -44156,9 +61312,11 @@ +CONFIG_MMC_BCM2835_SDHOST=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y ++CONFIG_MMC_SDHCI_OF_DWCMSHC=m +CONFIG_MMC_SDHCI_IPROC=y +CONFIG_MMC_SPI=m +CONFIG_LEDS_CLASS=y ++CONFIG_LEDS_CLASS_MULTICOLOR=m +CONFIG_LEDS_PCA9532=m +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_PCA955X=m @@ -44170,7 +61328,6 @@ +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 @@ -44205,6 +61362,8 @@ +CONFIG_RTC_DRV_RX8025=m +CONFIG_RTC_DRV_EM3027=m +CONFIG_RTC_DRV_RV3028=m ++CONFIG_RTC_DRV_RV3032=m ++CONFIG_RTC_DRV_RV8803=m +CONFIG_RTC_DRV_SD3078=m +CONFIG_RTC_DRV_M41T93=m +CONFIG_RTC_DRV_M41T94=m @@ -44221,12 +61380,11 @@ +CONFIG_RTC_DRV_RV3029C2=m +CONFIG_DMADEVICES=y +CONFIG_DMA_BCM2835=y ++CONFIG_DW_AXI_DMAC=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 @@ -44235,11 +61393,10 @@ +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_STAGING_MEDIA_DEPRECATED=y +CONFIG_FB_TFT=m +CONFIG_FB_TFT_AGM1264K_FL=m +CONFIG_FB_TFT_BD663474=m @@ -44267,48 +61424,61 @@ +CONFIG_FB_TFT_ST7789V=m +CONFIG_FB_TFT_TINYLCD=m +CONFIG_FB_TFT_TLS8204=m ++CONFIG_FB_TFT_UC1611=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_COMMON_CLK_RP1=y ++CONFIG_COMMON_CLK_RP1_SDIO=y +CONFIG_CLK_RASPBERRYPI=y +CONFIG_MAILBOX=y +CONFIG_BCM2835_MBOX=y -+# CONFIG_IOMMU_SUPPORT is not set ++CONFIG_BCM2712_IOMMU=y +CONFIG_RASPBERRYPI_POWER=y -+CONFIG_EXTCON_ARIZONA=m +CONFIG_IIO=m +CONFIG_IIO_BUFFER_CB=m ++CONFIG_IIO_SW_TRIGGER=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_SPS30_I2C=m +CONFIG_MAX30102=m +CONFIG_DHT11=m +CONFIG_HDC100X=m +CONFIG_HTU21=m ++CONFIG_SI7020=m ++CONFIG_BOSCH_BNO055_I2C=m +CONFIG_INV_MPU6050_I2C=m +CONFIG_APDS9960=m +CONFIG_BH1750=m +CONFIG_TSL4531=m +CONFIG_VEML6070=m ++CONFIG_IIO_HRTIMER_TRIGGER=m ++CONFIG_IIO_INTERRUPT_TRIGGER=m ++CONFIG_IIO_SYSFS_TRIGGER=m +CONFIG_BMP280=m ++CONFIG_MS5637=m +CONFIG_MAXIM_THERMOCOUPLE=m +CONFIG_MAX31856=m ++CONFIG_PWM=y +CONFIG_PWM_BCM2835=m ++CONFIG_PWM_BRCMSTB=y +CONFIG_PWM_PCA9685=m ++CONFIG_PWM_RASPBERRYPI_POE=m ++CONFIG_PWM_RP1=y ++CONFIG_BCM2712_MIP=y +CONFIG_RPI_AXIPERF=m -+CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDERFS=y +CONFIG_NVMEM_RMEM=m ++CONFIG_MUX_GPIO=m +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y @@ -44335,13 +61505,12 @@ +CONFIG_FANOTIFY=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m -+CONFIG_AUTOFS4_FS=y ++CONFIG_AUTOFS_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 @@ -44353,6 +61522,7 @@ +CONFIG_EXFAT_FS=m +CONFIG_NTFS_FS=m +CONFIG_NTFS_RW=y ++CONFIG_NTFS3_FS=m +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ECRYPT_FS=m @@ -44365,6 +61535,9 @@ +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y ++CONFIG_PSTORE=y ++CONFIG_PSTORE_CONSOLE=y ++CONFIG_PSTORE_RAM=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y @@ -44374,15 +61547,18 @@ +CONFIG_ROOT_NFS=y +CONFIG_NFS_FSCACHE=y +CONFIG_NFSD=m ++CONFIG_NFSD_V2=y ++CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y ++CONFIG_CEPH_FS=m +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_SMB_SERVER=m +CONFIG_9P_FS=m +CONFIG_9P_FS_POSIX_ACL=y +CONFIG_NLS_DEFAULT="utf8" @@ -44424,29 +61600,48 @@ +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_DLM=m ++CONFIG_KEY_DH_OPERATIONS=y +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_CRYPTD=m ++CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_DES=y ++CONFIG_CRYPTO_TWOFISH=m ++CONFIG_CRYPTO_ADIANTUM=m ++CONFIG_CRYPTO_CBC=m ++CONFIG_CRYPTO_CHACHA20POLY1305=m ++CONFIG_CRYPTO_MD4=m ++CONFIG_CRYPTO_SHA512=m ++CONFIG_CRYPTO_WP512=m ++CONFIG_CRYPTO_XCBC=m +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_GHASH_ARM64_CE=m ++CONFIG_CRYPTO_SHA1_ARM64_CE=m ++CONFIG_CRYPTO_SHA2_ARM64_CE=m ++CONFIG_CRYPTO_SHA512_ARM64_CE=m ++CONFIG_CRYPTO_SHA3_ARM64=m ++CONFIG_CRYPTO_SM3_ARM64_CE=m ++CONFIG_CRYPTO_AES_ARM64=m ++CONFIG_CRYPTO_AES_ARM64_CE_BLK=m ++CONFIG_CRYPTO_AES_ARM64_BS=m ++CONFIG_CRYPTO_SM4_ARM64_CE=m ++CONFIG_CRYPTO_AES_ARM64_CE_CCM=m +# CONFIG_CRYPTO_HW is not set ++CONFIG_PKCS8_PRIVATE_KEY_PARSER=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_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1f6 +CONFIG_KGDB=y +CONFIG_KGDB_KDB=y +CONFIG_KDB_KEYBOARD=y @@ -44455,22 +61650,23 @@ +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 ++# CONFIG_STRICT_DEVMEM is not set diff --git a/arch/arm64/configs/bcmrpi3_defconfig b/arch/arm64/configs/bcmrpi3_defconfig new file mode 100644 -index 000000000000..419813140a52 +index 000000000000..ffa7195abfad --- /dev/null +++ b/arch/arm64/configs/bcmrpi3_defconfig -@@ -0,0 +1,1411 @@ +@@ -0,0 +1,1560 @@ +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_BPF_SYSCALL=y +CONFIG_PREEMPT=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y @@ -44478,6 +61674,8 @@ +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y ++CONFIG_PSI=y ++CONFIG_PSI_DEFAULT_DISABLED=y +CONFIG_IKCONFIG=m +CONFIG_IKCONFIG_PROC=y +CONFIG_MEMCG=y @@ -44494,10 +61692,9 @@ +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_EXPERT=y +CONFIG_PROFILING=y ++CONFIG_ARCH_BCM=y +CONFIG_ARCH_BCM2835=y +# CONFIG_CAVIUM_ERRATUM_22375 is not set +# CONFIG_CAVIUM_ERRATUM_23154 is not set @@ -44515,7 +61712,6 @@ +# 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 @@ -44526,28 +61722,28 @@ +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_MODULE_COMPRESS_XZ=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_COMPAT_BRK is not set ++CONFIG_CMA=y ++CONFIG_LRU_GEN=y ++CONFIG_LRU_GEN_ENABLED=y +CONFIG_NET=y +CONFIG_PACKET=y -+CONFIG_UNIX=y +CONFIG_XFRM_USER=y ++CONFIG_XFRM_INTERFACE=m ++CONFIG_XFRM_SUB_POLICY=y ++CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=m -+CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y @@ -44584,10 +61780,10 @@ +CONFIG_IPV6_MROUTE=y +CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y +CONFIG_IPV6_PIMSM_V2=y ++CONFIG_MPTCP=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 @@ -44608,7 +61804,6 @@ +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 @@ -44616,21 +61811,23 @@ +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_XFRM=m +CONFIG_NFT_SOCKET=m +CONFIG_NFT_OSF=m +CONFIG_NFT_TPROXY=m ++CONFIG_NFT_SYNPROXY=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_XTABLES_COMPAT=y +CONFIG_NETFILTER_XT_SET=m +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m @@ -44702,6 +61899,7 @@ +CONFIG_IP_SET_HASH_NETIFACE=m +CONFIG_IP_SET_LIST_SET=m +CONFIG_IP_VS=m ++CONFIG_IP_VS_IPV6=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y @@ -44722,8 +61920,8 @@ +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_NF_LOG_IPV4=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m @@ -44736,7 +61934,6 @@ +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 @@ -44745,7 +61942,6 @@ +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 @@ -44769,7 +61965,6 @@ +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 @@ -44806,7 +62001,6 @@ +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 @@ -44817,7 +62011,6 @@ +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 @@ -44830,13 +62023,10 @@ +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 @@ -44875,11 +62065,6 @@ +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_CAN_PEAK_USB=m +CONFIG_BT=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y @@ -44903,7 +62088,6 @@ +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 @@ -44911,19 +62095,21 @@ +CONFIG_UEVENT_HELPER=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y ++CONFIG_RASPBERRYPI_FIRMWARE=y ++# CONFIG_EFI_VARS_PSTORE is not set +CONFIG_MTD=m +CONFIG_MTD_BLOCK=m ++CONFIG_MTD_SPI_NAND=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_EEPROM_AT25=m +CONFIG_TI_ST=m +CONFIG_SCSI=y +# CONFIG_SCSI_PROC_FS is not set @@ -44934,6 +62120,7 @@ +CONFIG_SCSI_ISCSI_ATTRS=y +CONFIG_ISCSI_TCP=m +CONFIG_ISCSI_BOOT_SYSFS=m ++CONFIG_ATA=m +CONFIG_MD=y +CONFIG_MD_LINEAR=m +CONFIG_BLK_DEV_DM=m @@ -44945,7 +62132,9 @@ +CONFIG_DM_LOG_USERSPACE=m +CONFIG_DM_RAID=m +CONFIG_DM_ZERO=m ++CONFIG_DM_MULTIPATH=m +CONFIG_DM_DELAY=m ++CONFIG_DM_INTEGRITY=m +CONFIG_NETDEVICES=y +CONFIG_BONDING=m +CONFIG_DUMMY=m @@ -44965,6 +62154,12 @@ +CONFIG_QCA7000_UART=m +CONFIG_WIZNET_W5100=m +CONFIG_WIZNET_W5100_SPI=m ++CONFIG_CAN_VCAN=m ++CONFIG_CAN_MCP251X=m ++CONFIG_CAN_MCP251XFD=m ++CONFIG_CAN_8DEV_USB=m ++CONFIG_CAN_EMS_USB=m ++CONFIG_CAN_PEAK_USB=m +CONFIG_MDIO_BITBANG=m +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m @@ -45043,6 +62238,7 @@ +CONFIG_MT7601U=m +CONFIG_MT76x0U=m +CONFIG_MT76x2U=m ++CONFIG_MT7921U=m +CONFIG_RT2X00=m +CONFIG_RT2500USB=m +CONFIG_RT73USB=m @@ -45053,11 +62249,15 @@ +CONFIG_RT2800USB_UNKNOWN=y +CONFIG_RTL8187=m +CONFIG_RTL8192CU=m ++CONFIG_RTW88=m ++CONFIG_RTW88_8822BU=m ++CONFIG_RTW88_8822CU=m ++CONFIG_RTW88_8723DU=m ++CONFIG_RTW88_8821CU=m +CONFIG_USB_ZD1201=m +CONFIG_ZD1211RW=m -+CONFIG_MAC80211_HWSIM=m +CONFIG_USB_NET_RNDIS_WLAN=m -+CONFIG_WIMAX_I2400M_USB=m ++CONFIG_MAC80211_HWSIM=m +CONFIG_IEEE802154_AT86RF230=m +CONFIG_IEEE802154_MRF24J40=m +CONFIG_IEEE802154_CC2520=m @@ -45076,15 +62276,24 @@ +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_FSIA6B=m +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_EKTF2127=m ++CONFIG_TOUCHSCREEN_EDT_FT5X06=m +CONFIG_TOUCHSCREEN_RASPBERRYPI_FW=m +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m ++CONFIG_TOUCHSCREEN_TSC2007=m ++CONFIG_TOUCHSCREEN_TSC2007_IIO=y +CONFIG_TOUCHSCREEN_STMPE=m ++CONFIG_TOUCHSCREEN_IQS5XX=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_AD714X=m +CONFIG_INPUT_ATI_REMOTE2=m @@ -45099,12 +62308,8 @@ +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 @@ -45123,39 +62328,43 @@ +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_RANDOM_TRUST_BOOTLOADER=y ++CONFIG_TCG_TIS_I2C=m ++CONFIG_RASPBERRYPI_GPIOMEM=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_I2C_ROBOTFUZZ_OSIF=m ++CONFIG_I2C_TINY_USB=m +CONFIG_SPI=y +CONFIG_SPI_BCM2835=m +CONFIG_SPI_BCM2835AUX=m -+CONFIG_SPI_SPIDEV=y -+CONFIG_PPS=m ++CONFIG_SPI_GPIO=m ++CONFIG_SPI_SPIDEV=m ++CONFIG_SPI_SLAVE=y +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_MAX7300=m +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_MAX7301=m +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 @@ -45165,6 +62374,7 @@ +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 @@ -45173,58 +62383,74 @@ +CONFIG_RPI_POE_POWER=m +CONFIG_BATTERY_DS2760=m +CONFIG_BATTERY_MAX17040=m ++CONFIG_CHARGER_GPIO=m ++CONFIG_BATTERY_GAUGE_LTC2941=m ++CONFIG_SENSORS_ADT7410=m ++CONFIG_SENSORS_AHT10=m ++CONFIG_SENSORS_DRIVETEMP=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_PWM_FAN=m +CONFIG_SENSORS_RASPBERRYPI_HWMON=m -+CONFIG_SENSORS_RPI_POE_FAN=m +CONFIG_SENSORS_SHT21=m ++CONFIG_SENSORS_SHT3x=m ++CONFIG_SENSORS_SHT4x=m +CONFIG_SENSORS_SHTC1=m ++CONFIG_SENSORS_EMC2305=m +CONFIG_SENSORS_INA2XX=m -+CONFIG_THERMAL=y ++CONFIG_SENSORS_TMP102=m +CONFIG_BCM2835_THERMAL=y +CONFIG_WATCHDOG=y ++CONFIG_GPIO_WATCHDOG=m +CONFIG_BCM2835_WDT=y ++CONFIG_MFD_RASPBERRYPI_POE_HAT=m +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_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY=m ++CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_V2=m +CONFIG_RC_CORE=y -+CONFIG_LIRC=y +CONFIG_BPF_LIRC_MODE2=y ++CONFIG_LIRC=y +CONFIG_RC_DECODERS=y ++CONFIG_IR_IMON_DECODER=m ++CONFIG_IR_JVC_DECODER=m ++CONFIG_IR_MCE_KBD_DECODER=m +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_SONY_DECODER=m +CONFIG_IR_XMP_DECODER=m -+CONFIG_IR_IMON_DECODER=m +CONFIG_RC_DEVICES=y -+CONFIG_RC_ATI_REMOTE=m ++CONFIG_IR_GPIO_CIR=m ++CONFIG_IR_GPIO_TX=m ++CONFIG_IR_IGUANA=m +CONFIG_IR_IMON=m +CONFIG_IR_MCEUSB=m ++CONFIG_IR_PWM_TX=m +CONFIG_IR_REDRAT3=m +CONFIG_IR_STREAMZAP=m -+CONFIG_IR_IGUANA=m ++CONFIG_IR_TOY=m +CONFIG_IR_TTUSBIR=m ++CONFIG_RC_ATI_REMOTE=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=m +CONFIG_USB_GSPCA_BENQ=m +CONFIG_USB_GSPCA_CONEX=m +CONFIG_USB_GSPCA_CPIA1=m @@ -45249,13 +62475,13 @@ +CONFIG_USB_GSPCA_SN9C20X=m +CONFIG_USB_GSPCA_SONIXB=m +CONFIG_USB_GSPCA_SONIXJ=m ++CONFIG_USB_GSPCA_SPCA1528=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 @@ -45265,103 +62491,133 @@ +CONFIG_USB_GSPCA_SUNPLUS=m +CONFIG_USB_GSPCA_T613=m +CONFIG_USB_GSPCA_TOPRO=m ++CONFIG_USB_GSPCA_TOUPTEK=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_GL860=m ++CONFIG_USB_M5602=m ++CONFIG_USB_STV06XX=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_USB_VIDEO_CLASS=m +CONFIG_VIDEO_GO7007=m +CONFIG_VIDEO_GO7007_USB=m +CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m ++CONFIG_VIDEO_HDPVR=m ++CONFIG_VIDEO_PVRUSB2=m ++CONFIG_VIDEO_STK1160=m +CONFIG_VIDEO_AU0828=m ++CONFIG_DVB_AS102=m ++CONFIG_DVB_B2C2_FLEXCOP_USB=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_DVBSKY=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_SAA7706H=m +CONFIG_RADIO_SHARK=m +CONFIG_RADIO_SHARK2=m -+CONFIG_USB_KEENE=m -+CONFIG_USB_MA901=m ++CONFIG_RADIO_SI4713=m +CONFIG_RADIO_TEA5764=m -+CONFIG_RADIO_SAA7706H=m +CONFIG_RADIO_TEF6862=m +CONFIG_RADIO_WL1273=m ++CONFIG_USB_DSBR=m ++CONFIG_USB_KEENE=m ++CONFIG_USB_MA901=m ++CONFIG_USB_MR800=m ++CONFIG_RADIO_SI470X=m ++CONFIG_USB_SI470X=m ++CONFIG_I2C_SI470X=m ++CONFIG_I2C_SI4713=m +CONFIG_RADIO_WL128X=m +CONFIG_V4L_PLATFORM_DRIVERS=y ++CONFIG_VIDEO_MUX=m +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_VIMC=m ++CONFIG_VIDEO_VIVID=m ++CONFIG_VIDEO_ARDUCAM_64MP=m ++CONFIG_VIDEO_ARDUCAM_PIVARIETY=m +CONFIG_VIDEO_IMX219=m ++CONFIG_VIDEO_IMX258=m +CONFIG_VIDEO_IMX290=m ++CONFIG_VIDEO_IMX296=m +CONFIG_VIDEO_IMX477=m +CONFIG_VIDEO_IMX519=m ++CONFIG_VIDEO_IMX708=m ++CONFIG_VIDEO_MT9V011=m ++CONFIG_VIDEO_OV2311=m +CONFIG_VIDEO_OV5647=m ++CONFIG_VIDEO_OV64A40=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV7640=m -+CONFIG_VIDEO_OV9281=m ++CONFIG_VIDEO_OV9282=m ++CONFIG_VIDEO_AD5398=m ++CONFIG_VIDEO_AK7375=m ++CONFIG_VIDEO_BU64754=m ++CONFIG_VIDEO_DW9807_VCM=m ++CONFIG_VIDEO_SONY_BTF_MPX=m ++CONFIG_VIDEO_UDA1342=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_IRS1125=m -+CONFIG_VIDEO_MT9V011=m ++CONFIG_VIDEO_I2C=m +CONFIG_DRM=m +CONFIG_DRM_LOAD_EDID_FIRMWARE=y +CONFIG_DRM_UDL=m +CONFIG_DRM_PANEL_SIMPLE=m ++CONFIG_DRM_PANEL_ILITEK_ILI9806E=m ++CONFIG_DRM_PANEL_ILITEK_ILI9881C=m +CONFIG_DRM_PANEL_JDI_LT070ME05000=m +CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m ++CONFIG_DRM_PANEL_SITRONIX_ST7701=m ++CONFIG_DRM_PANEL_TPO_Y17P=m ++CONFIG_DRM_PANEL_WAVESHARE_TOUCHSCREEN=m +CONFIG_DRM_DISPLAY_CONNECTOR=m +CONFIG_DRM_SIMPLE_BRIDGE=m +CONFIG_DRM_TOSHIBA_TC358762=m +CONFIG_DRM_VC4=m +CONFIG_DRM_VC4_HDMI_CEC=y ++CONFIG_DRM_PANEL_MIPI_DBI=m ++CONFIG_TINYDRM_HX8357D=m ++CONFIG_TINYDRM_ILI9225=m ++CONFIG_TINYDRM_ILI9341=m ++CONFIG_TINYDRM_ILI9486=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_PWM=m +CONFIG_BACKLIGHT_RPI=m ++CONFIG_BACKLIGHT_LM3630A=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 @@ -45370,6 +62626,7 @@ +CONFIG_SND_OSSEMUL=y +CONFIG_SND_PCM_OSS=m +CONFIG_SND_HRTIMER=m ++CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_DUMMY=m @@ -45383,10 +62640,12 @@ +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y +CONFIG_SND_USB_6FIRE=m ++CONFIG_SND_USB_HIFACE=m +CONFIG_SND_USB_TONEPORT=m +CONFIG_SND_SOC=m +CONFIG_SND_BCM2835_SOC_I2S=m +CONFIG_SND_BCM2708_SOC_CHIPDIP_DAC=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 @@ -45396,6 +62655,7 @@ +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 @@ -45407,31 +62667,45 @@ +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_DACBERRY400=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_TLV320AIC23_I2C=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 @@ -45459,14 +62733,19 @@ +CONFIG_HID_MICROSOFT=m +CONFIG_HID_MONTEREY=m +CONFIG_HID_MULTITOUCH=m ++CONFIG_HID_NINTENDO=m ++CONFIG_NINTENDO_FF=y +CONFIG_HID_NTRIG=m +CONFIG_HID_ORTEK=m +CONFIG_HID_PANTHERLORD=m +CONFIG_HID_PETALYNX=m +CONFIG_HID_PICOLCD=m ++CONFIG_HID_PLAYSTATION=m ++CONFIG_PLAYSTATION_FF=y +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 @@ -45482,7 +62761,6 @@ +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 @@ -45510,6 +62788,7 @@ +CONFIG_USBIP_VHCI_HCD=m +CONFIG_USBIP_HOST=m +CONFIG_USB_DWC2=y ++CONFIG_USB_DWC2_HOST=y +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_AIRCABLE=m @@ -45550,7 +62829,6 @@ +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 @@ -45568,7 +62846,6 @@ +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 @@ -45581,7 +62858,41 @@ +CONFIG_USB_CXACRU=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_XUSBATM=m -+CONFIG_USB_GADGET=m ++CONFIG_NOP_USB_XCEIV=y ++CONFIG_USB_GADGET=y ++CONFIG_U_SERIAL_CONSOLE=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_UAC1_LEGACY=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 @@ -45592,6 +62903,7 @@ +CONFIG_MMC_SDHCI_IPROC=m +CONFIG_MMC_SPI=m +CONFIG_LEDS_CLASS=y ++CONFIG_LEDS_CLASS_MULTICOLOR=m +CONFIG_LEDS_PCA9532=m +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_PCA955X=m @@ -45603,7 +62915,6 @@ +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 @@ -45638,6 +62949,8 @@ +CONFIG_RTC_DRV_RX8025=m +CONFIG_RTC_DRV_EM3027=m +CONFIG_RTC_DRV_RV3028=m ++CONFIG_RTC_DRV_RV3032=m ++CONFIG_RTC_DRV_RV8803=m +CONFIG_RTC_DRV_SD3078=m +CONFIG_RTC_DRV_M41T93=m +CONFIG_RTC_DRV_M41T94=m @@ -45664,10 +62977,9 @@ +CONFIG_STAGING=y +CONFIG_PRISM2_USB=m +CONFIG_R8712U=m -+CONFIG_R8188EU=m +CONFIG_VT6656=m +CONFIG_STAGING_MEDIA=y -+CONFIG_ASHMEM=y ++CONFIG_STAGING_MEDIA_DEPRECATED=y +CONFIG_FB_TFT=m +CONFIG_FB_TFT_AGM1264K_FL=m +CONFIG_FB_TFT_BD663474=m @@ -45692,11 +63004,12 @@ +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_UC1611=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 @@ -45707,28 +63020,43 @@ +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_IIO_SW_TRIGGER=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_SPS30_I2C=m +CONFIG_MAX30102=m +CONFIG_DHT11=m ++CONFIG_HDC100X=m +CONFIG_HTU21=m ++CONFIG_SI7020=m ++CONFIG_BOSCH_BNO055_I2C=m ++CONFIG_INV_MPU6050_I2C=m +CONFIG_APDS9960=m +CONFIG_BH1750=m ++CONFIG_TSL4531=m ++CONFIG_VEML6070=m ++CONFIG_IIO_HRTIMER_TRIGGER=m ++CONFIG_IIO_INTERRUPT_TRIGGER=m ++CONFIG_IIO_SYSFS_TRIGGER=m ++CONFIG_BMP280=m ++CONFIG_MS5637=m +CONFIG_MAXIM_THERMOCOUPLE=m +CONFIG_MAX31856=m ++CONFIG_PWM=y +CONFIG_PWM_BCM2835=m +CONFIG_PWM_PCA9685=m -+CONFIG_ANDROID=y ++CONFIG_PWM_RASPBERRYPI_POE=m ++CONFIG_RPI_AXIPERF=m +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDERFS=y ++CONFIG_NVMEM_RMEM=m ++CONFIG_MUX_GPIO=m +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y @@ -45755,13 +63083,12 @@ +CONFIG_FANOTIFY=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m -+CONFIG_AUTOFS4_FS=y ++CONFIG_AUTOFS_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 @@ -45773,6 +63100,7 @@ +CONFIG_EXFAT_FS=m +CONFIG_NTFS_FS=m +CONFIG_NTFS_RW=y ++CONFIG_NTFS3_FS=m +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ECRYPT_FS=m @@ -45785,6 +63113,9 @@ +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y ++CONFIG_PSTORE=y ++CONFIG_PSTORE_CONSOLE=y ++CONFIG_PSTORE_RAM=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y @@ -45794,14 +63125,18 @@ +CONFIG_ROOT_NFS=y +CONFIG_NFS_FSCACHE=y +CONFIG_NFSD=m ++CONFIG_NFSD_V2=y ++CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y ++CONFIG_CEPH_FS=m +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_SMB_SERVER=m +CONFIG_9P_FS=m +CONFIG_9P_FS_POSIX_ACL=y +CONFIG_NLS_DEFAULT="utf8" @@ -45843,28 +63178,37 @@ +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_DLM=m ++CONFIG_KEY_DH_OPERATIONS=y +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_CRYPTD=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_DES=y ++CONFIG_CRYPTO_TWOFISH=m ++CONFIG_CRYPTO_ADIANTUM=m ++CONFIG_CRYPTO_CHACHA20POLY1305=m ++CONFIG_CRYPTO_MD4=m ++CONFIG_CRYPTO_SHA512=m ++CONFIG_CRYPTO_WP512=m ++CONFIG_CRYPTO_XCBC=m +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_AES_ARM64=m ++CONFIG_CRYPTO_AES_ARM64_BS=m ++# CONFIG_CRYPTO_HW is not set ++CONFIG_PKCS8_PRIVATE_KEY_PARSER=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_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1f6 +CONFIG_KGDB=y +CONFIG_KGDB_KDB=y +CONFIG_KDB_KEYBOARD=y @@ -45873,33 +63217,22 @@ +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 --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig -index 5e7d86cf5dfa..73caaa8ceb96 100644 ---- a/arch/arm64/configs/defconfig -+++ b/arch/arm64/configs/defconfig -@@ -1027,6 +1027,7 @@ CONFIG_ROCKCHIP_EFUSE=y - 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 ++# CONFIG_UPROBE_EVENTS is not set diff --git a/arch/arm64/crypto/aes-cipher-glue.c b/arch/arm64/crypto/aes-cipher-glue.c -index 8caf6dfefce8..2c5772889bdf 100644 +index 4ec55e568941..bfaa0f1d3cc6 100644 --- a/arch/arm64/crypto/aes-cipher-glue.c +++ b/arch/arm64/crypto/aes-cipher-glue.c -@@ -9,6 +9,16 @@ - #include <linux/crypto.h> +@@ -9,6 +9,17 @@ + #include <crypto/algapi.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("xctr(aes)"); +MODULE_ALIAS_CRYPTO("cts(cbc(aes))"); +MODULE_ALIAS_CRYPTO("essiv(cbc(aes),sha256)"); +MODULE_ALIAS_CRYPTO("cmac(aes)"); @@ -45910,12 +63243,12 @@ asmlinkage void __aes_arm64_decrypt(u32 *rk, u8 *out, const u8 *in, int rounds); diff --git a/arch/arm64/crypto/aes-glue.c b/arch/arm64/crypto/aes-glue.c -index 3de1dc918ad4..d6a1f5d13af0 100644 +index 162787c7aa86..0b9626c8789e 100644 --- a/arch/arm64/crypto/aes-glue.c +++ b/arch/arm64/crypto/aes-glue.c -@@ -55,17 +55,17 @@ MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 Crypto Extensions"); +@@ -57,18 +57,18 @@ MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS/XCTR using ARMv8 Crypto Extensions"); #define aes_mac_update neon_aes_mac_update - MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 NEON"); + MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS/XCTR using ARMv8 NEON"); #endif -#if defined(USE_V8_CRYPTO_EXTENSIONS) || !IS_ENABLED(CONFIG_CRYPTO_AES_ARM64_BS) +#if defined(USE_V8_CRYPTO_EXTENSIONS) @@ -45923,6 +63256,7 @@ MODULE_ALIAS_CRYPTO("cbc(aes)"); MODULE_ALIAS_CRYPTO("ctr(aes)"); MODULE_ALIAS_CRYPTO("xts(aes)"); + MODULE_ALIAS_CRYPTO("xctr(aes)"); -#endif MODULE_ALIAS_CRYPTO("cts(cbc(aes))"); MODULE_ALIAS_CRYPTO("essiv(cbc(aes),sha256)"); @@ -45934,7 +63268,7 @@ MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>"); MODULE_LICENSE("GPL v2"); diff --git a/arch/arm64/crypto/aes-neonbs-glue.c b/arch/arm64/crypto/aes-neonbs-glue.c -index fb507d569922..cc52829d426a 100644 +index 467ac2f768ac..813ae2bbbd52 100644 --- a/arch/arm64/crypto/aes-neonbs-glue.c +++ b/arch/arm64/crypto/aes-neonbs-glue.c @@ -18,11 +18,6 @@ @@ -45950,12 +63284,12 @@ asmlinkage void aesbs_ecb_encrypt(u8 out, u8 const in, u8 const rk, diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c -index ba0d6b35461b..750f7239e86c 100644 +index fd0f291e215e..b843b686affd 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c -@@ -182,10 +182,15 @@ static void __init register_insn_emulation(struct insn_emulation_ops *ops) +@@ -539,9 +539,14 @@ static void __init register_insn_emulation(struct insn_emulation *insn) - switch (ops->status) { + switch (insn->status) { case INSN_DEPRECATED: +#if 0 insn->current_mode = INSN_EMULATE; @@ -45964,13 +63298,12 @@ +#else + insn->current_mode = INSN_HW; + run_all_cpu_set_hw_mode(insn, true); - insn->max = INSN_HW; +#endif + insn->max = INSN_HW; break; case INSN_OBSOLETE: - insn->current_mode = INSN_UNDEF; diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c -index e658b7a17d9b..37713bc17336 100644 +index eecedf5b67fa..33ac8dfb30ca 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -17,6 +17,7 @@ @@ -45981,7 +63314,7 @@ #include <linux/personality.h> #include <linux/preempt.h> #include <linux/printk.h> -@@ -138,6 +139,10 @@ static int c_show(struct seq_file *m, void *v) +@@ -178,6 +179,10 @@ static int c_show(struct seq_file *m, void *v) { int i, j; bool aarch32 = personality(current->personality) == PER_LINUX32; @@ -45992,12 +63325,10 @@ for_each_online_cpu(i) { struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i); -@@ -198,6 +203,26 @@ static int c_show(struct seq_file *m, void *v) +@@ -238,6 +243,24 @@ static int c_show(struct seq_file *m, void *v) 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)) @@ -46019,30 +63350,84 @@ return 0; } -diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 538232b4c42a..3e78f429fc49 100644 ---- a/drivers/bluetooth/btusb.c -+++ b/drivers/bluetooth/btusb.c -@@ -436,6 +436,14 @@ static const struct usb_device_id blacklist_table = { - { USB_DEVICE(0x0bda, 0xb009), .driver_info = BTUSB_REALTEK }, - { USB_DEVICE(0x2ff8, 0xb011), .driver_info = BTUSB_REALTEK }, - -+ /* Additional Realtek 8761B Bluetooth devices */ -+ { USB_DEVICE(0x2357, 0x0604), .driver_info = BTUSB_REALTEK | -+ BTUSB_WIDEBAND_SPEECH }, -+ -+ /* Additional Realtek 8761BU Bluetooth devices */ -+ { USB_DEVICE(0x0b05, 0x190e), .driver_info = BTUSB_REALTEK | -+ BTUSB_WIDEBAND_SPEECH }, -+ - /* Additional Realtek 8821AE Bluetooth devices */ - { USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK }, - { USB_DEVICE(0x13d3, 0x3414), .driver_info = BTUSB_REALTEK }, +diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c +index 068e5bb2661b..0465e6645537 100644 +--- a/arch/arm64/kernel/process.c ++++ b/arch/arm64/kernel/process.c +@@ -96,9 +96,7 @@ void machine_shutdown(void) + */ + void machine_halt(void) + { +- local_irq_disable(); +- smp_send_stop(); +- while (1); ++ machine_power_off(); + } + + /* +diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c +index 95cb22c083c8..d8cdca9144ba 100644 +--- a/arch/arm64/kernel/setup.c ++++ b/arch/arm64/kernel/setup.c +@@ -269,9 +269,9 @@ static void __init request_standard_resources(void) + size_t res_size; + + kernel_code.start = __pa_symbol(_stext); +- kernel_code.end = __pa_symbol(__init_begin - 1); ++ kernel_code.end = __pa_symbol(__init_begin) - 1; + kernel_data.start = __pa_symbol(_sdata); +- kernel_data.end = __pa_symbol(_end - 1); ++ kernel_data.end = __pa_symbol(_end) - 1; + insert_resource(&iomem_resource, &kernel_code); + insert_resource(&iomem_resource, &kernel_data); + +diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c +index 0a5445ac5e1b..3029004fa262 100644 +--- a/drivers/bluetooth/btbcm.c ++++ b/drivers/bluetooth/btbcm.c +@@ -24,12 +24,15 @@ + #define BDADDR_BCM20702A1 (&(bdaddr_t) {{0x00, 0x00, 0xa0, 0x02, 0x70, 0x20}}) + #define BDADDR_BCM2076B1 (&(bdaddr_t) {{0x79, 0x56, 0x00, 0xa0, 0x76, 0x20}}) + #define BDADDR_BCM43430A0 (&(bdaddr_t) {{0xac, 0x1f, 0x12, 0xa0, 0x43, 0x43}}) +-#define BDADDR_BCM43430A1 (&(bdaddr_t) {{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}}) ++#define BDADDR_BCM43430A1 (&(bdaddr_t) {{0xac, 0x1f, 0x12, 0xa1, 0x43, 0x43}}) ++#define BDADDR_BCM43430B0 (&(bdaddr_t) {{0xac, 0x1f, 0x37, 0xb0, 0x43, 0x43}}) + #define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}}) + #define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}}) + #define BDADDR_BCM4334B0 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb0, 0x34, 0x43}}) ++#define BDADDR_BCM4345C0 (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0xc0, 0x45, 0x43}}) + #define BDADDR_BCM4345C5 (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0xc5, 0x45, 0x43}}) + #define BDADDR_BCM43341B (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0x1b, 0x34, 0x43}}) ++#define BDADDR_BCM43438 (&(bdaddr_t) {{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}}) + + #define BCM_FW_NAME_LEN 64 + #define BCM_FW_NAME_COUNT_MAX 4 +@@ -126,9 +129,12 @@ int btbcm_check_bdaddr(struct hci_dev *hdev) + !bacmp(&bda->bdaddr, BDADDR_BCM4324B3) || + !bacmp(&bda->bdaddr, BDADDR_BCM4330B1) || + !bacmp(&bda->bdaddr, BDADDR_BCM4334B0) || ++ !bacmp(&bda->bdaddr, BDADDR_BCM4345C0) || + !bacmp(&bda->bdaddr, BDADDR_BCM4345C5) || + !bacmp(&bda->bdaddr, BDADDR_BCM43430A0) || + !bacmp(&bda->bdaddr, BDADDR_BCM43430A1) || ++ !bacmp(&bda->bdaddr, BDADDR_BCM43430B0) || ++ !bacmp(&bda->bdaddr, BDADDR_BCM43438) || + !bacmp(&bda->bdaddr, BDADDR_BCM43341B)) { + /* Try falling back to BDADDR EFI variable */ + if (btbcm_set_bdaddr_from_efi(hdev) != 0) { +@@ -514,6 +520,7 @@ static const struct bcm_subver_table bcm_uart_subver_table = { + { 0x4106, "BCM4335A0" }, /* 002.001.006 */ + { 0x410c, "BCM43430B0" }, /* 002.001.012 */ + { 0x2119, "BCM4373A0" }, /* 001.001.025 */ ++ { 0x2310, "BCM4343A2" }, /* 001.003.016 */ + { } + }; + diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c -index 996729e78105..6d179e455721 100644 +index 71e748a9477e..c58c16817e97 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c -@@ -343,7 +343,8 @@ static void h5_handle_internal_rx(struct hci_uart *hu) +@@ -357,7 +357,8 @@ static void h5_handle_internal_rx(struct hci_uart *hu) h5_link_control(hu, conf_req, 3); } else if (memcmp(data, conf_req, 2) == 0) { h5_link_control(hu, conf_rsp, 2); @@ -46053,7 +63438,7 @@ if (H5_HDR_LEN(hdr) > 2) h5->tx_win = (data2 & 0x07); diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig -index f75f9e3ea324..636e68e4eaeb 100644 +index 625af75833fc..96c3c37b7577 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -5,6 +5,8 @@ @@ -46065,23 +63450,35 @@ source "drivers/tty/Kconfig" config TTY_PRINTK +@@ -422,4 +424,12 @@ config ADI + and SSM (Silicon Secured Memory). Intended consumers of this + driver include crash and makedumpfile. + ++config RASPBERRYPI_GPIOMEM ++ tristate "Rootless GPIO access via mmap() on Raspberry Pi boards" ++ default n ++ help ++ Provides users with root-free access to the GPIO registers ++ on the board. Calling mmap(/dev/gpiomem) will map the GPIO ++ register page to the user's pointer. ++ + endmenu diff --git a/drivers/char/Makefile b/drivers/char/Makefile -index 362d4a9cd4cf..eea88cef9829 100644 +index c5f532e412f1..2ae16025a64b 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile -@@ -47,5 +47,6 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o - obj-$(CONFIG_XILLYBUS) += xillybus/ +@@ -44,3 +44,5 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o + obj-$(CONFIG_XILLYBUS_CLASS) += xillybus/ obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o obj-$(CONFIG_ADI) += adi.o +obj-$(CONFIG_BRCM_CHAR_DRIVERS) += broadcom/ - obj-$(CONFIG_PIN_MEMORY_DEV) += pin_memory.o - obj-$(CONFIG_HISI_SVM) += svm.o ++obj-$(CONFIG_RASPBERRYPI_GPIOMEM) += raspberrypi-gpiomem.o diff --git a/drivers/char/broadcom/Kconfig b/drivers/char/broadcom/Kconfig new file mode 100644 -index 000000000000..e555e841b8db +index 000000000000..29d880d47282 --- /dev/null +++ b/drivers/char/broadcom/Kconfig -@@ -0,0 +1,49 @@ +@@ -0,0 +1,33 @@ +# +# Broadcom char driver config +# @@ -46107,14 +63504,6 @@ + +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 @@ -46123,292 +63512,18 @@ + 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 --git a/drivers/char/broadcom/Makefile b/drivers/char/broadcom/Makefile new file mode 100644 -index 000000000000..a302fb3ff91a +index 000000000000..2ae3e9d411e9 --- /dev/null +++ b/drivers/char/broadcom/Makefile -@@ -0,0 +1,5 @@ +@@ -0,0 +1,3 @@ +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 --git a/drivers/char/broadcom/bcm2835-gpiomem.c b/drivers/char/broadcom/bcm2835-gpiomem.c -new file mode 100644 -index 000000000000..f5e7f1ba8fb6 ---- /dev/null -+++ b/drivers/char/broadcom/bcm2835-gpiomem.c -@@ -0,0 +1,258 @@ -+/** -+ * 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 --git a/drivers/char/broadcom/bcm2835_smi_dev.c b/drivers/char/broadcom/bcm2835_smi_dev.c new file mode 100644 -index 000000000000..34976fa4ed59 +index 000000000000..905f50218cc9 --- /dev/null +++ b/drivers/char/broadcom/bcm2835_smi_dev.c @@ -0,0 +1,409 @@ @@ -46747,7 +63862,7 @@ + + /* Create sysfs entries */ + -+ bcm2835_smi_class = class_create(THIS_MODULE, DEVICE_NAME); ++ bcm2835_smi_class = class_create(DEVICE_NAME); + ptr_err = bcm2835_smi_class; + if (IS_ERR(ptr_err)) + goto failed_class_create; @@ -46821,288 +63936,12 @@ +MODULE_DESCRIPTION( + "Character device driver for BCM2835's secondary memory interface"); +MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>"); -diff --git a/drivers/char/broadcom/rpivid-mem.c b/drivers/char/broadcom/rpivid-mem.c -new file mode 100644 -index 000000000000..9f38083f4cb6 ---- /dev/null -+++ b/drivers/char/broadcom/rpivid-mem.c -@@ -0,0 +1,270 @@ -+// 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 --git a/drivers/char/broadcom/vc_mem.c b/drivers/char/broadcom/vc_mem.c new file mode 100644 -index 000000000000..195b61a4387c +index 000000000000..5e99ac59aaea --- /dev/null +++ b/drivers/char/broadcom/vc_mem.c -@@ -0,0 +1,373 @@ +@@ -0,0 +1,632 @@ +/* + * Copyright 2010 - 2011 Broadcom Corporation. All rights reserved. + * @@ -47128,9 +63967,21 @@ +#include <linux/uaccess.h> +#include <linux/dma-mapping.h> +#include <linux/broadcom/vc_mem.h> ++#include <linux/compat.h> ++#include <linux/platform_data/dma-bcm2708.h> ++#include <soc/bcm2835/raspberrypi-firmware.h> + +#define DRIVER_NAME "vc-mem" + ++/* N.B. These use a different magic value for compatibility with bmc7208_fb */ ++#define VC_MEM_IOC_DMACOPY _IOW('z', 0x22, struct vc_mem_dmacopy) ++#define VC_MEM_IOC_DMACOPY32 _IOW('z', 0x22, struct vc_mem_dmacopy32) ++ ++/* address with no aliases */ ++#define INTALIAS_NORMAL(x) ((x) & ~0xc0000000) ++/* cache coherent but non-allocating in L1 and L2 */ ++#define INTALIAS_L1L2_NONALLOCATING(x) (((x) & ~0xc0000000) | 0x80000000) ++ +/* Device (/dev) related variables */ +static dev_t vc_mem_devnum; +static struct class *vc_mem_class; @@ -47141,6 +63992,20 @@ +static struct dentry *vc_mem_debugfs_entry; +#endif + ++struct vc_mem_dmacopy { ++ void *dst; ++ __u32 src; ++ __u32 length; ++}; ++ ++#ifdef CONFIG_COMPAT ++struct vc_mem_dmacopy32 { ++ compat_uptr_t dst; ++ __u32 src; ++ __u32 length; ++}; ++#endif ++ +/* + * Videocore memory addresses and size + * @@ -47167,6 +64032,20 @@ +static uint mem_size; +static uint mem_base; + ++struct vc_mem_dma { ++ struct device *dev; ++ int dma_chan; ++ int dma_irq; ++ void __iomem *dma_chan_base; ++ wait_queue_head_t dma_waitq; ++ void *cb_base; /* DMA control blocks */ ++ dma_addr_t cb_handle; ++}; ++ ++struct { u32 base, length; } gpu_mem; ++static struct mutex dma_mutex; ++static struct vc_mem_dma vc_mem_dma; ++ +static int +vc_mem_open(struct inode *inode, struct file *file) +{ @@ -47204,6 +64083,189 @@ +} +EXPORT_SYMBOL_GPL(vc_mem_get_current_size); + ++static int ++vc_mem_dma_init(void) ++{ ++ struct vc_mem_dma *vcdma = &vc_mem_dma; ++ struct platform_device *pdev; ++ struct device_node *fwnode; ++ struct rpi_firmware *fw; ++ struct device *dev; ++ u32 revision; ++ int rc; ++ ++ if (vcdma->dev) ++ return 0; ++ ++ fwnode = of_find_node_by_path("/system"); ++ rc = of_property_read_u32(fwnode, "linux,revision", &revision); ++ revision = (revision >> 12) & 0xf; ++ if (revision != 1 && revision != 2) { ++ /* Only BCM2709 and BCM2710 may have logs where the ARMs ++ * can't see them. ++ */ ++ return -ENXIO; ++ } ++ ++ fwnode = rpi_firmware_find_node(); ++ if (!fwnode) ++ return -ENXIO; ++ ++ pdev = of_find_device_by_node(fwnode); ++ dev = &pdev->dev; ++ ++ rc = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); ++ if (rc) ++ return rc; ++ ++ fw = rpi_firmware_get(fwnode); ++ if (!fw) ++ return -ENXIO; ++ rc = rpi_firmware_property(fw, RPI_FIRMWARE_GET_VC_MEMORY, ++ &gpu_mem, sizeof(gpu_mem)); ++ if (rc) ++ return rc; ++ ++ gpu_mem.base = INTALIAS_NORMAL(gpu_mem.base); ++ ++ if (!gpu_mem.base || !gpu_mem.length) { ++ dev_err(dev, "%s: unable to determine gpu memory (%x,%x)\n", ++ __func__, gpu_mem.base, gpu_mem.length); ++ return -EFAULT; ++ } ++ ++ vcdma->cb_base = dma_alloc_wc(dev, SZ_4K, &vcdma->cb_handle, GFP_KERNEL); ++ if (!vcdma->cb_base) { ++ dev_err(dev, "failed to allocate DMA CBs\n"); ++ return -ENOMEM; ++ } ++ ++ rc = bcm_dma_chan_alloc(BCM_DMA_FEATURE_BULK, ++ &vcdma->dma_chan_base, ++ &vcdma->dma_irq); ++ if (rc < 0) { ++ dev_err(dev, "failed to allocate a DMA channel\n"); ++ goto free_cb; ++ } ++ ++ vcdma->dma_chan = rc; ++ ++ init_waitqueue_head(&vcdma->dma_waitq); ++ ++ vcdma->dev = dev; ++ ++ return 0; ++ ++free_cb: ++ dma_free_wc(dev, SZ_4K, vcdma->cb_base, vcdma->cb_handle); ++ ++ return rc; ++} ++ ++static void ++vc_mem_dma_uninit(void) ++{ ++ struct vc_mem_dma *vcdma = &vc_mem_dma; ++ ++ if (vcdma->dev) { ++ bcm_dma_chan_free(vcdma->dma_chan); ++ dma_free_wc(vcdma->dev, SZ_4K, vcdma->cb_base, vcdma->cb_handle); ++ vcdma->dev = NULL; ++ } ++} ++ ++static int dma_memcpy(struct vc_mem_dma *vcdma, dma_addr_t dst, dma_addr_t src, ++ int size) ++{ ++ struct bcm2708_dma_cb *cb = vcdma->cb_base; ++ int burst_size = (vcdma->dma_chan == 0) ? 8 : 2; ++ ++ cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH | ++ BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH | ++ BCM2708_DMA_D_INC; ++ cb->dst = dst; ++ cb->src = src; ++ cb->length = size; ++ cb->stride = 0; ++ cb->pad0 = 0; ++ cb->pad1 = 0; ++ cb->next = 0; ++ ++ bcm_dma_start(vcdma->dma_chan_base, vcdma->cb_handle); ++ bcm_dma_wait_idle(vcdma->dma_chan_base); ++ ++ return 0; ++} ++ ++static long vc_mem_copy(struct vc_mem_dmacopy *ioparam) ++{ ++ struct vc_mem_dma *vcdma = &vc_mem_dma; ++ size_t size = PAGE_SIZE; ++ const u32 dma_xfer_chunk = 256; ++ u32 *buf = NULL; ++ dma_addr_t bus_addr; ++ long rc = 0; ++ size_t offset; ++ ++ /* restrict this to root user */ ++ if (!uid_eq(current_euid(), GLOBAL_ROOT_UID)) ++ return -EFAULT; ++ ++ if (mutex_lock_interruptible(&dma_mutex)) ++ return -EINTR; ++ ++ rc = vc_mem_dma_init(); ++ if (rc) ++ goto out; ++ ++ vcdma = &vc_mem_dma; ++ ++ if (INTALIAS_NORMAL(ioparam->src) < gpu_mem.base || ++ INTALIAS_NORMAL(ioparam->src) >= gpu_mem.base + gpu_mem.length) { ++ pr_err("%s: invalid memory access %x (%x-%x)", __func__, ++ INTALIAS_NORMAL(ioparam->src), gpu_mem.base, ++ gpu_mem.base + gpu_mem.length); ++ rc = -EFAULT; ++ goto out; ++ } ++ ++ buf = dma_alloc_coherent(vcdma->dev, PAGE_ALIGN(size), &bus_addr, ++ GFP_ATOMIC); ++ if (!buf) { ++ rc = -ENOMEM; ++ goto out; ++ } ++ ++ for (offset = 0; offset < ioparam->length; offset += size) { ++ size_t remaining = ioparam->length - offset; ++ size_t s = min(size, remaining); ++ u8 *p = (u8 *)((uintptr_t)ioparam->src + offset); ++ u8 *q = (u8 *)ioparam->dst + offset; ++ ++ rc = dma_memcpy(vcdma, bus_addr, ++ INTALIAS_L1L2_NONALLOCATING((u32)(uintptr_t)p), ++ (s + dma_xfer_chunk - 1) & ~(dma_xfer_chunk - 1)); ++ if (rc) { ++ dev_err(vcdma->dev, "dma_memcpy failed\n"); ++ break; ++ } ++ if (copy_to_user(q, buf, s) != 0) { ++ pr_err("%s: copy_to_user failed\n", __func__); ++ rc = -EFAULT; ++ break; ++ } ++ } ++ ++out: ++ if (buf) ++ dma_free_coherent(vcdma->dev, PAGE_ALIGN(size), buf, ++ bus_addr); ++ ++ mutex_unlock(&dma_mutex); ++ ++ return rc; ++} ++ +static long +vc_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ @@ -47268,6 +64330,21 @@ + } + break; + } ++ case VC_MEM_IOC_DMACOPY: ++ { ++ struct vc_mem_dmacopy ioparam; ++ /* Get the parameter data. ++ */ ++ if (copy_from_user ++ (&ioparam, (void *)arg, sizeof(ioparam))) { ++ pr_err("%s: copy_from_user failed\n", __func__); ++ rc = -EFAULT; ++ break; ++ } ++ ++ rc = vc_mem_copy(&ioparam); ++ break; ++ } + default: + { + return -ENOTTY; @@ -47298,6 +64375,24 @@ + + break; + ++ case VC_MEM_IOC_DMACOPY32: ++ { ++ struct vc_mem_dmacopy32 param32; ++ struct vc_mem_dmacopy param; ++ /* Get the parameter data. ++ */ ++ if (copy_from_user(¶m32, (void *)arg, sizeof(param32))) { ++ pr_err("%s: copy_from_user failed\n", __func__); ++ rc = -EFAULT; ++ break; ++ } ++ param.dst = compat_ptr(param32.dst); ++ param.src = param32.src; ++ param.length = param32.length; ++ rc = vc_mem_copy(¶m); ++ break; ++ } ++ + default: + rc = vc_mem_ioctl(file, cmd, arg); + break; @@ -47415,7 +64510,7 @@ + goto out_unregister; + } + -+ vc_mem_class = class_create(THIS_MODULE, DRIVER_NAME); ++ vc_mem_class = class_create(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); @@ -47435,6 +64530,7 @@ + vc_mem_debugfs_init(dev); +#endif + ++ mutex_init(&dma_mutex); + vc_mem_inited = 1; + return 0; + @@ -47457,14 +64553,16 @@ +{ + pr_debug("%s: called\n", __func__); + ++ vc_mem_dma_uninit(); + if (vc_mem_inited) { -+#if CONFIG_DEBUG_FS ++#ifdef CONFIG_DEBUG_FS + vc_mem_debugfs_deinit(); +#endif + device_destroy(vc_mem_class, vc_mem_devnum); + class_destroy(vc_mem_class); + cdev_del(&vc_mem_cdev); + unregister_chrdev_region(vc_mem_devnum, 1); ++ vc_mem_inited = 0; + } +} + @@ -47669,10 +64767,10 @@ +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rpi-vcio"); diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig -index dda4a9dfad2e..c66453d718d8 100644 +index 7c486989dd04..4ebc94573195 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig -@@ -104,7 +104,7 @@ config HW_RANDOM_IPROC_RNG200 +@@ -105,7 +105,7 @@ config HW_RANDOM_IPROC_RNG200 default HW_RANDOM help This driver provides kernel-side support for the RNG200 @@ -47682,10 +64780,58 @@ To compile this driver as a module, choose M here: the module will be called iproc-rng200 diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c -index 1a7c43b43c6b..ee47667d0710 100644 +index 4c08efe7f375..84c964b63324 100644 --- a/drivers/char/hw_random/bcm2835-rng.c +++ b/drivers/char/hw_random/bcm2835-rng.c -@@ -102,8 +102,10 @@ static int bcm2835_rng_init(struct hwrng *rng) +@@ -13,6 +13,7 @@ + #include <linux/printk.h> + #include <linux/clk.h> + #include <linux/reset.h> ++#include <linux/delay.h> + + #define RNG_CTRL 0x0 + #define RNG_STATUS 0x4 +@@ -27,6 +28,9 @@ + + #define RNG_INT_OFF 0x1 + ++#define RNG_FIFO_WORDS 4 ++#define RNG_US_PER_WORD 34 /* Tuned for throughput */ ++ + struct bcm2835_rng_priv { + struct hwrng rng; + void __iomem *base; +@@ -63,19 +67,23 @@ static inline void rng_writel(struct bcm2835_rng_priv *priv, u32 val, + static int bcm2835_rng_read(struct hwrng *rng, void *buf, size_t max, + bool wait) + { ++ u32 retries = 1000000/(RNG_FIFO_WORDS * RNG_US_PER_WORD); + struct bcm2835_rng_priv *priv = to_rng_priv(rng); + u32 max_words = max / sizeof(u32); + u32 num_words, count; + +- while ((rng_readl(priv, RNG_STATUS) >> 24) == 0) { +- if (!wait) ++ num_words = rng_readl(priv, RNG_STATUS) >> 24; ++ ++ while (!num_words) { ++ if (!wait || !retries) + return 0; +- hwrng_yield(rng); ++ retries--; ++ usleep_range((u32)RNG_US_PER_WORD, ++ (u32)RNG_US_PER_WORD * RNG_FIFO_WORDS); ++ num_words = rng_readl(priv, RNG_STATUS) >> 24; + } + +- num_words = rng_readl(priv, RNG_STATUS) >> 24; +- if (num_words > max_words) +- num_words = max_words; ++ num_words = min(num_words, max_words); + + for (count = 0; count < num_words; count++) + ((u32 *)buf)count = rng_readl(priv, RNG_DATA); +@@ -105,8 +113,10 @@ static int bcm2835_rng_init(struct hwrng *rng) } /* set warm-up count & enable */ @@ -47699,18 +64845,26 @@ return ret; } diff --git a/drivers/char/hw_random/iproc-rng200.c b/drivers/char/hw_random/iproc-rng200.c -index 01583faf9893..2a92ea658096 100644 +index 440fe28bddc0..33bc28f429f6 100644 --- a/drivers/char/hw_random/iproc-rng200.c +++ b/drivers/char/hw_random/iproc-rng200.c -@@ -29,6 +29,7 @@ +@@ -13,6 +13,7 @@ + #include <linux/kernel.h> + #include <linux/module.h> + #include <linux/mod_devicetable.h> ++#include <linux/of.h> + #include <linux/platform_device.h> + #include <linux/delay.h> + +@@ -20,6 +21,7 @@ + #define RNG_CTRL_OFFSET 0x00 #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 -@@ -36,16 +37,23 @@ +@@ -27,16 +29,23 @@ #define RBG_SOFT_RESET_OFFSET 0x08 #define RBG_SOFT_RESET 0x00000001 @@ -47734,7 +64888,7 @@ struct iproc_rng200_dev { struct hwrng rng; -@@ -166,6 +174,64 @@ static int iproc_rng200_init(struct hwrng *rng) +@@ -157,6 +166,64 @@ static int iproc_rng200_init(struct hwrng *rng) return 0; } @@ -47799,9 +64953,9 @@ static void iproc_rng200_cleanup(struct hwrng *rng) { struct iproc_rng200_dev *priv = to_rng_priv(rng); -@@ -195,11 +261,17 @@ static int iproc_rng200_probe(struct platform_device *pdev) - return PTR_ERR(priv->base); - } +@@ -183,11 +250,17 @@ static int iproc_rng200_probe(struct platform_device *pdev) + + dev_set_drvdata(dev, priv); - priv->rng.name = "iproc-rng200"; - priv->rng.read = iproc_rng200_read; @@ -47820,11 +64974,348 @@ /* Register driver */ ret = devm_hwrng_register(dev, &priv->rng); if (ret) { +diff --git a/drivers/char/random.c b/drivers/char/random.c +index b9ae54c243a9..09a441d24065 100644 +--- a/drivers/char/random.c ++++ b/drivers/char/random.c +@@ -843,6 +843,14 @@ void __init random_init_early(const char *command_line) + unsigned long entropyBLAKE2S_BLOCK_SIZE / sizeof(long); + size_t i, longs, arch_bits; + ++ /* ++ * If we were initialized by the bootloader before jump labels are ++ * initialized, then we should enable the static branch here, where ++ * it's guaranteed that jump labels have been initialized. ++ */ ++ if (!static_branch_likely(&crng_is_ready) && crng_init >= CRNG_READY) ++ crng_set_ready(NULL); ++ + #if defined(LATENT_ENTROPY_PLUGIN) + static const u8 compiletime_seedBLAKE2S_BLOCK_SIZE __initconst __latent_entropy; + _mix_pool_bytes(compiletime_seed, sizeof(compiletime_seed)); +diff --git a/drivers/char/raspberrypi-gpiomem.c b/drivers/char/raspberrypi-gpiomem.c +new file mode 100644 +index 000000000000..8606f39a1434 +--- /dev/null ++++ b/drivers/char/raspberrypi-gpiomem.c +@@ -0,0 +1,276 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/** ++ * raspberrypi-gpiomem.c ++ * ++ * Provides MMIO access to discontiguous section of Device memory as a linear ++ * user mapping. Successor to bcm2835-gpiomem.c. ++ * ++ * Copyright (c) 2023, Raspberry Pi Ltd. ++ */ ++ ++#include <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 "rpi-gpiomem" ++#define DEVICE_MINOR 0 ++ ++/* ++ * Sensible max for a hypothetical "gpio" controller that splits pads, ++ * IO controls, GPIO in/out/enable, and function selection into different ++ * ranges. Most use only one or two. ++ */ ++#define MAX_RANGES 4 ++ ++struct io_windows { ++ unsigned long phys_base; ++ unsigned long len; ++}; ++ ++struct rpi_gpiomem_priv { ++ dev_t devid; ++ struct class *class; ++ struct cdev rpi_gpiomem_cdev; ++ struct device *dev; ++ const char *name; ++ unsigned int nr_wins; ++ struct io_windows iowins4; ++}; ++ ++static int rpi_gpiomem_open(struct inode *inode, struct file *file) ++{ ++ int dev = iminor(inode); ++ int ret = 0; ++ struct rpi_gpiomem_priv *priv; ++ ++ if (dev != DEVICE_MINOR) ++ ret = -ENXIO; ++ ++ priv = container_of(inode->i_cdev, struct rpi_gpiomem_priv, ++ rpi_gpiomem_cdev); ++ if (!priv) ++ return -EINVAL; ++ file->private_data = priv; ++ return ret; ++} ++ ++static int rpi_gpiomem_release(struct inode *inode, struct file *file) ++{ ++ int dev = iminor(inode); ++ int ret = 0; ++ ++ if (dev != DEVICE_MINOR) ++ ret = -ENXIO; ++ ++ return ret; ++} ++ ++static const struct vm_operations_struct rpi_gpiomem_vm_ops = { ++#ifdef CONFIG_HAVE_IOREMAP_PROT ++ .access = generic_access_phys ++#endif ++}; ++ ++static int rpi_gpiomem_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int i; ++ struct rpi_gpiomem_priv *priv; ++ unsigned long base; ++ unsigned long len = 0; ++ unsigned long offset; ++ ++ priv = file->private_data; ++ /* ++ * Userspace must provide a virtual address space at least ++ * the size of the concatenated ranges. ++ */ ++ for (i = 0; i < priv->nr_wins; i++) ++ len += priv->iowinsi.len; ++ if (len > vma->vm_end - vma->vm_start + 1) ++ return -EINVAL; ++ ++ vma->vm_ops = &rpi_gpiomem_vm_ops; ++ offset = vma->vm_start; ++ for (i = 0; i < priv->nr_wins; i++) { ++ base = priv->iowinsi.phys_base >> PAGE_SHIFT; ++ len = priv->iowinsi.len; ++ vma->vm_page_prot = phys_mem_access_prot(file, base, len, ++ vma->vm_page_prot); ++ if (remap_pfn_range(vma, offset, ++ base, len, ++ vma->vm_page_prot)) ++ break; ++ offset += len; ++ } ++ ++ if (i < priv->nr_wins) ++ return -EAGAIN; ++ ++ return 0; ++} ++ ++static const struct file_operations rpi_gpiomem_fops = { ++ .owner = THIS_MODULE, ++ .open = rpi_gpiomem_open, ++ .release = rpi_gpiomem_release, ++ .mmap = rpi_gpiomem_mmap, ++}; ++ ++static const struct of_device_id rpi_gpiomem_of_match; ++ ++static int rpi_gpiomem_probe(struct platform_device *pdev) ++{ ++ int err, i; ++ const struct of_device_id *id; ++ struct device *dev = &pdev->dev; ++ struct device_node *node = dev->of_node; ++ struct resource *ioresource; ++ struct rpi_gpiomem_priv *priv; ++ ++ /* Allocate buffers and instance data */ ++ ++ priv = kzalloc(sizeof(struct rpi_gpiomem_priv), GFP_KERNEL); ++ ++ if (!priv) { ++ err = -ENOMEM; ++ goto failed_inst_alloc; ++ } ++ platform_set_drvdata(pdev, priv); ++ ++ priv->dev = dev; ++ id = of_match_device(rpi_gpiomem_of_match, dev); ++ if (!id) ++ return -EINVAL; ++ ++ /* ++ * Device node naming - for legacy (bcm2835) DT bindings, the driver ++ * created the node based on a hardcoded name - for new bindings, ++ * take the node name from DT. ++ */ ++ if (id == &rpi_gpiomem_of_match0) { ++ priv->name = "gpiomem"; ++ } else { ++ err = of_property_read_string(node, "chardev-name", &priv->name); ++ if (err) ++ return -EINVAL; ++ } ++ ++ /* ++ * Go find the register ranges associated with this instance ++ */ ++ for (i = 0; i < MAX_RANGES; i++) { ++ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, i); ++ if (!ioresource && i == 0) { ++ dev_err(priv->dev, "failed to get IO resource - no ranges available\n"); ++ err = -ENOENT; ++ goto failed_get_resource; ++ } ++ if (!ioresource) ++ break; ++ ++ priv->iowinsi.phys_base = ioresource->start; ++ priv->iowinsi.len = (ioresource->end + 1) - ioresource->start; ++ dev_info(&pdev->dev, "window base 0x%08lx size 0x%08lx\n", ++ priv->iowinsi.phys_base, priv->iowinsi.len); ++ priv->nr_wins++; ++ } ++ ++ /* Create character device entries */ ++ ++ err = alloc_chrdev_region(&priv->devid, ++ DEVICE_MINOR, 1, priv->name); ++ if (err != 0) { ++ dev_err(priv->dev, "unable to allocate device number"); ++ goto failed_alloc_chrdev; ++ } ++ cdev_init(&priv->rpi_gpiomem_cdev, &rpi_gpiomem_fops); ++ priv->rpi_gpiomem_cdev.owner = THIS_MODULE; ++ err = cdev_add(&priv->rpi_gpiomem_cdev, priv->devid, 1); ++ if (err != 0) { ++ dev_err(priv->dev, "unable to register device"); ++ goto failed_cdev_add; ++ } ++ ++ /* Create sysfs entries */ ++ ++ priv->class = class_create(priv->name); ++ if (IS_ERR(priv->class)) { ++ err = PTR_ERR(priv->class); ++ goto failed_class_create; ++ } ++ ++ dev = device_create(priv->class, NULL, priv->devid, NULL, priv->name); ++ if (IS_ERR(dev)) { ++ err = PTR_ERR(dev); ++ goto failed_device_create; ++ } ++ ++ dev_info(priv->dev, "initialised %u regions as /dev/%s\n", ++ priv->nr_wins, priv->name); ++ ++ return 0; ++ ++failed_device_create: ++ class_destroy(priv->class); ++failed_class_create: ++ cdev_del(&priv->rpi_gpiomem_cdev); ++failed_cdev_add: ++ unregister_chrdev_region(priv->devid, 1); ++failed_alloc_chrdev: ++failed_get_resource: ++ kfree(priv); ++failed_inst_alloc: ++ dev_err(&pdev->dev, "could not load rpi_gpiomem"); ++ return err; ++} ++ ++static int rpi_gpiomem_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct rpi_gpiomem_priv *priv = platform_get_drvdata(pdev); ++ ++ device_destroy(priv->class, priv->devid); ++ class_destroy(priv->class); ++ cdev_del(&priv->rpi_gpiomem_cdev); ++ unregister_chrdev_region(priv->devid, 1); ++ kfree(priv); ++ ++ dev_info(dev, "%s driver removed - OK", priv->name); ++ return 0; ++} ++ ++static const struct of_device_id rpi_gpiomem_of_match = { ++ { ++ .compatible = "brcm,bcm2835-gpiomem", ++ }, ++ { ++ .compatible = "raspberrypi,gpiomem", ++ }, ++ { /* sentinel */ }, ++}; ++ ++MODULE_DEVICE_TABLE(of, rpi_gpiomem_of_match); ++ ++static struct platform_driver rpi_gpiomem_driver = { ++ .probe = rpi_gpiomem_probe, ++ .remove = rpi_gpiomem_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = rpi_gpiomem_of_match, ++ }, ++}; ++ ++module_platform_driver(rpi_gpiomem_driver); ++ ++MODULE_ALIAS("platform:rpi-gpiomem"); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_DESCRIPTION("Driver for accessing GPIOs from userspace"); ++MODULE_AUTHOR("Jonathan Bell <jonathan@raspberrypi.com>"); +diff --git a/drivers/char/tpm/tpm_tis_spi_main.c b/drivers/char/tpm/tpm_tis_spi_main.c +index c5c3197ee29f..02700cb16f90 100644 +--- a/drivers/char/tpm/tpm_tis_spi_main.c ++++ b/drivers/char/tpm/tpm_tis_spi_main.c +@@ -347,7 +347,11 @@ static struct spi_driver tpm_tis_spi_driver = { + .pm = &tpm_tis_pm, + .of_match_table = of_match_ptr(of_tis_spi_match), + .acpi_match_table = ACPI_PTR(acpi_tis_spi_match), ++#ifdef CONFIG_IMA ++ .probe_type = PROBE_FORCE_SYNCHRONOUS, ++#else + .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++#endif + }, + .probe = tpm_tis_spi_driver_probe, + .remove = tpm_tis_spi_remove, diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig -index c715d4681a0b..32f8921307bd 100644 +index c30099866174..9d3e03565ed6 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig -@@ -86,6 +86,12 @@ config COMMON_CLK_HI655X +@@ -88,6 +88,19 @@ config COMMON_CLK_RK808 + These multi-function devices have two fixed-rate oscillators, clocked at 32KHz each. + Clkout1 is always on, Clkout2 can off by control register. + ++config COMMON_CLK_RP1 ++ tristate "Raspberry Pi RP1-based clock support" ++ depends on PCI || COMPILE_TEST ++ depends on COMMON_CLK ++ help ++ Enable common clock framework support for Raspberry Pi RP1 ++ ++config COMMON_CLK_RP1_SDIO ++ tristate "Clock driver for the RP1 SDIO interfaces" ++ depends on MFD_RP1 ++ help ++ SDIO clock driver for the RP1 support chip ++ + config COMMON_CLK_HI655X + tristate "Clock driver for Hi655x" if EXPERT + depends on (MFD_HI655X_PMIC || COMPILE_TEST) +@@ -98,6 +111,12 @@ config COMMON_CLK_HI655X multi-function device has one fixed-rate oscillator, clocked at 32KHz. @@ -47838,31 +65329,32 @@ tristate "Clock driver controlled via SCMI interface" depends on ARM_SCMI_PROTOCOL || COMPILE_TEST diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile -index da8fcf147eb1..f78099e1d9e7 100644 +index 18969cbd4bb1..0cec77182970 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile -@@ -18,6 +18,7 @@ endif - - # hardware specific clock types - # please keep this section sorted lexicographically by file path name -+obj-$(CONFIG_SND_BCM2708_SOC_ALLO_BOSS_DAC) += clk-allo-dac.o - obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o - obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o - obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o -@@ -37,6 +38,8 @@ obj-$(CONFIG_MACH_ASPEED_G6) += clk-ast2600.o - obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o - obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o +@@ -45,6 +45,8 @@ obj-$(CONFIG_COMMON_CLK_LAN966X) += clk-lan966x.o obj-$(CONFIG_COMMON_CLK_LOCHNAGAR) += clk-lochnagar.o + obj-$(CONFIG_MACH_LOONGSON32) += clk-loongson1.o + obj-$(CONFIG_COMMON_CLK_LOONGSON2) += clk-loongson2.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 +@@ -57,6 +59,8 @@ obj-$(CONFIG_CLK_LS1028A_PLLDIG) += clk-plldig.o + obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o + obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o + obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o ++obj-$(CONFIG_COMMON_CLK_RP1) += clk-rp1.o ++obj-$(CONFIG_COMMON_CLK_RP1_SDIO) += clk-rp1-sdio.o + obj-$(CONFIG_COMMON_CLK_HI655X) += clk-hi655x.o + obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o + obj-$(CONFIG_COMMON_CLK_SCMI) += clk-scmi.o diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c -index 178886823b90..7e74aafddbf8 100644 +index fb04734afc80..eecb2daa423f 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c -@@ -35,6 +35,7 @@ +@@ -36,6 +36,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <dt-bindings/clock/bcm2835.h> @@ -47870,7 +65362,7 @@ #define CM_PASSWORD 0x5a000000 -@@ -295,6 +296,8 @@ +@@ -296,6 +297,8 @@ #define SOC_BCM2711 BIT(1) #define SOC_ALL (SOC_BCM2835 | SOC_BCM2711) @@ -47879,7 +65371,7 @@ /* * 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 -@@ -313,6 +316,7 @@ static const char *const cprman_parent_names = { +@@ -314,6 +317,7 @@ static const char *const cprman_parent_names = { struct bcm2835_cprman { struct device *dev; void __iomem *regs; @@ -47887,7 +65379,7 @@ spinlock_t regs_lock; /* spinlock for all clocks */ unsigned int soc; -@@ -640,15 +644,17 @@ static int bcm2835_pll_on(struct clk_hw *hw) +@@ -643,15 +647,17 @@ static int bcm2835_pll_on(struct clk_hw *hw) spin_unlock(&cprman->regs_lock); /* Wait for the PLL to lock. */ @@ -47913,8 +65405,8 @@ } cprman_write(cprman, data->a2w_ctrl_reg, -@@ -1011,6 +1017,30 @@ static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw, - return bcm2835_clock_rate_from_divisor(clock, parent_rate, div); +@@ -1039,6 +1045,30 @@ static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw, + return rate; } +static unsigned long bcm2835_clock_get_rate_vpu(struct clk_hw *hw, @@ -47944,7 +65436,7 @@ static void bcm2835_clock_wait_busy(struct bcm2835_clock *clock) { struct bcm2835_cprman *cprman = clock->cprman; -@@ -1069,8 +1099,10 @@ static int bcm2835_clock_on(struct clk_hw *hw) +@@ -1097,8 +1127,10 @@ static int bcm2835_clock_on(struct clk_hw *hw) return 0; } @@ -47957,7 +65449,7 @@ { struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); struct bcm2835_cprman *cprman = clock->cprman; -@@ -1080,15 +1112,24 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw, +@@ -1108,15 +1140,24 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw, spin_lock(&cprman->regs_lock); @@ -47990,7 +65482,7 @@ ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0; cprman_write(cprman, data->ctl_reg, ctl); -@@ -1099,6 +1140,12 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw, +@@ -1127,6 +1168,12 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw, return 0; } @@ -48003,7 +65495,7 @@ static bool bcm2835_clk_is_pllc(struct clk_hw *hw) { -@@ -1282,6 +1329,7 @@ static const struct clk_ops bcm2835_clock_clk_ops = { +@@ -1310,6 +1357,7 @@ static const struct clk_ops bcm2835_clock_clk_ops = { .unprepare = bcm2835_clock_off, .recalc_rate = bcm2835_clock_get_rate, .set_rate = bcm2835_clock_set_rate, @@ -48011,7 +65503,7 @@ .determine_rate = bcm2835_clock_determine_rate, .set_parent = bcm2835_clock_set_parent, .get_parent = bcm2835_clock_get_parent, -@@ -1299,7 +1347,7 @@ static int bcm2835_vpu_clock_is_on(struct clk_hw *hw) +@@ -1327,7 +1375,7 @@ static int bcm2835_vpu_clock_is_on(struct clk_hw *hw) */ static const struct clk_ops bcm2835_vpu_clock_clk_ops = { .is_prepared = bcm2835_vpu_clock_is_on, @@ -48020,7 +65512,7 @@ .set_rate = bcm2835_clock_set_rate, .determine_rate = bcm2835_clock_determine_rate, .set_parent = bcm2835_clock_set_parent, -@@ -1307,6 +1355,8 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = { +@@ -1335,6 +1383,8 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = { .debug_init = bcm2835_clock_debug_init, }; @@ -48029,7 +65521,7 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman, const void *data) { -@@ -1324,6 +1374,9 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman, +@@ -1352,6 +1402,9 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman, init.ops = &bcm2835_pll_clk_ops; init.flags = pll_data->flags | CLK_IGNORE_UNUSED; @@ -48039,7 +65531,7 @@ pll = kzalloc(sizeof(*pll), GFP_KERNEL); if (!pll) return NULL; -@@ -1379,6 +1432,13 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, +@@ -1407,6 +1460,13 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, divider->div.hw.init = &init; divider->div.table = NULL; @@ -48053,7 +65545,7 @@ divider->cprman = cprman; divider->data = divider_data; -@@ -1432,6 +1492,15 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman, +@@ -1460,6 +1520,15 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman, init.name = clock_data->name; init.flags = clock_data->flags | CLK_IGNORE_UNUSED; @@ -48069,7 +65561,7 @@ /* * Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate * rate changes on at least of the parents. -@@ -1443,7 +1512,6 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman, +@@ -1471,7 +1540,6 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman, init.ops = &bcm2835_vpu_clock_clk_ops; } else { init.ops = &bcm2835_clock_clk_ops; @@ -48077,7 +65569,7 @@ /* If the clock wasn't actually enabled at boot, it's not * critical. -@@ -1668,16 +1736,12 @@ static const struct bcm2835_clk_desc clk_desc_array = { +@@ -1696,16 +1764,12 @@ static const struct bcm2835_clk_desc clk_desc_array = { .hold_mask = CM_PLLA_HOLDCORE, .fixed_divider = 1, .flags = CLK_SET_RATE_PARENT), @@ -48100,7 +65592,7 @@ BCM2835_PLLA_DSI0 = REGISTER_PLL_DIV( SOC_ALL, .name = "plla_dsi0", -@@ -1978,14 +2042,12 @@ static const struct bcm2835_clk_desc clk_desc_array = { +@@ -2006,14 +2070,12 @@ static const struct bcm2835_clk_desc clk_desc_array = { .int_bits = 6, .frac_bits = 0, .tcnt_mux = 3), @@ -48121,9 +65613,9 @@ /* * 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 -@@ -2147,21 +2209,6 @@ static const struct bcm2835_clk_desc clk_desc_array = { - .frac_bits = 12, - .tcnt_mux = 28), +@@ -2176,21 +2238,6 @@ static const struct bcm2835_clk_desc clk_desc_array = { + .tcnt_mux = 28, + .round_up = true), - /* TV encoder clock. Only operating frequency is 108Mhz. */ - BCM2835_CLOCK_VEC = REGISTER_PER_CLK( @@ -48143,7 +65635,7 @@ /* dsi clocks */ BCM2835_CLOCK_DSI0E = REGISTER_PER_CLK( SOC_ALL, -@@ -2211,6 +2258,8 @@ static const struct bcm2835_clk_desc clk_desc_array = { +@@ -2240,6 +2287,8 @@ static const struct bcm2835_clk_desc clk_desc_array = { .ctl_reg = CM_PERIICTL), }; @@ -48152,7 +65644,7 @@ /* * Permanently take a reference on the parent of the SDRAM clock. * -@@ -2230,6 +2279,21 @@ static int bcm2835_mark_sdc_parent_critical(struct clk *sdc) +@@ -2259,6 +2308,21 @@ static int bcm2835_mark_sdc_parent_critical(struct clk *sdc) return clk_prepare_enable(parent); } @@ -48174,7 +65666,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; -@@ -2238,7 +2302,9 @@ static int bcm2835_clk_probe(struct platform_device *pdev) +@@ -2267,7 +2331,9 @@ static int bcm2835_clk_probe(struct platform_device *pdev) const struct bcm2835_clk_desc *desc; const size_t asize = ARRAY_SIZE(clk_desc_array); const struct cprman_plat_data *pdata; @@ -48184,7 +65676,7 @@ int ret; pdata = of_device_get_match_data(&pdev->dev); -@@ -2257,6 +2323,21 @@ static int bcm2835_clk_probe(struct platform_device *pdev) +@@ -2286,6 +2352,21 @@ static int bcm2835_clk_probe(struct platform_device *pdev) if (IS_ERR(cprman->regs)) return PTR_ERR(cprman->regs); @@ -48206,7 +65698,7 @@ memcpy(cprman->real_parent_names, cprman_parent_names, sizeof(cprman_parent_names)); of_clk_parent_fill(dev->of_node, cprman->real_parent_names, -@@ -2290,8 +2371,15 @@ static int bcm2835_clk_probe(struct platform_device *pdev) +@@ -2319,8 +2400,15 @@ static int bcm2835_clk_probe(struct platform_device *pdev) if (ret) return ret; @@ -48223,7 +65715,7 @@ } static const struct cprman_plat_data cprman_bcm2835_plat_data = { -@@ -2317,7 +2405,11 @@ static struct platform_driver bcm2835_clk_driver = { +@@ -2346,7 +2434,15 @@ static struct platform_driver bcm2835_clk_driver = { .probe = bcm2835_clk_probe, }; @@ -48232,31 +65724,72 @@ +{ + return platform_driver_register(&bcm2835_clk_driver); +} ++#ifdef CONFIG_IMA ++subsys_initcall(__bcm2835_clk_driver_init); ++#else +postcore_initcall(__bcm2835_clk_driver_init); ++#endif MODULE_AUTHOR("Eric Anholt <eric@anholt.net>"); MODULE_DESCRIPTION("BCM2835 clock driver"); diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c -index f89b9cfc4309..c307e054f805 100644 +index 829406dc44a2..9b331f249a98 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c -@@ -33,6 +33,7 @@ enum rpi_firmware_clk_id { - RPI_FIRMWARE_EMMC2_CLK_ID, - RPI_FIRMWARE_M2MC_CLK_ID, - RPI_FIRMWARE_PIXEL_BVB_CLK_ID, -+ RPI_FIRMWARE_VEC_CLK_ID, - RPI_FIRMWARE_NUM_CLK_ID, - }; - -@@ -51,6 +52,7 @@ static char *rpi_firmware_clk_names = { - RPI_FIRMWARE_EMMC2_CLK_ID = "emmc2", +@@ -34,6 +34,7 @@ static char *rpi_firmware_clk_names = { RPI_FIRMWARE_M2MC_CLK_ID = "m2mc", RPI_FIRMWARE_PIXEL_BVB_CLK_ID = "pixel-bvb", -+ RPI_FIRMWARE_VEC_CLK_ID = "vec", + RPI_FIRMWARE_VEC_CLK_ID = "vec", ++ RPI_FIRMWARE_DISP_CLK_ID = "disp", }; #define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0) -@@ -97,7 +99,7 @@ static int raspberrypi_clock_property(struct rpi_firmware *firmware, +@@ -56,6 +57,12 @@ struct raspberrypi_clk_data { + struct raspberrypi_clk *rpi; + }; + ++static inline ++const struct raspberrypi_clk_data *clk_hw_to_data(const struct clk_hw *hw) ++{ ++ return container_of(hw, struct raspberrypi_clk_data, hw); ++} ++ + struct raspberrypi_clk_variant { + bool export; + char *clkdev; +@@ -111,18 +118,31 @@ raspberrypi_clk_variantsRPI_FIRMWARE_NUM_CLK_ID = { + }, + RPI_FIRMWARE_V3D_CLK_ID = { + .export = true, ++ .minimize = true, + }, + RPI_FIRMWARE_PIXEL_CLK_ID = { + .export = true, ++ .minimize = true, + }, + RPI_FIRMWARE_HEVC_CLK_ID = { + .export = true, ++ .minimize = true, ++ }, ++ RPI_FIRMWARE_ISP_CLK_ID = { ++ .export = true, ++ .minimize = true, + }, + RPI_FIRMWARE_PIXEL_BVB_CLK_ID = { + .export = true, ++ .minimize = true, + }, + RPI_FIRMWARE_VEC_CLK_ID = { + .export = true, ++ .minimize = true, ++ }, ++ RPI_FIRMWARE_DISP_CLK_ID = { ++ .export = true, ++ .minimize = true, + }, + }; + +@@ -153,7 +173,7 @@ static int raspberrypi_clock_property(struct rpi_firmware *firmware, struct raspberrypi_firmware_prop msg = { .id = cpu_to_le32(data->id), .val = cpu_to_le32(*val), @@ -48265,190 +65798,52 @@ }; int ret; -@@ -271,7 +273,10 @@ static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi, - 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: -+ case RPI_FIRMWARE_VEC_CLK_ID: -+ case RPI_FIRMWARE_PIXEL_CLK_ID: - hw = raspberrypi_clk_register(rpi, clks->parent, - clks->id); - if (IS_ERR(hw)) -diff --git a/drivers/clk/clk-allo-dac.c b/drivers/clk/clk-allo-dac.c -new file mode 100644 -index 000000000000..a9844cb9454b ---- /dev/null -+++ b/drivers/clk/clk-allo-dac.c -@@ -0,0 +1,161 @@ -+/* -+ * 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"); +@@ -168,8 +188,7 @@ static int raspberrypi_clock_property(struct rpi_firmware *firmware, + + static int raspberrypi_fw_is_prepared(struct clk_hw *hw) + { +- struct raspberrypi_clk_data *data = +- container_of(hw, struct raspberrypi_clk_data, hw); ++ const struct raspberrypi_clk_data *data = clk_hw_to_data(hw); + struct raspberrypi_clk *rpi = data->rpi; + u32 val = 0; + int ret; +@@ -186,8 +205,7 @@ static int raspberrypi_fw_is_prepared(struct clk_hw *hw) + static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw, + unsigned long parent_rate) + { +- struct raspberrypi_clk_data *data = +- container_of(hw, struct raspberrypi_clk_data, hw); ++ const struct raspberrypi_clk_data *data = clk_hw_to_data(hw); + struct raspberrypi_clk *rpi = data->rpi; + u32 val = 0; + int ret; +@@ -203,8 +221,7 @@ static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw, + static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) + { +- struct raspberrypi_clk_data *data = +- container_of(hw, struct raspberrypi_clk_data, hw); ++ const struct raspberrypi_clk_data *data = clk_hw_to_data(hw); + struct raspberrypi_clk *rpi = data->rpi; + u32 _rate = rate; + int ret; +@@ -221,8 +238,7 @@ static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate, + static int raspberrypi_fw_dumb_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) + { +- struct raspberrypi_clk_data *data = +- container_of(hw, struct raspberrypi_clk_data, hw); ++ const struct raspberrypi_clk_data *data = clk_hw_to_data(hw); + struct raspberrypi_clk_variant *variant = data->variant; + + /* diff --git a/drivers/clk/clk-hifiberry-dachd.c b/drivers/clk/clk-hifiberry-dachd.c new file mode 100644 -index 000000000000..ec528a0aef36 +index 000000000000..5280b5100559 --- /dev/null +++ b/drivers/clk/clk-hifiberry-dachd.c -@@ -0,0 +1,333 @@ +@@ -0,0 +1,331 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Clock Driver for HiFiBerry DAC+ HD @@ -48680,8 +66075,7 @@ +EXPORT_SYMBOL_GPL(hifiberry_pll_regmap); + + -+static int clk_hifiberry_dachd_i2c_probe(struct i2c_client *i2c, -+ const struct i2c_device_id *id) ++static int clk_hifiberry_dachd_i2c_probe(struct i2c_client *i2c) +{ + struct clk_hifiberry_drvdata *hdclk; + int ret = 0; @@ -48747,10 +66141,9 @@ + return ret; +} + -+static int clk_hifiberry_dachd_i2c_remove(struct i2c_client *i2c) ++static void 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 = { @@ -48784,10 +66177,10 @@ +MODULE_ALIAS("platform:clk-hifiberry-dachd"); diff --git a/drivers/clk/clk-hifiberry-dacpro.c b/drivers/clk/clk-hifiberry-dacpro.c new file mode 100644 -index 000000000000..9e2634465823 +index 000000000000..25603e75894c --- /dev/null +++ b/drivers/clk/clk-hifiberry-dacpro.c -@@ -0,0 +1,160 @@ +@@ -0,0 +1,181 @@ +/* + * Clock Driver for HiFiBerry DAC Pro + * @@ -48812,10 +66205,12 @@ +#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 ext_clk_rates { ++ /* Clock rate of CLK44EN attached to GPIO6 pin */ ++ unsigned long clk_44en; ++ /* Clock rate of CLK48EN attached to GPIO3 pin */ ++ unsigned long clk_48en; ++}; + +/** + * struct hifiberry_dacpro_clk - Common struct to the HiFiBerry DAC Pro @@ -48825,12 +66220,24 @@ +struct clk_hifiberry_hw { + struct clk_hw hw; + uint8_t mode; ++ struct ext_clk_rates clk_rates; +}; + +#define to_hifiberry_clk(_hw) container_of(_hw, struct clk_hifiberry_hw, hw) + ++static const struct ext_clk_rates hifiberry_dacpro_clks = { ++ .clk_44en = 22579200UL, ++ .clk_48en = 24576000UL, ++}; ++ ++static const struct ext_clk_rates allo_dac_clks = { ++ .clk_44en = 45158400UL, ++ .clk_48en = 49152000UL, ++}; ++ +static const struct of_device_id clk_hifiberry_dacpro_dt_ids = { -+ { .compatible = "hifiberry,dacpro-clk",}, ++ { .compatible = "hifiberry,dacpro-clk", &hifiberry_dacpro_clks }, ++ { .compatible = "allo,dac-clk", &allo_dac_clks }, + { } +}; +MODULE_DEVICE_TABLE(of, clk_hifiberry_dacpro_dt_ids); @@ -48838,27 +66245,29 @@ +static unsigned long clk_hifiberry_dacpro_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ -+ return (to_hifiberry_clk(hw)->mode == 0) ? CLK_44EN_RATE : -+ CLK_48EN_RATE; ++ struct clk_hifiberry_hw *clk = to_hifiberry_clk(hw); ++ return (clk->mode == 0) ? clk->clk_rates.clk_44en : ++ clk->clk_rates.clk_48en; +} + +static long clk_hifiberry_dacpro_round_rate(struct clk_hw *hw, + unsigned long rate, unsigned long *parent_rate) +{ ++ struct clk_hifiberry_hw *clk = to_hifiberry_clk(hw); + long actual_rate; + -+ if (rate <= CLK_44EN_RATE) { -+ actual_rate = (long)CLK_44EN_RATE; -+ } else if (rate >= CLK_48EN_RATE) { -+ actual_rate = (long)CLK_48EN_RATE; ++ if (rate <= clk->clk_rates.clk_44en) { ++ actual_rate = (long)clk->clk_rates.clk_44en; ++ } else if (rate >= clk->clk_rates.clk_48en) { ++ actual_rate = (long)clk->clk_rates.clk_48en; + } else { -+ long diff44Rate = (long)(rate - CLK_44EN_RATE); -+ long diff48Rate = (long)(CLK_48EN_RATE - rate); ++ long diff44Rate = (long)(rate - clk->clk_rates.clk_44en); ++ long diff48Rate = (long)(clk->clk_rates.clk_48en - rate); + + if (diff44Rate < diff48Rate) -+ actual_rate = (long)CLK_44EN_RATE; ++ actual_rate = (long)clk->clk_rates.clk_44en; + else -+ actual_rate = (long)CLK_48EN_RATE; ++ actual_rate = (long)clk->clk_rates.clk_48en; + } + return actual_rate; +} @@ -48867,12 +66276,12 @@ +static int clk_hifiberry_dacpro_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ -+ unsigned long actual_rate; + struct clk_hifiberry_hw *clk = to_hifiberry_clk(hw); ++ unsigned long actual_rate; + + actual_rate = (unsigned long)clk_hifiberry_dacpro_round_rate(hw, rate, + &parent_rate); -+ clk->mode = (actual_rate == CLK_44EN_RATE) ? 0 : 1; ++ clk->mode = (actual_rate == clk->clk_rates.clk_44en) ? 0 : 1; + return 0; +} + @@ -48885,13 +66294,17 @@ + +static int clk_hifiberry_dacpro_probe(struct platform_device *pdev) +{ -+ int ret; ++ const struct of_device_id *of_id; + struct clk_hifiberry_hw *proclk; + struct clk *clk; + struct device *dev; + struct clk_init_data init; ++ int ret; + + dev = &pdev->dev; ++ of_id = of_match_node(clk_hifiberry_dacpro_dt_ids, dev->of_node); ++ if (!of_id) ++ return -EINVAL; + + proclk = kzalloc(sizeof(struct clk_hifiberry_hw), GFP_KERNEL); + if (!proclk) @@ -48905,6 +66318,7 @@ + + proclk->mode = 0; + proclk->hw.init = &init; ++ memcpy(&proclk->clk_rates, of_id->data, sizeof(proclk->clk_rates)); + + clk = devm_clk_register(dev, &proclk->hw); + if (!IS_ERR(clk)) { @@ -48948,287 +66362,3089 @@ +MODULE_DESCRIPTION("HiFiBerry DAC Pro clock driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:clk-hifiberry-dacpro"); -diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c -index b8a0e3d23698..8c10c84098fb 100644 ---- a/drivers/clk/clk.c -+++ b/drivers/clk/clk.c -@@ -77,12 +77,14 @@ struct clk_core { - 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; -@@ -105,6 +107,12 @@ struct clk { - struct hlist_node clks_node; - }; - -+struct clk_request { -+ struct list_head list; -+ struct clk *clk; -+ unsigned long rate; -+}; +diff --git a/drivers/clk/clk-rp1-sdio.c b/drivers/clk/clk-rp1-sdio.c +new file mode 100644 +index 000000000000..7412e24d34cf +--- /dev/null ++++ b/drivers/clk/clk-rp1-sdio.c +@@ -0,0 +1,600 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * SDIO clock driver for RP1 ++ * ++ * Copyright (C) 2023 Raspberry Pi Ltd. ++ */ + - /*** runtime pm ***/ - static int clk_pm_runtime_get(struct clk_core *core) - { -@@ -1308,6 +1316,8 @@ static int clk_core_determine_round_nolock(struct clk_core *core, - if (!core) - return 0; - -+ req->rate = clamp(req->rate, req->min_rate, req->max_rate); ++#include <linux/io.h> ++#include <linux/clk.h> ++#include <linux/clk-provider.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> + - /* - * At this point, core protection will be disabled if - * - if the provider is not protected at all -@@ -1413,10 +1423,14 @@ unsigned long clk_hw_round_rate(struct clk_hw *hw, unsigned long rate) - { - 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); ++// Register : MODE ++#define MODE 0x00000000 ++#define MODE_BITS 0x70030000 ++#define MODE_RESET 0x00000000 ++// Field : MODE_STEPS_PER_CYCLE ++#define MODE_STEPS_PER_CYCLE_RESET 0x0 ++#define MODE_STEPS_PER_CYCLE_BITS 0x70000000 ++#define MODE_STEPS_PER_CYCLE_MSB 30 ++#define MODE_STEPS_PER_CYCLE_LSB 28 ++#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_20 0x0 ++#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_10 0x1 ++#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_16 0x2 ++#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_8 0x3 ++#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_12 0x4 ++#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_6 0x5 ++#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_5 0x6 ++#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_4 0x7 ++// Field : MODE_SRC_SEL ++#define MODE_SRC_SEL_RESET 0x0 ++#define MODE_SRC_SEL_BITS 0x00030000 ++#define MODE_SRC_SEL_MSB 17 ++#define MODE_SRC_SEL_LSB 16 ++#define MODE_SRC_SEL_VALUE_STOP 0x0 ++#define MODE_SRC_SEL_VALUE_CLK_ALT_SRC 0x1 ++#define MODE_SRC_SEL_VALUE_PLL_SYS_VCO 0x2 ++#define MODE_SRC_SEL_VALUE_PLL_SYS_VCO_AGAIN 0x3 ++// Register : FROMIP ++#define FROMIP 0x00000004 ++#define FROMIP_BITS 0x0f9713ff ++#define FROMIP_RESET 0x00000000 ++// Field : FROMIP_TUNING_CCLK_SEL ++#define FROMIP_TUNING_CCLK_SEL_RESET 0x0 ++#define FROMIP_TUNING_CCLK_SEL_BITS 0x0f000000 ++#define FROMIP_TUNING_CCLK_SEL_MSB 27 ++#define FROMIP_TUNING_CCLK_SEL_LSB 24 ++// Field : FROMIP_TUNING_CCLK_UPDATE ++#define FROMIP_TUNING_CCLK_UPDATE_RESET 0x0 ++#define FROMIP_TUNING_CCLK_UPDATE_BITS 0x00800000 ++#define FROMIP_TUNING_CCLK_UPDATE_MSB 23 ++#define FROMIP_TUNING_CCLK_UPDATE_LSB 23 ++// Field : FROMIP_SAMPLE_CCLK_SEL ++#define FROMIP_SAMPLE_CCLK_SEL_RESET 0x0 ++#define FROMIP_SAMPLE_CCLK_SEL_BITS 0x00100000 ++#define FROMIP_SAMPLE_CCLK_SEL_MSB 20 ++#define FROMIP_SAMPLE_CCLK_SEL_LSB 20 ++// Field : FROMIP_CLK2CARD_ON ++#define FROMIP_CLK2CARD_ON_RESET 0x0 ++#define FROMIP_CLK2CARD_ON_BITS 0x00040000 ++#define FROMIP_CLK2CARD_ON_MSB 18 ++#define FROMIP_CLK2CARD_ON_LSB 18 ++// Field : FROMIP_CARD_CLK_STABLE ++#define FROMIP_CARD_CLK_STABLE_RESET 0x0 ++#define FROMIP_CARD_CLK_STABLE_BITS 0x00020000 ++#define FROMIP_CARD_CLK_STABLE_MSB 17 ++#define FROMIP_CARD_CLK_STABLE_LSB 17 ++// Field : FROMIP_CARD_CLK_EN ++#define FROMIP_CARD_CLK_EN_RESET 0x0 ++#define FROMIP_CARD_CLK_EN_BITS 0x00010000 ++#define FROMIP_CARD_CLK_EN_MSB 16 ++#define FROMIP_CARD_CLK_EN_LSB 16 ++// Field : FROMIP_CLK_GEN_SEL ++#define FROMIP_CLK_GEN_SEL_RESET 0x0 ++#define FROMIP_CLK_GEN_SEL_BITS 0x00001000 ++#define FROMIP_CLK_GEN_SEL_MSB 12 ++#define FROMIP_CLK_GEN_SEL_LSB 12 ++// Field : FROMIP_FREQ_SEL ++#define FROMIP_FREQ_SEL_RESET 0x000 ++#define FROMIP_FREQ_SEL_BITS 0x000003ff ++#define FROMIP_FREQ_SEL_MSB 9 ++#define FROMIP_FREQ_SEL_LSB 0 ++// Register : LOCAL ++#define LOCAL 0x00000008 ++#define LOCAL_BITS 0x1f9713ff ++#define LOCAL_RESET 0x00000000 ++// Field : LOCAL_TUNING_CCLK_SEL ++#define LOCAL_TUNING_CCLK_SEL_RESET 0x00 ++#define LOCAL_TUNING_CCLK_SEL_BITS 0x1f000000 ++#define LOCAL_TUNING_CCLK_SEL_MSB 28 ++#define LOCAL_TUNING_CCLK_SEL_LSB 24 ++// Field : LOCAL_TUNING_CCLK_UPDATE ++#define LOCAL_TUNING_CCLK_UPDATE_RESET 0x0 ++#define LOCAL_TUNING_CCLK_UPDATE_BITS 0x00800000 ++#define LOCAL_TUNING_CCLK_UPDATE_MSB 23 ++#define LOCAL_TUNING_CCLK_UPDATE_LSB 23 ++// Field : LOCAL_SAMPLE_CCLK_SEL ++#define LOCAL_SAMPLE_CCLK_SEL_RESET 0x0 ++#define LOCAL_SAMPLE_CCLK_SEL_BITS 0x00100000 ++#define LOCAL_SAMPLE_CCLK_SEL_MSB 20 ++#define LOCAL_SAMPLE_CCLK_SEL_LSB 20 ++// Field : LOCAL_CLK2CARD_ON ++#define LOCAL_CLK2CARD_ON_RESET 0x0 ++#define LOCAL_CLK2CARD_ON_BITS 0x00040000 ++#define LOCAL_CLK2CARD_ON_MSB 18 ++#define LOCAL_CLK2CARD_ON_LSB 18 ++// Field : LOCAL_CARD_CLK_STABLE ++#define LOCAL_CARD_CLK_STABLE_RESET 0x0 ++#define LOCAL_CARD_CLK_STABLE_BITS 0x00020000 ++#define LOCAL_CARD_CLK_STABLE_MSB 17 ++#define LOCAL_CARD_CLK_STABLE_LSB 17 ++// Field : LOCAL_CARD_CLK_EN ++#define LOCAL_CARD_CLK_EN_RESET 0x0 ++#define LOCAL_CARD_CLK_EN_BITS 0x00010000 ++#define LOCAL_CARD_CLK_EN_MSB 16 ++#define LOCAL_CARD_CLK_EN_LSB 16 ++// Field : LOCAL_CLK_GEN_SEL ++#define LOCAL_CLK_GEN_SEL_RESET 0x0 ++#define LOCAL_CLK_GEN_SEL_BITS 0x00001000 ++#define LOCAL_CLK_GEN_SEL_MSB 12 ++#define LOCAL_CLK_GEN_SEL_LSB 12 ++#define LOCAL_CLK_GEN_SEL_VALUE_PROGCLOCKMODE 0x0 ++#define LOCAL_CLK_GEN_SEL_VALUE_DIVCLOCKMODE 0x1 ++// Field : LOCAL_FREQ_SEL ++#define LOCAL_FREQ_SEL_RESET 0x000 ++#define LOCAL_FREQ_SEL_BITS 0x000003ff ++#define LOCAL_FREQ_SEL_MSB 9 ++#define LOCAL_FREQ_SEL_LSB 0 ++// Register : USE_LOCAL ++#define USE_LOCAL 0x0000000c ++#define USE_LOCAL_BITS 0x01951001 ++#define USE_LOCAL_RESET 0x00000000 ++// Field : USE_LOCAL_TUNING_CCLK_SEL ++#define USE_LOCAL_TUNING_CCLK_SEL_RESET 0x0 ++#define USE_LOCAL_TUNING_CCLK_SEL_BITS 0x01000000 ++#define USE_LOCAL_TUNING_CCLK_SEL_MSB 24 ++#define USE_LOCAL_TUNING_CCLK_SEL_LSB 24 ++// Field : USE_LOCAL_TUNING_CCLK_UPDATE ++#define USE_LOCAL_TUNING_CCLK_UPDATE_RESET 0x0 ++#define USE_LOCAL_TUNING_CCLK_UPDATE_BITS 0x00800000 ++#define USE_LOCAL_TUNING_CCLK_UPDATE_MSB 23 ++#define USE_LOCAL_TUNING_CCLK_UPDATE_LSB 23 ++// Field : USE_LOCAL_SAMPLE_CCLK_SEL ++#define USE_LOCAL_SAMPLE_CCLK_SEL_RESET 0x0 ++#define USE_LOCAL_SAMPLE_CCLK_SEL_BITS 0x00100000 ++#define USE_LOCAL_SAMPLE_CCLK_SEL_MSB 20 ++#define USE_LOCAL_SAMPLE_CCLK_SEL_LSB 20 ++// Field : USE_LOCAL_CLK2CARD_ON ++#define USE_LOCAL_CLK2CARD_ON_RESET 0x0 ++#define USE_LOCAL_CLK2CARD_ON_BITS 0x00040000 ++#define USE_LOCAL_CLK2CARD_ON_MSB 18 ++#define USE_LOCAL_CLK2CARD_ON_LSB 18 ++// Field : USE_LOCAL_CARD_CLK_EN ++#define USE_LOCAL_CARD_CLK_EN_RESET 0x0 ++#define USE_LOCAL_CARD_CLK_EN_BITS 0x00010000 ++#define USE_LOCAL_CARD_CLK_EN_MSB 16 ++#define USE_LOCAL_CARD_CLK_EN_LSB 16 ++// Field : USE_LOCAL_CLK_GEN_SEL ++#define USE_LOCAL_CLK_GEN_SEL_RESET 0x0 ++#define USE_LOCAL_CLK_GEN_SEL_BITS 0x00001000 ++#define USE_LOCAL_CLK_GEN_SEL_MSB 12 ++#define USE_LOCAL_CLK_GEN_SEL_LSB 12 ++// Field : USE_LOCAL_FREQ_SEL ++#define USE_LOCAL_FREQ_SEL_RESET 0x0 ++#define USE_LOCAL_FREQ_SEL_BITS 0x00000001 ++#define USE_LOCAL_FREQ_SEL_MSB 0 ++#define USE_LOCAL_FREQ_SEL_LSB 0 ++// Register : SD_DELAY ++#define SD_DELAY 0x00000010 ++#define SD_DELAY_BITS 0x0000001f ++#define SD_DELAY_RESET 0x00000000 ++// Field : SD_DELAY_STEPS ++#define SD_DELAY_STEPS_RESET 0x00 ++#define SD_DELAY_STEPS_BITS 0x0000001f ++#define SD_DELAY_STEPS_MSB 4 ++#define SD_DELAY_STEPS_LSB 0 ++// Register : RX_DELAY ++#define RX_DELAY 0x00000014 ++#define RX_DELAY_BITS 0x19f3331f ++#define RX_DELAY_RESET 0x00000000 ++// Field : RX_DELAY_BYPASS ++#define RX_DELAY_BYPASS_RESET 0x0 ++#define RX_DELAY_BYPASS_BITS 0x10000000 ++#define RX_DELAY_BYPASS_MSB 28 ++#define RX_DELAY_BYPASS_LSB 28 ++// Field : RX_DELAY_FAIL_ACTUAL ++#define RX_DELAY_FAIL_ACTUAL_RESET 0x0 ++#define RX_DELAY_FAIL_ACTUAL_BITS 0x08000000 ++#define RX_DELAY_FAIL_ACTUAL_MSB 27 ++#define RX_DELAY_FAIL_ACTUAL_LSB 27 ++// Field : RX_DELAY_ACTUAL ++#define RX_DELAY_ACTUAL_RESET 0x00 ++#define RX_DELAY_ACTUAL_BITS 0x01f00000 ++#define RX_DELAY_ACTUAL_MSB 24 ++#define RX_DELAY_ACTUAL_LSB 20 ++// Field : RX_DELAY_OFFSET ++#define RX_DELAY_OFFSET_RESET 0x0 ++#define RX_DELAY_OFFSET_BITS 0x00030000 ++#define RX_DELAY_OFFSET_MSB 17 ++#define RX_DELAY_OFFSET_LSB 16 ++// Field : RX_DELAY_OVERFLOW ++#define RX_DELAY_OVERFLOW_RESET 0x0 ++#define RX_DELAY_OVERFLOW_BITS 0x00003000 ++#define RX_DELAY_OVERFLOW_MSB 13 ++#define RX_DELAY_OVERFLOW_LSB 12 ++#define RX_DELAY_OVERFLOW_VALUE_ALLOW 0x0 ++#define RX_DELAY_OVERFLOW_VALUE_CLAMP 0x1 ++#define RX_DELAY_OVERFLOW_VALUE_FAIL 0x2 ++// Field : RX_DELAY_MAP ++#define RX_DELAY_MAP_RESET 0x0 ++#define RX_DELAY_MAP_BITS 0x00000300 ++#define RX_DELAY_MAP_MSB 9 ++#define RX_DELAY_MAP_LSB 8 ++#define RX_DELAY_MAP_VALUE_DIRECT 0x0 ++#define RX_DELAY_MAP_VALUE 0x1 ++#define RX_DELAY_MAP_VALUE_STRETCH 0x2 ++// Field : RX_DELAY_FIXED ++#define RX_DELAY_FIXED_RESET 0x00 ++#define RX_DELAY_FIXED_BITS 0x0000001f ++#define RX_DELAY_FIXED_MSB 4 ++#define RX_DELAY_FIXED_LSB 0 ++// Register : NDIV ++#define NDIV 0x00000018 ++#define NDIV_BITS 0x1fff0000 ++#define NDIV_RESET 0x00110000 ++// Field : NDIV_DIVB ++#define NDIV_DIVB_RESET 0x001 ++#define NDIV_DIVB_BITS 0x1ff00000 ++#define NDIV_DIVB_MSB 28 ++#define NDIV_DIVB_LSB 20 ++// Field : NDIV_DIVA ++#define NDIV_DIVA_RESET 0x1 ++#define NDIV_DIVA_BITS 0x000f0000 ++#define NDIV_DIVA_MSB 19 ++#define NDIV_DIVA_LSB 16 ++// Register : CS ++#define CS 0x0000001c ++#define CS_BITS 0x00111101 ++#define CS_RESET 0x00000001 ++// Field : CS_RX_DEL_UPDATED ++#define CS_RX_DEL_UPDATED_RESET 0x0 ++#define CS_RX_DEL_UPDATED_BITS 0x00100000 ++#define CS_RX_DEL_UPDATED_MSB 20 ++#define CS_RX_DEL_UPDATED_LSB 20 ++// Field : CS_RX_CLK_RUNNING ++#define CS_RX_CLK_RUNNING_RESET 0x0 ++#define CS_RX_CLK_RUNNING_BITS 0x00010000 ++#define CS_RX_CLK_RUNNING_MSB 16 ++#define CS_RX_CLK_RUNNING_LSB 16 ++// Field : CS_SD_CLK_RUNNING ++#define CS_SD_CLK_RUNNING_RESET 0x0 ++#define CS_SD_CLK_RUNNING_BITS 0x00001000 ++#define CS_SD_CLK_RUNNING_MSB 12 ++#define CS_SD_CLK_RUNNING_LSB 12 ++// Field : CS_TX_CLK_RUNNING ++#define CS_TX_CLK_RUNNING_RESET 0x0 ++#define CS_TX_CLK_RUNNING_BITS 0x00000100 ++#define CS_TX_CLK_RUNNING_MSB 8 ++#define CS_TX_CLK_RUNNING_LSB 8 ++// Field : CS_RESET ++#define CS_RESET_RESET 0x1 ++#define CS_RESET_BITS 0x00000001 ++#define CS_RESET_MSB 0 ++#define CS_RESET_LSB 0 ++ ++#define FPGA_SRC_RATE 400000000 ++ ++/* Base number of steps to delay in relation to tx clk. ++ * The relationship of the 3 clocks are as follows: ++ * tx_clk: This clock is provided to the controller. Data is sent out ++ * to the pads using this clock. ++ * sd_clk: This clock is sent out to the card. ++ * rx_clk: This clock is used to sample the data coming back from the card. ++ * This may need to be several steps ahead of the tx_clk. The default rx delay ++ * is used as a base delay, and can be further adjusted by the sd host ++ * controller during the tuning process if using a DDR50 or faster SD card ++ */ ++/* ++ * PRJY-1813 - the default SD clock delay needs to be set to ~60% of the total ++ * number of steps to meet tISU (>6ns) and tIH (>2ns) in high-speed mode. ++ * On FPGA this means delay SDCLK by 5, and sample RX with a delay of 6. ++ */ ++#define DEFAULT_RX_DELAY 6 ++#define DEFAULT_SD_DELAY 5 + - ret = clk_core_round_rate_nolock(hw->core, &req); - if (ret) - return 0; -@@ -1437,6 +1451,7 @@ EXPORT_SYMBOL_GPL(clk_hw_round_rate); - long clk_round_rate(struct clk *clk, unsigned long rate) - { - struct clk_rate_request req; -+ struct clk_request *clk_req; - int ret; - - if (!clk) -@@ -1450,6 +1465,9 @@ long clk_round_rate(struct clk *clk, unsigned long rate) - 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); ++struct rp1_sdio_clkgen { ++ struct device *dev; + - ret = clk_core_round_rate_nolock(clk->core, &req); - - if (clk->exclusive_count) -@@ -1917,6 +1935,7 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core, - unsigned long new_rate; - unsigned long min_rate; - unsigned long max_rate; -+ struct clk_request *req; - int p_index = 0; - long ret; - -@@ -1931,6 +1950,9 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core, - - 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); ++ /* Source clock. Either PLL VCO or fixed freq on FPGA */ ++ struct clk *src_clk; ++ /* Desired base frequency. Max freq card can go */ ++ struct clk *base_clk; + - /* find the closest rate and parent clk/rate */ - if (clk_core_can_round(core)) { - struct clk_rate_request req; -@@ -2135,6 +2157,7 @@ static unsigned long clk_core_req_round_rate_nolock(struct clk_core *core, - { - int ret, cnt; - struct clk_rate_request req; -+ struct clk_request *clk_req; - - lockdep_assert_held(&prepare_lock); - -@@ -2149,6 +2172,9 @@ static unsigned long clk_core_req_round_rate_nolock(struct clk_core *core, - 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); ++ struct clk_hw hw; ++ void __iomem *regs; + - ret = clk_core_round_rate_nolock(core, &req); - - /* restore the protection */ -@@ -2242,6 +2268,9 @@ int clk_set_rate(struct clk *clk, unsigned long rate) - - ret = clk_core_set_rate_nolock(clk->core, rate); - -+ if (!list_empty(&clk->core->pending_requests)) -+ clk->core->default_request_rate = rate; ++ /* Starting value of local register before changing freq */ ++ u32 local_base; ++}; + - if (clk->exclusive_count) - clk_core_rate_protect(clk->core); - -@@ -2401,6 +2430,103 @@ int clk_set_max_rate(struct clk *clk, unsigned long rate) - } - 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) ++static inline void clkgen_write(struct rp1_sdio_clkgen *clkgen, u32 reg, u32 val) +{ -+ struct clk_request *req; -+ int ret; ++ dev_dbg(clkgen->dev, "%s: write reg 0x%x: 0x%x\n", __func__, reg, val); ++ writel(val, clkgen->regs + reg); ++} + -+ if (!clk) -+ return ERR_PTR(-EINVAL); ++static inline u32 clkgen_read(struct rp1_sdio_clkgen *clkgen, u32 reg) ++{ ++ u32 val = readl(clkgen->regs + reg); + -+ req = kzalloc(sizeof(*req), GFP_KERNEL); -+ if (!req) -+ return ERR_PTR(-ENOMEM); ++ dev_dbg(clkgen->dev, "%s: read reg 0x%x: 0x%x\n", __func__, reg, val); ++ return val; ++} ++ ++static int get_steps(unsigned int steps) ++{ ++ int ret = -1; ++ ++ if (steps == 4) ++ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_4; ++ else if (steps == 5) ++ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_5; ++ else if (steps == 6) ++ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_6; ++ else if (steps == 8) ++ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_8; ++ else if (steps == 10) ++ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_10; ++ else if (steps == 12) ++ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_12; ++ else if (steps == 16) ++ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_16; ++ else if (steps == 20) ++ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_20; ++ return ret; ++} + -+ clk_prepare_lock(); ++static int rp1_sdio_clk_init(struct rp1_sdio_clkgen *clkgen) ++{ ++ unsigned long src_rate = clk_get_rate(clkgen->src_clk); ++ unsigned long base_rate = clk_get_rate(clkgen->base_clk); ++ unsigned int steps = src_rate / base_rate; ++ u32 reg = 0; ++ int steps_value = 0; + -+ req->clk = clk; -+ req->rate = rate; ++ dev_dbg(clkgen->dev, "init: src_rate %lu, base_rate %lu, steps %d\n", ++ src_rate, base_rate, steps); + -+ if (list_empty(&clk->core->pending_requests)) -+ clk->core->default_request_rate = clk_core_get_rate_recalc(clk->core); ++ /* Assert reset while we set up clkgen */ ++ clkgen_write(clkgen, CS, CS_RESET_BITS); + -+ ret = clk_core_set_rate_nolock(clk->core, rate); -+ if (ret) { -+ clk_prepare_unlock(); -+ kfree(req); -+ return ERR_PTR(ret); ++ /* Pick clock source */ ++ if (src_rate == FPGA_SRC_RATE) { ++ /* Using ALT SRC */ ++ reg |= MODE_SRC_SEL_VALUE_CLK_ALT_SRC << MODE_SRC_SEL_LSB; ++ } else { ++ /* Assume we are using PLL SYS VCO */ ++ reg |= MODE_SRC_SEL_VALUE_PLL_SYS_VCO << MODE_SRC_SEL_LSB; + } + -+ list_add_tail(&req->list, &clk->core->pending_requests); -+ clk_prepare_unlock(); ++ /* How many delay steps are available in one cycle for this source */ ++ steps_value = get_steps(steps); ++ if (steps_value < 0) { ++ dev_err(clkgen->dev, "Invalid step value: %d\n", steps); ++ return -EINVAL; ++ } ++ reg |= steps_value << MODE_STEPS_PER_CYCLE_LSB; + -+ return req; ++ /* Mode register is done now*/ ++ clkgen_write(clkgen, MODE, reg); ++ ++ /* Now set delay mode */ ++ /* Clamp value if out of range rx delay is used */ ++ reg = RX_DELAY_OVERFLOW_VALUE_CLAMP << RX_DELAY_OVERFLOW_LSB; ++ /* SD tuning bus goes from 0x0 to 0xf but we don't necessarily have that ++ * many steps available depending on the source so map 0x0 -> 0xf to one ++ * cycle of rx delay ++ */ ++ reg |= RX_DELAY_MAP_VALUE_STRETCH << RX_DELAY_MAP_LSB; ++ ++ /* Default RX delay */ ++ dev_dbg(clkgen->dev, "default rx delay %d\n", DEFAULT_RX_DELAY); ++ reg |= (DEFAULT_RX_DELAY & RX_DELAY_FIXED_BITS) << RX_DELAY_FIXED_LSB; ++ clkgen_write(clkgen, RX_DELAY, reg); ++ ++ /* Default SD delay */ ++ dev_dbg(clkgen->dev, "default sd delay %d\n", DEFAULT_SD_DELAY); ++ reg = (DEFAULT_SD_DELAY & SD_DELAY_STEPS_BITS) << SD_DELAY_STEPS_LSB; ++ clkgen_write(clkgen, SD_DELAY, reg); ++ ++ /* We select freq, we turn on tx clock, we turn on sd clk, ++ * we pick clock generator mode ++ */ ++ reg = USE_LOCAL_FREQ_SEL_BITS | USE_LOCAL_CARD_CLK_EN_BITS | ++ USE_LOCAL_CLK2CARD_ON_BITS | USE_LOCAL_CLK_GEN_SEL_BITS; ++ clkgen_write(clkgen, USE_LOCAL, reg); ++ ++ /* Deassert reset. Reset bit is only writable bit of CS ++ * reg so fine to write a 0. ++ */ ++ clkgen_write(clkgen, CS, 0); ++ ++ return 0; +} -+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) ++#define RUNNING \ ++ (CS_TX_CLK_RUNNING_BITS | CS_RX_CLK_RUNNING_BITS | \ ++ CS_SD_CLK_RUNNING_BITS) ++static int rp1_sdio_clk_is_prepared(struct clk_hw *hw) +{ -+ struct clk_core *core; ++ struct rp1_sdio_clkgen *clkgen = ++ container_of(hw, struct rp1_sdio_clkgen, hw); ++ u32 status; + -+ if (!req) -+ return; -+ core = req->clk->core; ++ dev_dbg(clkgen->dev, "is_prepared\n"); ++ status = clkgen_read(clkgen, CS); ++ return ((status & RUNNING) == RUNNING); ++} + -+ clk_prepare_lock(); ++/* Can define an additional divider if an sd card isn't working at full speed */ ++/* #define SLOWDOWN 3 */ + -+ list_del(&req->list); ++static unsigned long rp1_sdio_clk_get_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ /* Get the current rate */ ++ struct rp1_sdio_clkgen *clkgen = ++ container_of(hw, struct rp1_sdio_clkgen, hw); ++ unsigned long actual_rate = 0; ++ u32 ndiv_diva; ++ u32 ndiv_divb; ++ u32 tmp; ++ u32 div; + -+ 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; ++ tmp = clkgen_read(clkgen, LOCAL); ++ if ((tmp & LOCAL_CLK2CARD_ON_BITS) == 0) { ++ dev_dbg(clkgen->dev, "get_rate 0\n"); ++ return 0; ++ } + -+ list_for_each_entry(cur_req, &core->pending_requests, list) -+ new_rate = max(new_rate, cur_req->rate); ++ tmp = clkgen_read(clkgen, NDIV); ++ ndiv_diva = (tmp & NDIV_DIVA_BITS) >> NDIV_DIVA_LSB; ++ ndiv_divb = (tmp & NDIV_DIVB_BITS) >> NDIV_DIVB_LSB; ++ div = ndiv_diva * ndiv_divb; ++ actual_rate = (clk_get_rate(clkgen->base_clk) / div); + -+ clk_core_set_rate_nolock(core, new_rate); -+ } ++#ifdef SLOWDOWN ++ actual_rate *= SLOWDOWN; ++#endif + -+ clk_prepare_unlock(); ++ dev_dbg(clkgen->dev, "get_rate. ndiv_diva %d, ndiv_divb %d = %lu\n", ++ ndiv_diva, ndiv_divb, actual_rate); + -+ kfree(req); ++ return actual_rate; +} -+EXPORT_SYMBOL_GPL(clk_request_done); + - /** - * clk_get_parent - return the parent of a clk - * @clk: the clk whose parent gets returned -@@ -3838,6 +3964,7 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw) - 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 --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig -index 08013345d1f2..cdfb63c723f6 100644 ---- a/drivers/dma/Kconfig -+++ b/drivers/dma/Kconfig -@@ -652,6 +652,10 @@ config UNIPHIER_XDMAC - 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 ++static int rp1_sdio_clk_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct rp1_sdio_clkgen *clkgen = ++ container_of(hw, struct rp1_sdio_clkgen, hw); ++ u32 div; ++ u32 reg; + - config XGENE_DMA - tristate "APM X-Gene DMA support" - depends on ARCH_XGENE || COMPILE_TEST -diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile -index 948a8da05f8b..e543c69fa6b5 100644 ---- a/drivers/dma/Makefile -+++ b/drivers/dma/Makefile -@@ -21,6 +21,7 @@ obj-$(CONFIG_AT_XDMAC) += at_xdmac.o - 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 --git a/drivers/dma/bcm2708-dmaengine.c b/drivers/dma/bcm2708-dmaengine.c -new file mode 100644 -index 000000000000..075da9aadf6d ---- /dev/null -+++ b/drivers/dma/bcm2708-dmaengine.c -@@ -0,0 +1,281 @@ -+/* -+ * 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. -+ */ ++ dev_dbg(clkgen->dev, "set_rate %lu\n", rate); + -+#include <linux/init.h> -+#include <linux/interrupt.h> ++ if (rate == 0) { ++ /* Keep tx clock running */ ++ clkgen_write(clkgen, LOCAL, LOCAL_CARD_CLK_EN_BITS); ++ return 0; ++ } ++ ++#ifdef SLOWDOWN ++ rate /= SLOWDOWN; ++#endif ++ ++ div = (clk_get_rate(clkgen->base_clk) / rate) - 1; ++ reg = LOCAL_CLK_GEN_SEL_BITS | LOCAL_CARD_CLK_EN_BITS | ++ LOCAL_CLK2CARD_ON_BITS | (div << LOCAL_FREQ_SEL_LSB); ++ clkgen_write(clkgen, LOCAL, reg); ++ ++ return 0; ++} ++ ++#define MAX_NDIV (256 * 8) ++static int rp1_sdio_clk_determine_rate(struct clk_hw *hw, ++ struct clk_rate_request *req) ++{ ++ unsigned long rate; ++ struct rp1_sdio_clkgen *clkgen = ++ container_of(hw, struct rp1_sdio_clkgen, hw); ++ unsigned long base_rate = clk_get_rate(clkgen->base_clk); ++ u32 div; ++ ++ /* What is the actual rate I can get if I request xyz */ ++ if (req->rate) { ++ div = min((u32)(base_rate / req->rate), (u32)MAX_NDIV); ++ rate = base_rate / div; ++ req->rate = rate; ++ dev_dbg(clkgen->dev, "determine_rate %lu: %lu / %d = %lu\n", ++ req->rate, base_rate, div, rate); ++ } else { ++ rate = 0; ++ dev_dbg(clkgen->dev, "determine_rate %lu: %lu\n", req->rate, ++ rate); ++ } ++ ++ return 0; ++} ++ ++static const struct clk_ops rp1_sdio_clk_ops = { ++ .is_prepared = rp1_sdio_clk_is_prepared, ++ .recalc_rate = rp1_sdio_clk_get_rate, ++ .set_rate = rp1_sdio_clk_set_rate, ++ .determine_rate = rp1_sdio_clk_determine_rate, ++}; ++ ++static int rp1_sdio_clk_probe(struct platform_device *pdev) ++{ ++ struct device_node *node = pdev->dev.of_node; ++ struct rp1_sdio_clkgen *clkgen; ++ void __iomem *regs; ++ struct clk_init_data init = {}; ++ int ret; ++ ++ clkgen = devm_kzalloc(&pdev->dev, sizeof(*clkgen), GFP_KERNEL); ++ if (!clkgen) ++ return -ENOMEM; ++ platform_set_drvdata(pdev, clkgen); ++ ++ clkgen->dev = &pdev->dev; ++ ++ /* Source freq */ ++ clkgen->src_clk = devm_clk_get(&pdev->dev, "src"); ++ if (IS_ERR(clkgen->src_clk)) { ++ int err = PTR_ERR(clkgen->src_clk); ++ ++ dev_err(&pdev->dev, "failed to get src clk: %d\n", err); ++ return err; ++ } ++ ++ /* Desired maximum output freq (i.e. base freq) */ ++ clkgen->base_clk = devm_clk_get(&pdev->dev, "base"); ++ if (IS_ERR(clkgen->base_clk)) { ++ int err = PTR_ERR(clkgen->base_clk); ++ ++ dev_err(&pdev->dev, "failed to get base clk: %d\n", err); ++ return err; ++ } ++ ++ regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(regs)) ++ return PTR_ERR(regs); ++ ++ init.name = node->name; ++ init.ops = &rp1_sdio_clk_ops; ++ init.flags = CLK_GET_RATE_NOCACHE; ++ ++ clkgen->hw.init = &init; ++ clkgen->regs = regs; ++ ++ dev_info(&pdev->dev, "loaded %s\n", init.name); ++ ++ ret = devm_clk_hw_register(&pdev->dev, &clkgen->hw); ++ if (ret) ++ return ret; ++ ++ ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &clkgen->hw); ++ if (ret) ++ return ret; ++ ++ ret = rp1_sdio_clk_init(clkgen); ++ return ret; ++} ++ ++static int rp1_sdio_clk_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static const struct of_device_id rp1_sdio_clk_dt_ids = { ++ { .compatible = "raspberrypi,rp1-sdio-clk", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, rp1_sdio_clk_dt_ids); ++ ++static struct platform_driver rp1_sdio_clk_driver = { ++ .probe = rp1_sdio_clk_probe, ++ .remove = rp1_sdio_clk_remove, ++ .driver = { ++ .name = "rp1-sdio-clk", ++ .of_match_table = rp1_sdio_clk_dt_ids, ++ }, ++}; ++module_platform_driver(rp1_sdio_clk_driver); ++ ++MODULE_AUTHOR("Liam Fraser <liam@raspberrypi.com>"); ++MODULE_DESCRIPTION("RP1 SDIO clock driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/clk/clk-rp1.c b/drivers/clk/clk-rp1.c +new file mode 100644 +index 000000000000..b4964babf84a +--- /dev/null ++++ b/drivers/clk/clk-rp1.c +@@ -0,0 +1,2422 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2023 Raspberry Pi Ltd. ++ * ++ * Clock driver for RP1 PCIe multifunction chip. ++ */ ++ ++#include <linux/clk-provider.h> ++#include <linux/clkdev.h> ++#include <linux/clk.h> ++#include <linux/debugfs.h> ++#include <linux/delay.h> ++#include <linux/io.h> ++#include <linux/math64.h> ++#include <linux/module.h> ++#include <linux/of_device.h> ++#include <linux/platform_device.h> ++#include <linux/rp1_platform.h> ++#include <linux/slab.h> ++ ++#include <asm/div64.h> ++ ++#include <dt-bindings/clock/rp1.h> ++ ++#define PLL_SYS_CS 0x08000 ++#define PLL_SYS_PWR 0x08004 ++#define PLL_SYS_FBDIV_INT 0x08008 ++#define PLL_SYS_FBDIV_FRAC 0x0800c ++#define PLL_SYS_PRIM 0x08010 ++#define PLL_SYS_SEC 0x08014 ++ ++#define PLL_AUDIO_CS 0x0c000 ++#define PLL_AUDIO_PWR 0x0c004 ++#define PLL_AUDIO_FBDIV_INT 0x0c008 ++#define PLL_AUDIO_FBDIV_FRAC 0x0c00c ++#define PLL_AUDIO_PRIM 0x0c010 ++#define PLL_AUDIO_SEC 0x0c014 ++#define PLL_AUDIO_TERN 0x0c018 ++ ++#define PLL_VIDEO_CS 0x10000 ++#define PLL_VIDEO_PWR 0x10004 ++#define PLL_VIDEO_FBDIV_INT 0x10008 ++#define PLL_VIDEO_FBDIV_FRAC 0x1000c ++#define PLL_VIDEO_PRIM 0x10010 ++#define PLL_VIDEO_SEC 0x10014 ++ ++#define GPCLK_OE_CTRL 0x00000 ++ ++#define CLK_SYS_CTRL 0x00014 ++#define CLK_SYS_DIV_INT 0x00018 ++#define CLK_SYS_SEL 0x00020 ++ ++#define CLK_SLOW_SYS_CTRL 0x00024 ++#define CLK_SLOW_SYS_DIV_INT 0x00028 ++#define CLK_SLOW_SYS_SEL 0x00030 ++ ++#define CLK_DMA_CTRL 0x00044 ++#define CLK_DMA_DIV_INT 0x00048 ++#define CLK_DMA_SEL 0x00050 ++ ++#define CLK_UART_CTRL 0x00054 ++#define CLK_UART_DIV_INT 0x00058 ++#define CLK_UART_SEL 0x00060 ++ ++#define CLK_ETH_CTRL 0x00064 ++#define CLK_ETH_DIV_INT 0x00068 ++#define CLK_ETH_SEL 0x00070 ++ ++#define CLK_PWM0_CTRL 0x00074 ++#define CLK_PWM0_DIV_INT 0x00078 ++#define CLK_PWM0_DIV_FRAC 0x0007c ++#define CLK_PWM0_SEL 0x00080 ++ ++#define CLK_PWM1_CTRL 0x00084 ++#define CLK_PWM1_DIV_INT 0x00088 ++#define CLK_PWM1_DIV_FRAC 0x0008c ++#define CLK_PWM1_SEL 0x00090 ++ ++#define CLK_AUDIO_IN_CTRL 0x00094 ++#define CLK_AUDIO_IN_DIV_INT 0x00098 ++#define CLK_AUDIO_IN_SEL 0x000a0 ++ ++#define CLK_AUDIO_OUT_CTRL 0x000a4 ++#define CLK_AUDIO_OUT_DIV_INT 0x000a8 ++#define CLK_AUDIO_OUT_SEL 0x000b0 ++ ++#define CLK_I2S_CTRL 0x000b4 ++#define CLK_I2S_DIV_INT 0x000b8 ++#define CLK_I2S_SEL 0x000c0 ++ ++#define CLK_MIPI0_CFG_CTRL 0x000c4 ++#define CLK_MIPI0_CFG_DIV_INT 0x000c8 ++#define CLK_MIPI0_CFG_SEL 0x000d0 ++ ++#define CLK_MIPI1_CFG_CTRL 0x000d4 ++#define CLK_MIPI1_CFG_DIV_INT 0x000d8 ++#define CLK_MIPI1_CFG_SEL 0x000e0 ++ ++#define CLK_PCIE_AUX_CTRL 0x000e4 ++#define CLK_PCIE_AUX_DIV_INT 0x000e8 ++#define CLK_PCIE_AUX_SEL 0x000f0 ++ ++#define CLK_USBH0_MICROFRAME_CTRL 0x000f4 ++#define CLK_USBH0_MICROFRAME_DIV_INT 0x000f8 ++#define CLK_USBH0_MICROFRAME_SEL 0x00100 ++ ++#define CLK_USBH1_MICROFRAME_CTRL 0x00104 ++#define CLK_USBH1_MICROFRAME_DIV_INT 0x00108 ++#define CLK_USBH1_MICROFRAME_SEL 0x00110 ++ ++#define CLK_USBH0_SUSPEND_CTRL 0x00114 ++#define CLK_USBH0_SUSPEND_DIV_INT 0x00118 ++#define CLK_USBH0_SUSPEND_SEL 0x00120 ++ ++#define CLK_USBH1_SUSPEND_CTRL 0x00124 ++#define CLK_USBH1_SUSPEND_DIV_INT 0x00128 ++#define CLK_USBH1_SUSPEND_SEL 0x00130 ++ ++#define CLK_ETH_TSU_CTRL 0x00134 ++#define CLK_ETH_TSU_DIV_INT 0x00138 ++#define CLK_ETH_TSU_SEL 0x00140 ++ ++#define CLK_ADC_CTRL 0x00144 ++#define CLK_ADC_DIV_INT 0x00148 ++#define CLK_ADC_SEL 0x00150 ++ ++#define CLK_SDIO_TIMER_CTRL 0x00154 ++#define CLK_SDIO_TIMER_DIV_INT 0x00158 ++#define CLK_SDIO_TIMER_SEL 0x00160 ++ ++#define CLK_SDIO_ALT_SRC_CTRL 0x00164 ++#define CLK_SDIO_ALT_SRC_DIV_INT 0x00168 ++#define CLK_SDIO_ALT_SRC_SEL 0x00170 ++ ++#define CLK_GP0_CTRL 0x00174 ++#define CLK_GP0_DIV_INT 0x00178 ++#define CLK_GP0_DIV_FRAC 0x0017c ++#define CLK_GP0_SEL 0x00180 ++ ++#define CLK_GP1_CTRL 0x00184 ++#define CLK_GP1_DIV_INT 0x00188 ++#define CLK_GP1_DIV_FRAC 0x0018c ++#define CLK_GP1_SEL 0x00190 ++ ++#define CLK_GP2_CTRL 0x00194 ++#define CLK_GP2_DIV_INT 0x00198 ++#define CLK_GP2_DIV_FRAC 0x0019c ++#define CLK_GP2_SEL 0x001a0 ++ ++#define CLK_GP3_CTRL 0x001a4 ++#define CLK_GP3_DIV_INT 0x001a8 ++#define CLK_GP3_DIV_FRAC 0x001ac ++#define CLK_GP3_SEL 0x001b0 ++ ++#define CLK_GP4_CTRL 0x001b4 ++#define CLK_GP4_DIV_INT 0x001b8 ++#define CLK_GP4_DIV_FRAC 0x001bc ++#define CLK_GP4_SEL 0x001c0 ++ ++#define CLK_GP5_CTRL 0x001c4 ++#define CLK_GP5_DIV_INT 0x001c8 ++#define CLK_GP5_DIV_FRAC 0x001cc ++#define CLK_GP5_SEL 0x001d0 ++ ++#define CLK_SYS_RESUS_CTRL 0x0020c ++ ++#define CLK_SLOW_SYS_RESUS_CTRL 0x00214 ++ ++#define FC0_REF_KHZ 0x0021c ++#define FC0_MIN_KHZ 0x00220 ++#define FC0_MAX_KHZ 0x00224 ++#define FC0_DELAY 0x00228 ++#define FC0_INTERVAL 0x0022c ++#define FC0_SRC 0x00230 ++#define FC0_STATUS 0x00234 ++#define FC0_RESULT 0x00238 ++#define FC_SIZE 0x20 ++#define FC_COUNT 8 ++#define FC_NUM(idx, off) ((idx) * 32 + (off)) ++ ++#define AUX_SEL 1 ++ ++#define VIDEO_CLOCKS_OFFSET 0x4000 ++#define VIDEO_CLK_VEC_CTRL (VIDEO_CLOCKS_OFFSET + 0x0000) ++#define VIDEO_CLK_VEC_DIV_INT (VIDEO_CLOCKS_OFFSET + 0x0004) ++#define VIDEO_CLK_VEC_SEL (VIDEO_CLOCKS_OFFSET + 0x000c) ++#define VIDEO_CLK_DPI_CTRL (VIDEO_CLOCKS_OFFSET + 0x0010) ++#define VIDEO_CLK_DPI_DIV_INT (VIDEO_CLOCKS_OFFSET + 0x0014) ++#define VIDEO_CLK_DPI_SEL (VIDEO_CLOCKS_OFFSET + 0x001c) ++#define VIDEO_CLK_MIPI0_DPI_CTRL (VIDEO_CLOCKS_OFFSET + 0x0020) ++#define VIDEO_CLK_MIPI0_DPI_DIV_INT (VIDEO_CLOCKS_OFFSET + 0x0024) ++#define VIDEO_CLK_MIPI0_DPI_DIV_FRAC (VIDEO_CLOCKS_OFFSET + 0x0028) ++#define VIDEO_CLK_MIPI0_DPI_SEL (VIDEO_CLOCKS_OFFSET + 0x002c) ++#define VIDEO_CLK_MIPI1_DPI_CTRL (VIDEO_CLOCKS_OFFSET + 0x0030) ++#define VIDEO_CLK_MIPI1_DPI_DIV_INT (VIDEO_CLOCKS_OFFSET + 0x0034) ++#define VIDEO_CLK_MIPI1_DPI_DIV_FRAC (VIDEO_CLOCKS_OFFSET + 0x0038) ++#define VIDEO_CLK_MIPI1_DPI_SEL (VIDEO_CLOCKS_OFFSET + 0x003c) ++ ++#define DIV_INT_8BIT_MAX 0x000000ffu /* max divide for most clocks */ ++#define DIV_INT_16BIT_MAX 0x0000ffffu /* max divide for GPx, PWM */ ++#define DIV_INT_24BIT_MAX 0x00ffffffu /* max divide for CLK_SYS */ ++ ++#define FC0_STATUS_DONE BIT(4) ++#define FC0_STATUS_RUNNING BIT(8) ++#define FC0_RESULT_FRAC_SHIFT 5 ++ ++#define PLL_PRIM_DIV1_SHIFT 16 ++#define PLL_PRIM_DIV1_MASK 0x00070000 ++#define PLL_PRIM_DIV2_SHIFT 12 ++#define PLL_PRIM_DIV2_MASK 0x00007000 ++ ++#define PLL_SEC_DIV_SHIFT 8 ++#define PLL_SEC_DIV_WIDTH 5 ++#define PLL_SEC_DIV_MASK 0x00001f00 ++ ++#define PLL_CS_LOCK BIT(31) ++#define PLL_CS_REFDIV_SHIFT 0 ++ ++#define PLL_PWR_PD BIT(0) ++#define PLL_PWR_DACPD BIT(1) ++#define PLL_PWR_DSMPD BIT(2) ++#define PLL_PWR_POSTDIVPD BIT(3) ++#define PLL_PWR_4PHASEPD BIT(4) ++#define PLL_PWR_VCOPD BIT(5) ++#define PLL_PWR_MASK 0x0000003f ++ ++#define PLL_SEC_RST BIT(16) ++#define PLL_SEC_IMPL BIT(31) ++ ++/* PLL phase output for both PRI and SEC */ ++#define PLL_PH_EN BIT(4) ++#define PLL_PH_PHASE_SHIFT 0 ++ ++#define RP1_PLL_PHASE_0 0 ++#define RP1_PLL_PHASE_90 1 ++#define RP1_PLL_PHASE_180 2 ++#define RP1_PLL_PHASE_270 3 ++ ++/* Clock fields for all clocks */ ++#define CLK_CTRL_ENABLE BIT(11) ++#define CLK_CTRL_AUXSRC_MASK 0x000003e0 ++#define CLK_CTRL_AUXSRC_SHIFT 5 ++#define CLK_CTRL_SRC_SHIFT 0 ++#define CLK_DIV_FRAC_BITS 16 ++ ++#define KHz 1000 ++#define MHz (KHz * KHz) ++#define LOCK_TIMEOUT_NS 100000000 ++#define FC_TIMEOUT_NS 100000000 ++ ++#define MAX_CLK_PARENTS 16 ++ ++#define MEASURE_CLOCK_RATE ++const char * const fc0_ref_clk_name = "clk_slow_sys"; ++ ++#define ABS_DIFF(a, b) ((a) > (b) ? (a) - (b) : (b) - (a)) ++#define DIV_NEAREST(a, b) (((a) + ((b) >> 1)) / (b)) ++#define DIV_U64_NEAREST(a, b) div_u64(((a) + ((b) >> 1)), (b)) ++ ++/* ++ * Names of the reference clock for the pll cores. This name must match ++ * the DT reference clock-output-name. ++ */ ++static const char *const ref_clock = "xosc"; ++ ++/* ++ * Secondary PLL channel output divider table. ++ * Divider values range from 8 to 19. ++ * Invalid values default to 19 ++ */ ++static const struct clk_div_table pll_sec_div_table = { ++ { 0x00, 19 }, ++ { 0x01, 19 }, ++ { 0x02, 19 }, ++ { 0x03, 19 }, ++ { 0x04, 19 }, ++ { 0x05, 19 }, ++ { 0x06, 19 }, ++ { 0x07, 19 }, ++ { 0x08, 8 }, ++ { 0x09, 9 }, ++ { 0x0a, 10 }, ++ { 0x0b, 11 }, ++ { 0x0c, 12 }, ++ { 0x0d, 13 }, ++ { 0x0e, 14 }, ++ { 0x0f, 15 }, ++ { 0x10, 16 }, ++ { 0x11, 17 }, ++ { 0x12, 18 }, ++ { 0x13, 19 }, ++ { 0x14, 19 }, ++ { 0x15, 19 }, ++ { 0x16, 19 }, ++ { 0x17, 19 }, ++ { 0x18, 19 }, ++ { 0x19, 19 }, ++ { 0x1a, 19 }, ++ { 0x1b, 19 }, ++ { 0x1c, 19 }, ++ { 0x1d, 19 }, ++ { 0x1e, 19 }, ++ { 0x1f, 19 }, ++ { 0 } ++}; ++ ++struct rp1_clockman { ++ struct device *dev; ++ void __iomem *regs; ++ spinlock_t regs_lock; /* spinlock for all clocks */ ++ ++ /* Must be last */ ++ struct clk_hw_onecell_data onecell; ++}; ++ ++struct rp1_pll_core_data { ++ const char *name; ++ u32 cs_reg; ++ u32 pwr_reg; ++ u32 fbdiv_int_reg; ++ u32 fbdiv_frac_reg; ++ unsigned long flags; ++ u32 fc0_src; ++}; ++ ++struct rp1_pll_data { ++ const char *name; ++ const char *source_pll; ++ u32 ctrl_reg; ++ unsigned long flags; ++ u32 fc0_src; ++}; ++ ++struct rp1_pll_ph_data { ++ const char *name; ++ const char *source_pll; ++ unsigned int phase; ++ unsigned int fixed_divider; ++ u32 ph_reg; ++ unsigned long flags; ++ u32 fc0_src; ++}; ++ ++struct rp1_pll_divider_data { ++ const char *name; ++ const char *source_pll; ++ u32 sec_reg; ++ unsigned long flags; ++ u32 fc0_src; ++}; ++ ++struct rp1_clock_data { ++ const char *name; ++ const char *const parentsMAX_CLK_PARENTS; ++ int num_std_parents; ++ int num_aux_parents; ++ unsigned long flags; ++ u32 oe_mask; ++ u32 clk_src_mask; ++ u32 ctrl_reg; ++ u32 div_int_reg; ++ u32 div_frac_reg; ++ u32 sel_reg; ++ u32 div_int_max; ++ unsigned long max_freq; ++ u32 fc0_src; ++}; ++ ++struct rp1_pll_core { ++ struct clk_hw hw; ++ struct rp1_clockman *clockman; ++ const struct rp1_pll_core_data *data; ++ unsigned long cached_rate; ++}; ++ ++struct rp1_pll { ++ struct clk_hw hw; ++ struct clk_divider div; ++ struct rp1_clockman *clockman; ++ const struct rp1_pll_data *data; ++ unsigned long cached_rate; ++}; ++ ++struct rp1_pll_ph { ++ struct clk_hw hw; ++ struct rp1_clockman *clockman; ++ const struct rp1_pll_ph_data *data; ++}; ++ ++struct rp1_clock { ++ struct clk_hw hw; ++ struct rp1_clockman *clockman; ++ const struct rp1_clock_data *data; ++ unsigned long cached_rate; ++}; ++ ++ ++struct rp1_clk_change { ++ struct clk_hw *hw; ++ unsigned long new_rate; ++}; ++ ++struct rp1_clk_change rp1_clk_chg_tree3; ++ ++static struct clk_hw *clk_xosc; ++static struct clk_hw *clk_audio; ++static struct clk_hw *clk_i2s; ++ ++static void rp1_debugfs_regset(struct rp1_clockman *clockman, u32 base, ++ const struct debugfs_reg32 *regs, ++ size_t nregs, struct dentry *dentry) ++{ ++ struct debugfs_regset32 *regset; ++ ++ regset = devm_kzalloc(clockman->dev, sizeof(*regset), GFP_KERNEL); ++ if (!regset) ++ return; ++ ++ regset->regs = regs; ++ regset->nregs = nregs; ++ regset->base = clockman->regs + base; ++ ++ debugfs_create_regset32("regdump", 0444, dentry, regset); ++} ++ ++static inline u32 set_register_field(u32 reg, u32 val, u32 mask, u32 shift) ++{ ++ reg &= ~mask; ++ reg |= (val << shift) & mask; ++ return reg; ++} ++ ++static inline ++void clockman_write(struct rp1_clockman *clockman, u32 reg, u32 val) ++{ ++ writel(val, clockman->regs + reg); ++} ++ ++static inline u32 clockman_read(struct rp1_clockman *clockman, u32 reg) ++{ ++ return readl(clockman->regs + reg); ++} ++ ++#ifdef MEASURE_CLOCK_RATE ++static unsigned long clockman_measure_clock(struct rp1_clockman *clockman, ++ const char *clk_name, ++ unsigned int fc0_src) ++{ ++ struct clk *ref_clk = __clk_lookup(fc0_ref_clk_name); ++ unsigned long result; ++ ktime_t timeout; ++ unsigned int fc_idx, fc_offset, fc_src; ++ ++ fc_idx = fc0_src / 32; ++ fc_src = fc0_src % 32; ++ ++ /* fc_src == 0 is invalid. */ ++ if (!fc_src || fc_idx >= FC_COUNT) ++ return 0; ++ ++ fc_offset = fc_idx * FC_SIZE; ++ ++ /* Ensure the frequency counter is idle. */ ++ timeout = ktime_add_ns(ktime_get(), FC_TIMEOUT_NS); ++ while (clockman_read(clockman, fc_offset + FC0_STATUS) & FC0_STATUS_RUNNING) { ++ if (ktime_after(ktime_get(), timeout)) { ++ dev_err(clockman->dev, "%s: FC0 busy timeout\n", ++ clk_name); ++ return 0; ++ } ++ cpu_relax(); ++ } ++ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, fc_offset + FC0_REF_KHZ, ++ clk_get_rate(ref_clk) / KHz); ++ clockman_write(clockman, fc_offset + FC0_MIN_KHZ, 0); ++ clockman_write(clockman, fc_offset + FC0_MAX_KHZ, 0x1ffffff); ++ clockman_write(clockman, fc_offset + FC0_INTERVAL, 8); ++ clockman_write(clockman, fc_offset + FC0_DELAY, 7); ++ clockman_write(clockman, fc_offset + FC0_SRC, fc_src); ++ spin_unlock(&clockman->regs_lock); ++ ++ /* Ensure the frequency counter is idle. */ ++ timeout = ktime_add_ns(ktime_get(), FC_TIMEOUT_NS); ++ while (!(clockman_read(clockman, fc_offset + FC0_STATUS) & FC0_STATUS_DONE)) { ++ if (ktime_after(ktime_get(), timeout)) { ++ dev_err(clockman->dev, "%s: FC0 wait timeout\n", ++ clk_name); ++ return 0; ++ } ++ cpu_relax(); ++ } ++ ++ result = clockman_read(clockman, fc_offset + FC0_RESULT); ++ ++ /* Disable FC0 */ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, fc_offset + FC0_SRC, 0); ++ spin_unlock(&clockman->regs_lock); ++ ++ return result; ++} ++#endif ++ ++static int rp1_pll_core_is_on(struct clk_hw *hw) ++{ ++ struct rp1_pll_core *pll_core = container_of(hw, struct rp1_pll_core, hw); ++ struct rp1_clockman *clockman = pll_core->clockman; ++ const struct rp1_pll_core_data *data = pll_core->data; ++ u32 pwr = clockman_read(clockman, data->pwr_reg); ++ ++ return (pwr & PLL_PWR_PD) || (pwr & PLL_PWR_POSTDIVPD); ++} ++ ++static int rp1_pll_core_on(struct clk_hw *hw) ++{ ++ struct rp1_pll_core *pll_core = container_of(hw, struct rp1_pll_core, hw); ++ struct rp1_clockman *clockman = pll_core->clockman; ++ const struct rp1_pll_core_data *data = pll_core->data; ++ u32 fbdiv_frac; ++ ktime_t timeout; ++ ++ spin_lock(&clockman->regs_lock); ++ ++ if (!(clockman_read(clockman, data->cs_reg) & PLL_CS_LOCK)) { ++ /* Reset to a known state. */ ++ clockman_write(clockman, data->pwr_reg, PLL_PWR_MASK); ++ clockman_write(clockman, data->fbdiv_int_reg, 20); ++ clockman_write(clockman, data->fbdiv_frac_reg, 0); ++ clockman_write(clockman, data->cs_reg, 1 << PLL_CS_REFDIV_SHIFT); ++ } ++ ++ /* Come out of reset. */ ++ fbdiv_frac = clockman_read(clockman, data->fbdiv_frac_reg); ++ clockman_write(clockman, data->pwr_reg, fbdiv_frac ? 0 : PLL_PWR_DSMPD); ++ spin_unlock(&clockman->regs_lock); ++ ++ /* Wait for the PLL to lock. */ ++ timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); ++ while (!(clockman_read(clockman, data->cs_reg) & PLL_CS_LOCK)) { ++ if (ktime_after(ktime_get(), timeout)) { ++ dev_err(clockman->dev, "%s: can't lock PLL\n", ++ clk_hw_get_name(hw)); ++ return -ETIMEDOUT; ++ } ++ cpu_relax(); ++ } ++ ++ return 0; ++} ++ ++static void rp1_pll_core_off(struct clk_hw *hw) ++{ ++ struct rp1_pll_core *pll_core = container_of(hw, struct rp1_pll_core, hw); ++ struct rp1_clockman *clockman = pll_core->clockman; ++ const struct rp1_pll_core_data *data = pll_core->data; ++ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, data->pwr_reg, 0); ++ spin_unlock(&clockman->regs_lock); ++} ++ ++static inline unsigned long get_pll_core_divider(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long parent_rate, ++ u32 *div_int, u32 *div_frac) ++{ ++ unsigned long calc_rate; ++ u32 fbdiv_int, fbdiv_frac; ++ u64 div_fp64; /* 32.32 fixed point fraction. */ ++ ++ /* Factor of reference clock to VCO frequency. */ ++ div_fp64 = (u64)(rate) << 32; ++ div_fp64 = DIV_U64_NEAREST(div_fp64, parent_rate); ++ ++ /* Round the fractional component at 24 bits. */ ++ div_fp64 += 1 << (32 - 24 - 1); ++ ++ fbdiv_int = div_fp64 >> 32; ++ fbdiv_frac = (div_fp64 >> (32 - 24)) & 0xffffff; ++ ++ calc_rate = ++ ((u64)parent_rate * (((u64)fbdiv_int << 24) + fbdiv_frac) + (1 << 23)) >> 24; ++ ++ *div_int = fbdiv_int; ++ *div_frac = fbdiv_frac; ++ ++ return calc_rate; ++} ++ ++static int rp1_pll_core_set_rate(struct clk_hw *hw, ++ unsigned long rate, unsigned long parent_rate) ++{ ++ struct rp1_pll_core *pll_core = container_of(hw, struct rp1_pll_core, hw); ++ struct rp1_clockman *clockman = pll_core->clockman; ++ const struct rp1_pll_core_data *data = pll_core->data; ++ unsigned long calc_rate; ++ u32 fbdiv_int, fbdiv_frac; ++ ++ // todo: is this needed?? ++ //rp1_pll_off(hw); ++ ++ /* Disable dividers to start with. */ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, data->fbdiv_int_reg, 0); ++ clockman_write(clockman, data->fbdiv_frac_reg, 0); ++ spin_unlock(&clockman->regs_lock); ++ ++ calc_rate = get_pll_core_divider(hw, rate, parent_rate, ++ &fbdiv_int, &fbdiv_frac); ++ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, data->pwr_reg, fbdiv_frac ? 0 : PLL_PWR_DSMPD); ++ clockman_write(clockman, data->fbdiv_int_reg, fbdiv_int); ++ clockman_write(clockman, data->fbdiv_frac_reg, fbdiv_frac); ++ spin_unlock(&clockman->regs_lock); ++ ++ /* Check that reference frequency is no greater than VCO / 16. */ ++ BUG_ON(parent_rate > (rate / 16)); ++ ++ pll_core->cached_rate = calc_rate; ++ ++ spin_lock(&clockman->regs_lock); ++ /* Don't need to divide ref unless parent_rate > (output freq / 16) */ ++ clockman_write(clockman, data->cs_reg, ++ clockman_read(clockman, data->cs_reg) | ++ (1 << PLL_CS_REFDIV_SHIFT)); ++ spin_unlock(&clockman->regs_lock); ++ ++ return 0; ++} ++ ++static unsigned long rp1_pll_core_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct rp1_pll_core *pll_core = container_of(hw, struct rp1_pll_core, hw); ++ struct rp1_clockman *clockman = pll_core->clockman; ++ const struct rp1_pll_core_data *data = pll_core->data; ++ u32 fbdiv_int, fbdiv_frac; ++ unsigned long calc_rate; ++ ++ fbdiv_int = clockman_read(clockman, data->fbdiv_int_reg); ++ fbdiv_frac = clockman_read(clockman, data->fbdiv_frac_reg); ++ calc_rate = ++ ((u64)parent_rate * (((u64)fbdiv_int << 24) + fbdiv_frac) + (1 << 23)) >> 24; ++ ++ return calc_rate; ++} ++ ++static long rp1_pll_core_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ u32 fbdiv_int, fbdiv_frac; ++ long calc_rate; ++ ++ calc_rate = get_pll_core_divider(hw, rate, *parent_rate, ++ &fbdiv_int, &fbdiv_frac); ++ return calc_rate; ++} ++ ++static void rp1_pll_core_debug_init(struct clk_hw *hw, struct dentry *dentry) ++{ ++ struct rp1_pll_core *pll_core = container_of(hw, struct rp1_pll_core, hw); ++ struct rp1_clockman *clockman = pll_core->clockman; ++ const struct rp1_pll_core_data *data = pll_core->data; ++ struct debugfs_reg32 *regs; ++ ++ regs = devm_kcalloc(clockman->dev, 4, sizeof(*regs), GFP_KERNEL); ++ if (!regs) ++ return; ++ ++ regs0.name = "cs"; ++ regs0.offset = data->cs_reg; ++ regs1.name = "pwr"; ++ regs1.offset = data->pwr_reg; ++ regs2.name = "fbdiv_int"; ++ regs2.offset = data->fbdiv_int_reg; ++ regs3.name = "fbdiv_frac"; ++ regs3.offset = data->fbdiv_frac_reg; ++ ++ rp1_debugfs_regset(clockman, 0, regs, 4, dentry); ++} ++ ++static void get_pll_prim_dividers(unsigned long rate, unsigned long parent_rate, ++ u32 *divider1, u32 *divider2) ++{ ++ unsigned int div1, div2; ++ unsigned int best_div1 = 7, best_div2 = 7; ++ unsigned long best_rate_diff = ++ ABS_DIFF(DIV_ROUND_CLOSEST(parent_rate, best_div1 * best_div2), rate); ++ long rate_diff, calc_rate; ++ ++ for (div1 = 1; div1 <= 7; div1++) { ++ for (div2 = 1; div2 <= div1; div2++) { ++ calc_rate = DIV_ROUND_CLOSEST(parent_rate, div1 * div2); ++ rate_diff = ABS_DIFF(calc_rate, rate); ++ ++ if (calc_rate == rate) { ++ best_div1 = div1; ++ best_div2 = div2; ++ goto done; ++ } else if (rate_diff < best_rate_diff) { ++ best_div1 = div1; ++ best_div2 = div2; ++ best_rate_diff = rate_diff; ++ } ++ } ++ } ++ ++done: ++ *divider1 = best_div1; ++ *divider2 = best_div2; ++} ++ ++static int rp1_pll_set_rate(struct clk_hw *hw, ++ unsigned long rate, unsigned long parent_rate) ++{ ++ struct rp1_pll *pll = container_of(hw, struct rp1_pll, hw); ++ struct rp1_clockman *clockman = pll->clockman; ++ const struct rp1_pll_data *data = pll->data; ++ u32 prim, prim_div1, prim_div2; ++ ++ get_pll_prim_dividers(rate, parent_rate, &prim_div1, &prim_div2); ++ ++ spin_lock(&clockman->regs_lock); ++ prim = clockman_read(clockman, data->ctrl_reg); ++ prim = set_register_field(prim, prim_div1, PLL_PRIM_DIV1_MASK, ++ PLL_PRIM_DIV1_SHIFT); ++ prim = set_register_field(prim, prim_div2, PLL_PRIM_DIV2_MASK, ++ PLL_PRIM_DIV2_SHIFT); ++ clockman_write(clockman, data->ctrl_reg, prim); ++ spin_unlock(&clockman->regs_lock); ++ ++#ifdef MEASURE_CLOCK_RATE ++ clockman_measure_clock(clockman, data->name, data->fc0_src); ++#endif ++ return 0; ++} ++ ++static unsigned long rp1_pll_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct rp1_pll *pll = container_of(hw, struct rp1_pll, hw); ++ struct rp1_clockman *clockman = pll->clockman; ++ const struct rp1_pll_data *data = pll->data; ++ u32 prim, prim_div1, prim_div2; ++ ++ prim = clockman_read(clockman, data->ctrl_reg); ++ prim_div1 = (prim & PLL_PRIM_DIV1_MASK) >> PLL_PRIM_DIV1_SHIFT; ++ prim_div2 = (prim & PLL_PRIM_DIV2_MASK) >> PLL_PRIM_DIV2_SHIFT; ++ ++ if (!prim_div1 || !prim_div2) { ++ dev_err(clockman->dev, "%s: (%s) zero divider value\n", ++ __func__, data->name); ++ return 0; ++ } ++ ++ return DIV_ROUND_CLOSEST(parent_rate, prim_div1 * prim_div2); ++} ++ ++static long rp1_pll_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ const struct rp1_clk_change *chg = &rp1_clk_chg_tree1; ++ u32 div1, div2; ++ ++ if (chg->hw == hw && chg->new_rate == rate) ++ *parent_rate = chg1.new_rate; ++ ++ get_pll_prim_dividers(rate, *parent_rate, &div1, &div2); ++ ++ return DIV_ROUND_CLOSEST(*parent_rate, div1 * div2); ++} ++ ++static void rp1_pll_debug_init(struct clk_hw *hw, ++ struct dentry *dentry) ++{ ++ struct rp1_pll *pll = container_of(hw, struct rp1_pll, hw); ++ struct rp1_clockman *clockman = pll->clockman; ++ const struct rp1_pll_data *data = pll->data; ++ struct debugfs_reg32 *regs; ++ ++ regs = devm_kcalloc(clockman->dev, 1, sizeof(*regs), GFP_KERNEL); ++ if (!regs) ++ return; ++ ++ regs0.name = "prim"; ++ regs0.offset = data->ctrl_reg; ++ ++ rp1_debugfs_regset(clockman, 0, regs, 1, dentry); ++} ++ ++static int rp1_pll_ph_is_on(struct clk_hw *hw) ++{ ++ struct rp1_pll_ph *pll = container_of(hw, struct rp1_pll_ph, hw); ++ struct rp1_clockman *clockman = pll->clockman; ++ const struct rp1_pll_ph_data *data = pll->data; ++ ++ return !!(clockman_read(clockman, data->ph_reg) & PLL_PH_EN); ++} ++ ++static int rp1_pll_ph_on(struct clk_hw *hw) ++{ ++ struct rp1_pll_ph *pll_ph = container_of(hw, struct rp1_pll_ph, hw); ++ struct rp1_clockman *clockman = pll_ph->clockman; ++ const struct rp1_pll_ph_data *data = pll_ph->data; ++ u32 ph_reg; ++ ++ /* todo: ensure pri/sec is enabled! */ ++ spin_lock(&clockman->regs_lock); ++ ph_reg = clockman_read(clockman, data->ph_reg); ++ ph_reg |= data->phase << PLL_PH_PHASE_SHIFT; ++ ph_reg |= PLL_PH_EN; ++ clockman_write(clockman, data->ph_reg, ph_reg); ++ spin_unlock(&clockman->regs_lock); ++ ++#ifdef MEASURE_CLOCK_RATE ++ clockman_measure_clock(clockman, data->name, data->fc0_src); ++#endif ++ return 0; ++} ++ ++static void rp1_pll_ph_off(struct clk_hw *hw) ++{ ++ struct rp1_pll_ph *pll_ph = container_of(hw, struct rp1_pll_ph, hw); ++ struct rp1_clockman *clockman = pll_ph->clockman; ++ const struct rp1_pll_ph_data *data = pll_ph->data; ++ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, data->ph_reg, ++ clockman_read(clockman, data->ph_reg) & ~PLL_PH_EN); ++ spin_unlock(&clockman->regs_lock); ++} ++ ++static int rp1_pll_ph_set_rate(struct clk_hw *hw, ++ unsigned long rate, unsigned long parent_rate) ++{ ++ struct rp1_pll_ph *pll_ph = container_of(hw, struct rp1_pll_ph, hw); ++ const struct rp1_pll_ph_data *data = pll_ph->data; ++ struct rp1_clockman *clockman = pll_ph->clockman; ++ ++ /* Nothing really to do here! */ ++ WARN_ON(data->fixed_divider != 1 && data->fixed_divider != 2); ++ WARN_ON(rate != parent_rate / data->fixed_divider); ++ ++#ifdef MEASURE_CLOCK_RATE ++ if (rp1_pll_ph_is_on(hw)) ++ clockman_measure_clock(clockman, data->name, data->fc0_src); ++#endif ++ return 0; ++} ++ ++static unsigned long rp1_pll_ph_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct rp1_pll_ph *pll_ph = container_of(hw, struct rp1_pll_ph, hw); ++ const struct rp1_pll_ph_data *data = pll_ph->data; ++ ++ return parent_rate / data->fixed_divider; ++} ++ ++static long rp1_pll_ph_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ struct rp1_pll_ph *pll_ph = container_of(hw, struct rp1_pll_ph, hw); ++ const struct rp1_pll_ph_data *data = pll_ph->data; ++ ++ return *parent_rate / data->fixed_divider; ++} ++ ++static void rp1_pll_ph_debug_init(struct clk_hw *hw, ++ struct dentry *dentry) ++{ ++ struct rp1_pll_ph *pll_ph = container_of(hw, struct rp1_pll_ph, hw); ++ const struct rp1_pll_ph_data *data = pll_ph->data; ++ struct rp1_clockman *clockman = pll_ph->clockman; ++ struct debugfs_reg32 *regs; ++ ++ regs = devm_kcalloc(clockman->dev, 1, sizeof(*regs), GFP_KERNEL); ++ if (!regs) ++ return; ++ ++ regs0.name = "ph_reg"; ++ regs0.offset = data->ph_reg; ++ ++ rp1_debugfs_regset(clockman, 0, regs, 1, dentry); ++} ++ ++static int rp1_pll_divider_is_on(struct clk_hw *hw) ++{ ++ struct rp1_pll *divider = container_of(hw, struct rp1_pll, div.hw); ++ struct rp1_clockman *clockman = divider->clockman; ++ const struct rp1_pll_data *data = divider->data; ++ ++ return !(clockman_read(clockman, data->ctrl_reg) & PLL_SEC_RST); ++} ++ ++static int rp1_pll_divider_on(struct clk_hw *hw) ++{ ++ struct rp1_pll *divider = container_of(hw, struct rp1_pll, div.hw); ++ struct rp1_clockman *clockman = divider->clockman; ++ const struct rp1_pll_data *data = divider->data; ++ ++ spin_lock(&clockman->regs_lock); ++ /* Check the implementation bit is set! */ ++ WARN_ON(!(clockman_read(clockman, data->ctrl_reg) & PLL_SEC_IMPL)); ++ clockman_write(clockman, data->ctrl_reg, ++ clockman_read(clockman, data->ctrl_reg) & ~PLL_SEC_RST); ++ spin_unlock(&clockman->regs_lock); ++ ++#ifdef MEASURE_CLOCK_RATE ++ clockman_measure_clock(clockman, data->name, data->fc0_src); ++#endif ++ return 0; ++} ++ ++static void rp1_pll_divider_off(struct clk_hw *hw) ++{ ++ struct rp1_pll *divider = container_of(hw, struct rp1_pll, div.hw); ++ struct rp1_clockman *clockman = divider->clockman; ++ const struct rp1_pll_data *data = divider->data; ++ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, data->ctrl_reg, PLL_SEC_RST); ++ spin_unlock(&clockman->regs_lock); ++} ++ ++static int rp1_pll_divider_set_rate(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct rp1_pll *divider = container_of(hw, struct rp1_pll, div.hw); ++ struct rp1_clockman *clockman = divider->clockman; ++ const struct rp1_pll_data *data = divider->data; ++ u32 div, sec; ++ ++ div = DIV_ROUND_UP_ULL(parent_rate, rate); ++ div = clamp(div, 8u, 19u); ++ ++ spin_lock(&clockman->regs_lock); ++ sec = clockman_read(clockman, data->ctrl_reg); ++ sec = set_register_field(sec, div, PLL_SEC_DIV_MASK, PLL_SEC_DIV_SHIFT); ++ ++ /* Must keep the divider in reset to change the value. */ ++ sec |= PLL_SEC_RST; ++ clockman_write(clockman, data->ctrl_reg, sec); ++ ++ // todo: must sleep 10 pll vco cycles ++ sec &= ~PLL_SEC_RST; ++ clockman_write(clockman, data->ctrl_reg, sec); ++ spin_unlock(&clockman->regs_lock); ++ ++#ifdef MEASURE_CLOCK_RATE ++ if (rp1_pll_divider_is_on(hw)) ++ clockman_measure_clock(clockman, data->name, data->fc0_src); ++#endif ++ return 0; ++} ++ ++static unsigned long rp1_pll_divider_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ return clk_divider_ops.recalc_rate(hw, parent_rate); ++} ++ ++static long rp1_pll_divider_round_rate(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ return clk_divider_ops.round_rate(hw, rate, parent_rate); ++} ++ ++static void rp1_pll_divider_debug_init(struct clk_hw *hw, struct dentry *dentry) ++{ ++ struct rp1_pll *divider = container_of(hw, struct rp1_pll, div.hw); ++ struct rp1_clockman *clockman = divider->clockman; ++ const struct rp1_pll_data *data = divider->data; ++ struct debugfs_reg32 *regs; ++ ++ regs = devm_kcalloc(clockman->dev, 1, sizeof(*regs), GFP_KERNEL); ++ if (!regs) ++ return; ++ ++ regs0.name = "sec"; ++ regs0.offset = data->ctrl_reg; ++ ++ rp1_debugfs_regset(clockman, 0, regs, 1, dentry); ++} ++ ++static int rp1_clock_is_on(struct clk_hw *hw) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ struct rp1_clockman *clockman = clock->clockman; ++ const struct rp1_clock_data *data = clock->data; ++ ++ return !!(clockman_read(clockman, data->ctrl_reg) & CLK_CTRL_ENABLE); ++} ++ ++static unsigned long rp1_clock_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ struct rp1_clockman *clockman = clock->clockman; ++ const struct rp1_clock_data *data = clock->data; ++ u64 calc_rate; ++ u64 div; ++ ++ u32 frac; ++ ++ div = clockman_read(clockman, data->div_int_reg); ++ frac = (data->div_frac_reg != 0) ? ++ clockman_read(clockman, data->div_frac_reg) : 0; ++ ++ /* If the integer portion of the divider is 0, treat it as 2^16 */ ++ if (!div) ++ div = 1 << 16; ++ ++ div = (div << CLK_DIV_FRAC_BITS) | (frac >> (32 - CLK_DIV_FRAC_BITS)); ++ ++ calc_rate = (u64)parent_rate << CLK_DIV_FRAC_BITS; ++ calc_rate = div64_u64(calc_rate, div); ++ ++ return calc_rate; ++} ++ ++static int rp1_clock_on(struct clk_hw *hw) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ struct rp1_clockman *clockman = clock->clockman; ++ const struct rp1_clock_data *data = clock->data; ++ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, data->ctrl_reg, ++ clockman_read(clockman, data->ctrl_reg) | CLK_CTRL_ENABLE); ++ /* If this is a GPCLK, turn on the output-enable */ ++ if (data->oe_mask) ++ clockman_write(clockman, GPCLK_OE_CTRL, ++ clockman_read(clockman, GPCLK_OE_CTRL) | data->oe_mask); ++ spin_unlock(&clockman->regs_lock); ++ ++#ifdef MEASURE_CLOCK_RATE ++ clockman_measure_clock(clockman, data->name, data->fc0_src); ++#endif ++ return 0; ++} ++ ++static void rp1_clock_off(struct clk_hw *hw) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ struct rp1_clockman *clockman = clock->clockman; ++ const struct rp1_clock_data *data = clock->data; ++ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, data->ctrl_reg, ++ clockman_read(clockman, data->ctrl_reg) & ~CLK_CTRL_ENABLE); ++ /* If this is a GPCLK, turn off the output-enable */ ++ if (data->oe_mask) ++ clockman_write(clockman, GPCLK_OE_CTRL, ++ clockman_read(clockman, GPCLK_OE_CTRL) & ~data->oe_mask); ++ spin_unlock(&clockman->regs_lock); ++} ++ ++static u32 rp1_clock_choose_div(unsigned long rate, unsigned long parent_rate, ++ const struct rp1_clock_data *data) ++{ ++ u64 div; ++ ++ /* ++ * Due to earlier rounding, calculated parent_rate may differ from ++ * expected value. Don't fail on a small discrepancy near unity divide. ++ */ ++ if (!rate || rate > parent_rate + (parent_rate >> CLK_DIV_FRAC_BITS)) ++ return 0; ++ ++ /* ++ * Always express div in fixed-point format for fractional division; ++ * If no fractional divider is present, the fraction part will be zero. ++ */ ++ if (data->div_frac_reg) { ++ div = (u64)parent_rate << CLK_DIV_FRAC_BITS; ++ div = DIV_U64_NEAREST(div, rate); ++ } else { ++ div = DIV_U64_NEAREST(parent_rate, rate); ++ div <<= CLK_DIV_FRAC_BITS; ++ } ++ ++ div = clamp(div, ++ 1ull << CLK_DIV_FRAC_BITS, ++ (u64)data->div_int_max << CLK_DIV_FRAC_BITS); ++ ++ return div; ++} ++ ++static u8 rp1_clock_get_parent(struct clk_hw *hw) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ struct rp1_clockman *clockman = clock->clockman; ++ const struct rp1_clock_data *data = clock->data; ++ u32 sel, ctrl; ++ u8 parent; ++ ++ /* Sel is one-hot, so find the first bit set */ ++ sel = clockman_read(clockman, data->sel_reg); ++ parent = ffs(sel) - 1; ++ ++ /* sel == 0 implies the parent clock is not enabled yet. */ ++ if (!sel) { ++ /* Read the clock src from the CTRL register instead */ ++ ctrl = clockman_read(clockman, data->ctrl_reg); ++ parent = (ctrl & data->clk_src_mask) >> CLK_CTRL_SRC_SHIFT; ++ } ++ ++ if (parent >= data->num_std_parents) ++ parent = AUX_SEL; ++ ++ if (parent == AUX_SEL) { ++ /* ++ * Clock parent is an auxiliary source, so get the parent from ++ * the AUXSRC register field. ++ */ ++ ctrl = clockman_read(clockman, data->ctrl_reg); ++ parent = (ctrl & CLK_CTRL_AUXSRC_MASK) >> CLK_CTRL_AUXSRC_SHIFT; ++ parent += data->num_std_parents; ++ } ++ ++ return parent; ++} ++ ++static int rp1_clock_set_parent(struct clk_hw *hw, u8 index) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ struct rp1_clockman *clockman = clock->clockman; ++ const struct rp1_clock_data *data = clock->data; ++ u32 ctrl, sel; ++ ++ spin_lock(&clockman->regs_lock); ++ ctrl = clockman_read(clockman, data->ctrl_reg); ++ ++ if (index >= data->num_std_parents) { ++ /* This is an aux source request */ ++ if (index >= data->num_std_parents + data->num_aux_parents) ++ return -EINVAL; ++ ++ /* Select parent from aux list */ ++ ctrl = set_register_field(ctrl, index - data->num_std_parents, ++ CLK_CTRL_AUXSRC_MASK, ++ CLK_CTRL_AUXSRC_SHIFT); ++ /* Set src to aux list */ ++ ctrl = set_register_field(ctrl, AUX_SEL, data->clk_src_mask, ++ CLK_CTRL_SRC_SHIFT); ++ } else { ++ ctrl = set_register_field(ctrl, index, data->clk_src_mask, ++ CLK_CTRL_SRC_SHIFT); ++ } ++ ++ clockman_write(clockman, data->ctrl_reg, ctrl); ++ spin_unlock(&clockman->regs_lock); ++ ++ sel = rp1_clock_get_parent(hw); ++ WARN(sel != index, "(%s): Parent index req %u returned back %u\n", ++ data->name, index, sel); ++ ++ return 0; ++} ++ ++static int rp1_clock_set_rate_and_parent(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long parent_rate, ++ u8 parent) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ struct rp1_clockman *clockman = clock->clockman; ++ const struct rp1_clock_data *data = clock->data; ++ u32 div = rp1_clock_choose_div(rate, parent_rate, data); ++ ++ WARN(rate > 4000000000ll, "rate is -ve (%d)\n", (int)rate); ++ ++ if (WARN(!div, ++ "clk divider calculated as 0! (%s, rate %ld, parent rate %ld)\n", ++ data->name, rate, parent_rate)) ++ div = 1 << CLK_DIV_FRAC_BITS; ++ ++ spin_lock(&clockman->regs_lock); ++ ++ clockman_write(clockman, data->div_int_reg, div >> CLK_DIV_FRAC_BITS); ++ if (data->div_frac_reg) ++ clockman_write(clockman, data->div_frac_reg, div << (32 - CLK_DIV_FRAC_BITS)); ++ ++ spin_unlock(&clockman->regs_lock); ++ ++ if (parent != 0xff) ++ rp1_clock_set_parent(hw, parent); ++ ++#ifdef MEASURE_CLOCK_RATE ++ if (rp1_clock_is_on(hw)) ++ clockman_measure_clock(clockman, data->name, data->fc0_src); ++#endif ++ return 0; ++} ++ ++static int rp1_clock_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ return rp1_clock_set_rate_and_parent(hw, rate, parent_rate, 0xff); ++} ++ ++static unsigned long calc_core_pll_rate(struct clk_hw *pll_hw, ++ unsigned long target_rate, ++ int *pdiv_prim, int *pdiv_clk) ++{ ++ static const int prim_divs = { ++ 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, ++ 18, 20, 21, 24, 25, 28, 30, 35, 36, 42, 49, ++ }; ++ const unsigned long xosc_rate = clk_hw_get_rate(clk_xosc); ++ const unsigned long core_max = 2400000000; ++ const unsigned long core_min = xosc_rate * 16; ++ unsigned long best_rate = core_max + 1; ++ int best_div_prim = 1, best_div_clk = 1; ++ unsigned long core_rate = 0; ++ int div_int, div_frac; ++ u64 div; ++ int i; ++ ++ /* Given the target rate, choose a set of divisors/multipliers */ ++ for (i = 0; i < ARRAY_SIZE(prim_divs); i++) { ++ int div_prim = prim_divsi; ++ int div_clk; ++ ++ for (div_clk = 1; div_clk <= 256; div_clk++) { ++ core_rate = target_rate * div_clk * div_prim; ++ if (core_rate >= core_min) { ++ if (core_rate < best_rate) { ++ best_rate = core_rate; ++ best_div_prim = div_prim; ++ best_div_clk = div_clk; ++ } ++ break; ++ } ++ } ++ } ++ ++ if (best_rate < core_max) { ++ div = ((best_rate << 24) + xosc_rate / 2) / xosc_rate; ++ div_int = div >> 24; ++ div_frac = div % (1 << 24); ++ core_rate = (xosc_rate * ((div_int << 24) + div_frac) + (1 << 23)) >> 24; ++ } else { ++ core_rate = 0; ++ } ++ ++ if (pdiv_prim) ++ *pdiv_prim = best_div_prim; ++ if (pdiv_clk) ++ *pdiv_clk = best_div_clk; ++ ++ return core_rate; ++} ++ ++static void rp1_clock_choose_div_and_prate(struct clk_hw *hw, ++ int parent_idx, ++ unsigned long rate, ++ unsigned long *prate, ++ unsigned long *calc_rate) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ const struct rp1_clock_data *data = clock->data; ++ struct clk_hw *parent; ++ u32 div; ++ u64 tmp; ++ int i; ++ ++ parent = clk_hw_get_parent_by_index(hw, parent_idx); ++ ++ for (i = 0; i < ARRAY_SIZE(rp1_clk_chg_tree); i++) { ++ const struct rp1_clk_change *chg = &rp1_clk_chg_treei; ++ ++ if (chg->hw == hw && chg->new_rate == rate) { ++ if (i == 2) ++ *prate = clk_hw_get_rate(clk_xosc); ++ else if (parent == rp1_clk_chg_treei + 1.hw) ++ *prate = rp1_clk_chg_treei + 1.new_rate; ++ else ++ continue; ++ *calc_rate = chg->new_rate; ++ return; ++ } ++ } ++ ++ if (hw == clk_i2s && parent == clk_audio) { ++ unsigned long core_rate, audio_rate, i2s_rate; ++ int div_prim, div_clk; ++ ++ core_rate = calc_core_pll_rate(parent, rate, &div_prim, &div_clk); ++ audio_rate = DIV_NEAREST(core_rate, div_prim); ++ i2s_rate = DIV_NEAREST(audio_rate, div_clk); ++ rp1_clk_chg_tree2.hw = clk_hw_get_parent(parent); ++ rp1_clk_chg_tree2.new_rate = core_rate; ++ rp1_clk_chg_tree1.hw = clk_audio; ++ rp1_clk_chg_tree1.new_rate = audio_rate; ++ rp1_clk_chg_tree0.hw = clk_i2s; ++ rp1_clk_chg_tree0.new_rate = i2s_rate; ++ *prate = audio_rate; ++ *calc_rate = i2s_rate; ++ return; ++ } ++ ++ *prate = clk_hw_get_rate(parent); ++ div = rp1_clock_choose_div(rate, *prate, data); ++ ++ if (!div) { ++ *calc_rate = 0; ++ return; ++ } ++ ++ /* Recalculate to account for rounding errors */ ++ tmp = (u64)*prate << CLK_DIV_FRAC_BITS; ++ tmp = div_u64(tmp, div); ++ /* ++ * Prevent overclocks - if all parent choices result in ++ * a downstream clock in excess of the maximum, then the ++ * call to set the clock will fail. ++ */ ++ if (tmp > clock->data->max_freq) ++ *calc_rate = 0; ++ else ++ *calc_rate = tmp; ++} ++ ++static int rp1_clock_determine_rate(struct clk_hw *hw, ++ struct clk_rate_request *req) ++{ ++ struct clk_hw *parent, *best_parent = NULL; ++ unsigned long best_rate = 0; ++ unsigned long best_prate = 0; ++ unsigned long best_rate_diff = ULONG_MAX; ++ unsigned long prate, calc_rate; ++ size_t i; ++ ++ /* ++ * If the NO_REPARENT flag is set, try to use existing parent. ++ */ ++ if ((clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT)) { ++ i = rp1_clock_get_parent(hw); ++ parent = clk_hw_get_parent_by_index(hw, i); ++ if (parent) { ++ rp1_clock_choose_div_and_prate(hw, i, req->rate, &prate, ++ &calc_rate); ++ if (calc_rate > 0) { ++ req->best_parent_hw = parent; ++ req->best_parent_rate = prate; ++ req->rate = calc_rate; ++ return 0; ++ } ++ } ++ } ++ ++ /* ++ * Select parent clock that results in the closest rate (lower or ++ * higher) ++ */ ++ for (i = 0; i < clk_hw_get_num_parents(hw); i++) { ++ parent = clk_hw_get_parent_by_index(hw, i); ++ if (!parent) ++ continue; ++ ++ rp1_clock_choose_div_and_prate(hw, i, req->rate, &prate, ++ &calc_rate); ++ ++ if (ABS_DIFF(calc_rate, req->rate) < best_rate_diff) { ++ best_parent = parent; ++ best_prate = prate; ++ best_rate = calc_rate; ++ best_rate_diff = ABS_DIFF(calc_rate, req->rate); ++ ++ if (best_rate_diff == 0) ++ break; ++ } ++ } ++ ++ if (best_rate == 0) ++ return -EINVAL; ++ ++ req->best_parent_hw = best_parent; ++ req->best_parent_rate = best_prate; ++ req->rate = best_rate; ++ ++ return 0; ++} ++ ++static void rp1_clk_debug_init(struct clk_hw *hw, struct dentry *dentry) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ struct rp1_clockman *clockman = clock->clockman; ++ const struct rp1_clock_data *data = clock->data; ++ struct debugfs_reg32 *regs; ++ int i; ++ ++ regs = devm_kcalloc(clockman->dev, 4, sizeof(*regs), GFP_KERNEL); ++ if (!regs) ++ return; ++ ++ i = 0; ++ regsi.name = "ctrl"; ++ regsi++.offset = data->ctrl_reg; ++ regsi.name = "div_int"; ++ regsi++.offset = data->div_int_reg; ++ regsi.name = "div_frac"; ++ regsi++.offset = data->div_frac_reg; ++ regsi.name = "sel"; ++ regsi++.offset = data->sel_reg; ++ ++ rp1_debugfs_regset(clockman, 0, regs, i, dentry); ++} ++ ++static const struct clk_ops rp1_pll_core_ops = { ++ .is_prepared = rp1_pll_core_is_on, ++ .prepare = rp1_pll_core_on, ++ .unprepare = rp1_pll_core_off, ++ .set_rate = rp1_pll_core_set_rate, ++ .recalc_rate = rp1_pll_core_recalc_rate, ++ .round_rate = rp1_pll_core_round_rate, ++ .debug_init = rp1_pll_core_debug_init, ++}; ++ ++static const struct clk_ops rp1_pll_ops = { ++ .set_rate = rp1_pll_set_rate, ++ .recalc_rate = rp1_pll_recalc_rate, ++ .round_rate = rp1_pll_round_rate, ++ .debug_init = rp1_pll_debug_init, ++}; ++ ++static const struct clk_ops rp1_pll_ph_ops = { ++ .is_prepared = rp1_pll_ph_is_on, ++ .prepare = rp1_pll_ph_on, ++ .unprepare = rp1_pll_ph_off, ++ .set_rate = rp1_pll_ph_set_rate, ++ .recalc_rate = rp1_pll_ph_recalc_rate, ++ .round_rate = rp1_pll_ph_round_rate, ++ .debug_init = rp1_pll_ph_debug_init, ++}; ++ ++static const struct clk_ops rp1_pll_divider_ops = { ++ .is_prepared = rp1_pll_divider_is_on, ++ .prepare = rp1_pll_divider_on, ++ .unprepare = rp1_pll_divider_off, ++ .set_rate = rp1_pll_divider_set_rate, ++ .recalc_rate = rp1_pll_divider_recalc_rate, ++ .round_rate = rp1_pll_divider_round_rate, ++ .debug_init = rp1_pll_divider_debug_init, ++}; ++ ++static const struct clk_ops rp1_clk_ops = { ++ .is_prepared = rp1_clock_is_on, ++ .prepare = rp1_clock_on, ++ .unprepare = rp1_clock_off, ++ .recalc_rate = rp1_clock_recalc_rate, ++ .get_parent = rp1_clock_get_parent, ++ .set_parent = rp1_clock_set_parent, ++ .set_rate_and_parent = rp1_clock_set_rate_and_parent, ++ .set_rate = rp1_clock_set_rate, ++ .determine_rate = rp1_clock_determine_rate, ++ .debug_init = rp1_clk_debug_init, ++}; ++ ++static bool rp1_clk_is_claimed(const char *name); ++ ++static struct clk_hw *rp1_register_pll_core(struct rp1_clockman *clockman, ++ const void *data) ++{ ++ const struct rp1_pll_core_data *pll_core_data = data; ++ struct rp1_pll_core *pll_core; ++ struct clk_init_data init; ++ int ret; ++ ++ memset(&init, 0, sizeof(init)); ++ ++ /* All of the PLL cores derive from the external oscillator. */ ++ init.parent_names = &ref_clock; ++ init.num_parents = 1; ++ init.name = pll_core_data->name; ++ init.ops = &rp1_pll_core_ops; ++ init.flags = pll_core_data->flags | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL; ++ ++ pll_core = kzalloc(sizeof(*pll_core), GFP_KERNEL); ++ if (!pll_core) ++ return NULL; ++ ++ pll_core->clockman = clockman; ++ pll_core->data = pll_core_data; ++ pll_core->hw.init = &init; ++ ++ ret = devm_clk_hw_register(clockman->dev, &pll_core->hw); ++ if (ret) { ++ kfree(pll_core); ++ return NULL; ++ } ++ ++ return &pll_core->hw; ++} ++ ++static struct clk_hw *rp1_register_pll(struct rp1_clockman *clockman, ++ const void *data) ++{ ++ const struct rp1_pll_data *pll_data = data; ++ struct rp1_pll *pll; ++ struct clk_init_data init; ++ int ret; ++ ++ memset(&init, 0, sizeof(init)); ++ ++ init.parent_names = &pll_data->source_pll; ++ init.num_parents = 1; ++ init.name = pll_data->name; ++ init.ops = &rp1_pll_ops; ++ init.flags = pll_data->flags | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL; ++ ++ pll = kzalloc(sizeof(*pll), GFP_KERNEL); ++ if (!pll) ++ return NULL; ++ ++ pll->clockman = clockman; ++ pll->data = pll_data; ++ pll->hw.init = &init; ++ ++ ret = devm_clk_hw_register(clockman->dev, &pll->hw); ++ if (ret) { ++ kfree(pll); ++ return NULL; ++ } ++ ++ return &pll->hw; ++} ++ ++static struct clk_hw *rp1_register_pll_ph(struct rp1_clockman *clockman, ++ const void *data) ++{ ++ const struct rp1_pll_ph_data *ph_data = data; ++ struct rp1_pll_ph *ph; ++ struct clk_init_data init; ++ int ret; ++ ++ memset(&init, 0, sizeof(init)); ++ ++ /* All of the PLLs derive from the external oscillator. */ ++ init.parent_names = &ph_data->source_pll; ++ init.num_parents = 1; ++ init.name = ph_data->name; ++ init.ops = &rp1_pll_ph_ops; ++ init.flags = ph_data->flags | CLK_IGNORE_UNUSED; ++ ++ ph = kzalloc(sizeof(*ph), GFP_KERNEL); ++ if (!ph) ++ return NULL; ++ ++ ph->clockman = clockman; ++ ph->data = ph_data; ++ ph->hw.init = &init; ++ ++ ret = devm_clk_hw_register(clockman->dev, &ph->hw); ++ if (ret) { ++ kfree(ph); ++ return NULL; ++ } ++ ++ return &ph->hw; ++} ++ ++static struct clk_hw *rp1_register_pll_divider(struct rp1_clockman *clockman, ++ const void *data) ++{ ++ const struct rp1_pll_data *divider_data = data; ++ struct rp1_pll *divider; ++ struct clk_init_data init; ++ int ret; ++ ++ memset(&init, 0, sizeof(init)); ++ ++ init.parent_names = ÷r_data->source_pll; ++ init.num_parents = 1; ++ init.name = divider_data->name; ++ init.ops = &rp1_pll_divider_ops; ++ init.flags = divider_data->flags | CLK_IGNORE_UNUSED; ++ ++ divider = devm_kzalloc(clockman->dev, sizeof(*divider), GFP_KERNEL); ++ if (!divider) ++ return NULL; ++ ++ divider->div.reg = clockman->regs + divider_data->ctrl_reg; ++ divider->div.shift = PLL_SEC_DIV_SHIFT; ++ divider->div.width = PLL_SEC_DIV_WIDTH; ++ divider->div.flags = CLK_DIVIDER_ROUND_CLOSEST; ++ divider->div.lock = &clockman->regs_lock; ++ divider->div.hw.init = &init; ++ divider->div.table = pll_sec_div_table; ++ ++ if (!rp1_clk_is_claimed(divider_data->source_pll)) ++ init.flags |= CLK_IS_CRITICAL; ++ if (!rp1_clk_is_claimed(divider_data->name)) ++ divider->div.flags |= CLK_IS_CRITICAL; ++ ++ divider->clockman = clockman; ++ divider->data = divider_data; ++ ++ ret = devm_clk_hw_register(clockman->dev, ÷r->div.hw); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ return ÷r->div.hw; ++} ++ ++static struct clk_hw *rp1_register_clock(struct rp1_clockman *clockman, ++ const void *data) ++{ ++ const struct rp1_clock_data *clock_data = data; ++ struct rp1_clock *clock; ++ struct clk_init_data init; ++ int ret; ++ ++ BUG_ON(MAX_CLK_PARENTS < ++ clock_data->num_std_parents + clock_data->num_aux_parents); ++ /* There must be a gap for the AUX selector */ ++ BUG_ON((clock_data->num_std_parents > AUX_SEL) && ++ strcmp("-", clock_data->parentsAUX_SEL)); ++ ++ memset(&init, 0, sizeof(init)); ++ init.parent_names = clock_data->parents; ++ init.num_parents = ++ clock_data->num_std_parents + clock_data->num_aux_parents; ++ init.name = clock_data->name; ++ init.flags = clock_data->flags | CLK_IGNORE_UNUSED; ++ init.ops = &rp1_clk_ops; ++ ++ clock = devm_kzalloc(clockman->dev, sizeof(*clock), GFP_KERNEL); ++ if (!clock) ++ return NULL; ++ ++ clock->clockman = clockman; ++ clock->data = clock_data; ++ clock->hw.init = &init; ++ ++ ret = devm_clk_hw_register(clockman->dev, &clock->hw); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ return &clock->hw; ++} ++ ++struct rp1_clk_desc { ++ struct clk_hw *(*clk_register)(struct rp1_clockman *clockman, ++ const void *data); ++ const void *data; ++}; ++ ++/* Assignment helper macros for different clock types. */ ++#define _REGISTER(f, ...) { .clk_register = f, .data = __VA_ARGS__ } ++ ++#define REGISTER_PLL_CORE(...) _REGISTER(&rp1_register_pll_core, \ ++ &(struct rp1_pll_core_data) \ ++ {__VA_ARGS__}) ++ ++#define REGISTER_PLL(...) _REGISTER(&rp1_register_pll, \ ++ &(struct rp1_pll_data) \ ++ {__VA_ARGS__}) ++ ++#define REGISTER_PLL_PH(...) _REGISTER(&rp1_register_pll_ph, \ ++ &(struct rp1_pll_ph_data) \ ++ {__VA_ARGS__}) ++ ++#define REGISTER_PLL_DIV(...) _REGISTER(&rp1_register_pll_divider, \ ++ &(struct rp1_pll_data) \ ++ {__VA_ARGS__}) ++ ++#define REGISTER_CLK(...) _REGISTER(&rp1_register_clock, \ ++ &(struct rp1_clock_data) \ ++ {__VA_ARGS__}) ++ ++static const struct rp1_clk_desc clk_desc_array = { ++ RP1_PLL_SYS_CORE = REGISTER_PLL_CORE( ++ .name = "pll_sys_core", ++ .cs_reg = PLL_SYS_CS, ++ .pwr_reg = PLL_SYS_PWR, ++ .fbdiv_int_reg = PLL_SYS_FBDIV_INT, ++ .fbdiv_frac_reg = PLL_SYS_FBDIV_FRAC, ++ ), ++ ++ RP1_PLL_AUDIO_CORE = REGISTER_PLL_CORE( ++ .name = "pll_audio_core", ++ .cs_reg = PLL_AUDIO_CS, ++ .pwr_reg = PLL_AUDIO_PWR, ++ .fbdiv_int_reg = PLL_AUDIO_FBDIV_INT, ++ .fbdiv_frac_reg = PLL_AUDIO_FBDIV_FRAC, ++ ), ++ ++ RP1_PLL_VIDEO_CORE = REGISTER_PLL_CORE( ++ .name = "pll_video_core", ++ .cs_reg = PLL_VIDEO_CS, ++ .pwr_reg = PLL_VIDEO_PWR, ++ .fbdiv_int_reg = PLL_VIDEO_FBDIV_INT, ++ .fbdiv_frac_reg = PLL_VIDEO_FBDIV_FRAC, ++ ), ++ ++ RP1_PLL_SYS = REGISTER_PLL( ++ .name = "pll_sys", ++ .source_pll = "pll_sys_core", ++ .ctrl_reg = PLL_SYS_PRIM, ++ .fc0_src = FC_NUM(0, 2), ++ ), ++ ++ RP1_PLL_AUDIO = REGISTER_PLL( ++ .name = "pll_audio", ++ .source_pll = "pll_audio_core", ++ .ctrl_reg = PLL_AUDIO_PRIM, ++ .fc0_src = FC_NUM(4, 2), ++ .flags = CLK_SET_RATE_PARENT, ++ ), ++ ++ RP1_PLL_VIDEO = REGISTER_PLL( ++ .name = "pll_video", ++ .source_pll = "pll_video_core", ++ .ctrl_reg = PLL_VIDEO_PRIM, ++ .fc0_src = FC_NUM(3, 2), ++ ), ++ ++ RP1_PLL_SYS_PRI_PH = REGISTER_PLL_PH( ++ .name = "pll_sys_pri_ph", ++ .source_pll = "pll_sys", ++ .ph_reg = PLL_SYS_PRIM, ++ .fixed_divider = 2, ++ .phase = RP1_PLL_PHASE_0, ++ .fc0_src = FC_NUM(1, 2), ++ ), ++ ++ RP1_PLL_AUDIO_PRI_PH = REGISTER_PLL_PH( ++ .name = "pll_audio_pri_ph", ++ .source_pll = "pll_audio", ++ .ph_reg = PLL_AUDIO_PRIM, ++ .fixed_divider = 2, ++ .phase = RP1_PLL_PHASE_0, ++ .fc0_src = FC_NUM(5, 1), ++ ), ++ ++ RP1_PLL_VIDEO_PRI_PH = REGISTER_PLL_PH( ++ .name = "pll_video_pri_ph", ++ .source_pll = "pll_video", ++ .ph_reg = PLL_VIDEO_PRIM, ++ .fixed_divider = 2, ++ .phase = RP1_PLL_PHASE_0, ++ .fc0_src = FC_NUM(4, 3), ++ ), ++ ++ RP1_PLL_SYS_SEC = REGISTER_PLL_DIV( ++ .name = "pll_sys_sec", ++ .source_pll = "pll_sys_core", ++ .ctrl_reg = PLL_SYS_SEC, ++ .fc0_src = FC_NUM(2, 2), ++ ), ++ ++ RP1_PLL_AUDIO_SEC = REGISTER_PLL_DIV( ++ .name = "pll_audio_sec", ++ .source_pll = "pll_audio_core", ++ .ctrl_reg = PLL_AUDIO_SEC, ++ .fc0_src = FC_NUM(6, 2), ++ ), ++ ++ RP1_PLL_VIDEO_SEC = REGISTER_PLL_DIV( ++ .name = "pll_video_sec", ++ .source_pll = "pll_video_core", ++ .ctrl_reg = PLL_VIDEO_SEC, ++ .fc0_src = FC_NUM(5, 3), ++ ), ++ ++ RP1_PLL_AUDIO_TERN = REGISTER_PLL_DIV( ++ .name = "pll_audio_tern", ++ .source_pll = "pll_audio_core", ++ .ctrl_reg = PLL_AUDIO_TERN, ++ .fc0_src = FC_NUM(6, 2), ++ ), ++ ++ RP1_CLK_SYS = REGISTER_CLK( ++ .name = "clk_sys", ++ .parents = {"xosc", "-", "pll_sys"}, ++ .num_std_parents = 3, ++ .num_aux_parents = 0, ++ .ctrl_reg = CLK_SYS_CTRL, ++ .div_int_reg = CLK_SYS_DIV_INT, ++ .sel_reg = CLK_SYS_SEL, ++ .div_int_max = DIV_INT_24BIT_MAX, ++ .max_freq = 200 * MHz, ++ .fc0_src = FC_NUM(0, 4), ++ .clk_src_mask = 0x3, ++ ), ++ ++ RP1_CLK_SLOW_SYS = REGISTER_CLK( ++ .name = "clk_slow_sys", ++ .parents = {"xosc"}, ++ .num_std_parents = 1, ++ .num_aux_parents = 0, ++ .ctrl_reg = CLK_SLOW_SYS_CTRL, ++ .div_int_reg = CLK_SLOW_SYS_DIV_INT, ++ .sel_reg = CLK_SLOW_SYS_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .max_freq = 50 * MHz, ++ .fc0_src = FC_NUM(1, 4), ++ .clk_src_mask = 0x1, ++ ), ++ ++ RP1_CLK_UART = REGISTER_CLK( ++ .name = "clk_uart", ++ .parents = {"pll_sys_pri_ph", ++ "pll_video", ++ "xosc", ++ "clksrc_gp0", ++ "clksrc_gp1", ++ "clksrc_gp2", ++ "clksrc_gp3", ++ "clksrc_gp4", ++ "clksrc_gp5"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 9, ++ .ctrl_reg = CLK_UART_CTRL, ++ .div_int_reg = CLK_UART_DIV_INT, ++ .sel_reg = CLK_UART_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .max_freq = 100 * MHz, ++ .fc0_src = FC_NUM(6, 7), ++ ), ++ ++ RP1_CLK_ETH = REGISTER_CLK( ++ .name = "clk_eth", ++ .parents = {"pll_sys_sec", ++ "pll_sys", ++ "pll_video_sec", ++ "clksrc_gp0", ++ "clksrc_gp1", ++ "clksrc_gp2", ++ "clksrc_gp3", ++ "clksrc_gp4", ++ "clksrc_gp5"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 9, ++ .ctrl_reg = CLK_ETH_CTRL, ++ .div_int_reg = CLK_ETH_DIV_INT, ++ .sel_reg = CLK_ETH_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .max_freq = 125 * MHz, ++ .fc0_src = FC_NUM(4, 6), ++ ), ++ ++ RP1_CLK_PWM0 = REGISTER_CLK( ++ .name = "clk_pwm0", ++ .parents = {"", // "pll_audio_pri_ph", ++ "pll_video_sec", ++ "xosc", ++ "clksrc_gp0", ++ "clksrc_gp1", ++ "clksrc_gp2", ++ "clksrc_gp3", ++ "clksrc_gp4", ++ "clksrc_gp5"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 9, ++ .ctrl_reg = CLK_PWM0_CTRL, ++ .div_int_reg = CLK_PWM0_DIV_INT, ++ .div_frac_reg = CLK_PWM0_DIV_FRAC, ++ .sel_reg = CLK_PWM0_SEL, ++ .div_int_max = DIV_INT_16BIT_MAX, ++ .max_freq = 76800 * KHz, ++ .fc0_src = FC_NUM(0, 5), ++ ), ++ ++ RP1_CLK_PWM1 = REGISTER_CLK( ++ .name = "clk_pwm1", ++ .parents = {"", // "pll_audio_pri_ph", ++ "pll_video_sec", ++ "xosc", ++ "clksrc_gp0", ++ "clksrc_gp1", ++ "clksrc_gp2", ++ "clksrc_gp3", ++ "clksrc_gp4", ++ "clksrc_gp5"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 9, ++ .ctrl_reg = CLK_PWM1_CTRL, ++ .div_int_reg = CLK_PWM1_DIV_INT, ++ .div_frac_reg = CLK_PWM1_DIV_FRAC, ++ .sel_reg = CLK_PWM1_SEL, ++ .div_int_max = DIV_INT_16BIT_MAX, ++ .max_freq = 76800 * KHz, ++ .fc0_src = FC_NUM(1, 5), ++ ), ++ ++ RP1_CLK_AUDIO_IN = REGISTER_CLK( ++ .name = "clk_audio_in", ++ .parents = {"", //"pll_audio", ++ "", //"pll_audio_pri_ph", ++ "", //"pll_audio_sec", ++ "pll_video_sec", ++ "xosc", ++ "clksrc_gp0", ++ "clksrc_gp1", ++ "clksrc_gp2", ++ "clksrc_gp3", ++ "clksrc_gp4", ++ "clksrc_gp5"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 11, ++ .ctrl_reg = CLK_AUDIO_IN_CTRL, ++ .div_int_reg = CLK_AUDIO_IN_DIV_INT, ++ .sel_reg = CLK_AUDIO_IN_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .max_freq = 76800 * KHz, ++ .fc0_src = FC_NUM(2, 5), ++ ), ++ ++ RP1_CLK_AUDIO_OUT = REGISTER_CLK( ++ .name = "clk_audio_out", ++ .parents = {"", //"pll_audio", ++ "", //"pll_audio_sec", ++ "pll_video_sec", ++ "xosc", ++ "clksrc_gp0", ++ "clksrc_gp1", ++ "clksrc_gp2", ++ "clksrc_gp3", ++ "clksrc_gp4", ++ "clksrc_gp5"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 10, ++ .ctrl_reg = CLK_AUDIO_OUT_CTRL, ++ .div_int_reg = CLK_AUDIO_OUT_DIV_INT, ++ .sel_reg = CLK_AUDIO_OUT_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .max_freq = 153600 * KHz, ++ .fc0_src = FC_NUM(3, 5), ++ ), ++ ++ RP1_CLK_I2S = REGISTER_CLK( ++ .name = "clk_i2s", ++ .parents = {"xosc", ++ "pll_audio", ++ "pll_audio_sec", ++ "clksrc_gp0", ++ "clksrc_gp1", ++ "clksrc_gp2", ++ "clksrc_gp3", ++ "clksrc_gp4", ++ "clksrc_gp5"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 9, ++ .ctrl_reg = CLK_I2S_CTRL, ++ .div_int_reg = CLK_I2S_DIV_INT, ++ .sel_reg = CLK_I2S_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .max_freq = 50 * MHz, ++ .fc0_src = FC_NUM(4, 4), ++ .flags = CLK_SET_RATE_PARENT, ++ ), ++ ++ RP1_CLK_MIPI0_CFG = REGISTER_CLK( ++ .name = "clk_mipi0_cfg", ++ .parents = {"xosc"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 1, ++ .ctrl_reg = CLK_MIPI0_CFG_CTRL, ++ .div_int_reg = CLK_MIPI0_CFG_DIV_INT, ++ .sel_reg = CLK_MIPI0_CFG_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .max_freq = 50 * MHz, ++ .fc0_src = FC_NUM(4, 5), ++ ), ++ ++ RP1_CLK_MIPI1_CFG = REGISTER_CLK( ++ .name = "clk_mipi1_cfg", ++ .parents = {"xosc"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 1, ++ .ctrl_reg = CLK_MIPI1_CFG_CTRL, ++ .div_int_reg = CLK_MIPI1_CFG_DIV_INT, ++ .sel_reg = CLK_MIPI1_CFG_SEL, ++ .clk_src_mask = 1, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .max_freq = 50 * MHz, ++ .fc0_src = FC_NUM(5, 6), ++ ), ++ ++ RP1_CLK_ETH_TSU = REGISTER_CLK( ++ .name = "clk_eth_tsu", ++ .parents = {"xosc", ++ "pll_video_sec", ++ "clksrc_gp0", ++ "clksrc_gp1", ++ "clksrc_gp2", ++ "clksrc_gp3", ++ "clksrc_gp4", ++ "clksrc_gp5"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 8, ++ .ctrl_reg = CLK_ETH_TSU_CTRL, ++ .div_int_reg = CLK_ETH_TSU_DIV_INT, ++ .sel_reg = CLK_ETH_TSU_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .max_freq = 50 * MHz, ++ .fc0_src = FC_NUM(5, 7), ++ ), ++ ++ RP1_CLK_ADC = REGISTER_CLK( ++ .name = "clk_adc", ++ .parents = {"xosc", ++ "", //"pll_audio_tern", ++ "clksrc_gp0", ++ "clksrc_gp1", ++ "clksrc_gp2", ++ "clksrc_gp3", ++ "clksrc_gp4", ++ "clksrc_gp5"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 8, ++ .ctrl_reg = CLK_ADC_CTRL, ++ .div_int_reg = CLK_ADC_DIV_INT, ++ .sel_reg = CLK_ADC_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .max_freq = 50 * MHz, ++ .fc0_src = FC_NUM(5, 5), ++ ), ++ ++ RP1_CLK_SDIO_TIMER = REGISTER_CLK( ++ .name = "clk_sdio_timer", ++ .parents = {"xosc"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 1, ++ .ctrl_reg = CLK_SDIO_TIMER_CTRL, ++ .div_int_reg = CLK_SDIO_TIMER_DIV_INT, ++ .sel_reg = CLK_SDIO_TIMER_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .max_freq = 50 * MHz, ++ .fc0_src = FC_NUM(3, 4), ++ ), ++ ++ RP1_CLK_SDIO_ALT_SRC = REGISTER_CLK( ++ .name = "clk_sdio_alt_src", ++ .parents = {"pll_sys"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 1, ++ .ctrl_reg = CLK_SDIO_ALT_SRC_CTRL, ++ .div_int_reg = CLK_SDIO_ALT_SRC_DIV_INT, ++ .sel_reg = CLK_SDIO_ALT_SRC_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .max_freq = 200 * MHz, ++ .fc0_src = FC_NUM(5, 4), ++ ), ++ ++ RP1_CLK_GP0 = REGISTER_CLK( ++ .name = "clk_gp0", ++ .parents = {"xosc", ++ "clksrc_gp1", ++ "clksrc_gp2", ++ "clksrc_gp3", ++ "clksrc_gp4", ++ "clksrc_gp5", ++ "pll_sys", ++ "", //"pll_audio", ++ "", ++ "", ++ "clk_i2s", ++ "clk_adc", ++ "", ++ "", ++ "", ++ "clk_sys"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 16, ++ .oe_mask = BIT(0), ++ .ctrl_reg = CLK_GP0_CTRL, ++ .div_int_reg = CLK_GP0_DIV_INT, ++ .div_frac_reg = CLK_GP0_DIV_FRAC, ++ .sel_reg = CLK_GP0_SEL, ++ .div_int_max = DIV_INT_16BIT_MAX, ++ .max_freq = 100 * MHz, ++ .fc0_src = FC_NUM(0, 1), ++ ), ++ ++ RP1_CLK_GP1 = REGISTER_CLK( ++ .name = "clk_gp1", ++ .parents = {"clk_sdio_timer", ++ "clksrc_gp0", ++ "clksrc_gp2", ++ "clksrc_gp3", ++ "clksrc_gp4", ++ "clksrc_gp5", ++ "pll_sys_pri_ph", ++ "", //"pll_audio_pri_ph", ++ "", ++ "", ++ "clk_adc", ++ "clk_dpi", ++ "clk_pwm0", ++ "", ++ "", ++ ""}, ++ .num_std_parents = 0, ++ .num_aux_parents = 16, ++ .oe_mask = BIT(1), ++ .ctrl_reg = CLK_GP1_CTRL, ++ .div_int_reg = CLK_GP1_DIV_INT, ++ .div_frac_reg = CLK_GP1_DIV_FRAC, ++ .sel_reg = CLK_GP1_SEL, ++ .div_int_max = DIV_INT_16BIT_MAX, ++ .max_freq = 100 * MHz, ++ .fc0_src = FC_NUM(1, 1), ++ ), ++ ++ RP1_CLK_GP2 = REGISTER_CLK( ++ .name = "clk_gp2", ++ .parents = {"clk_sdio_alt_src", ++ "clksrc_gp0", ++ "clksrc_gp1", ++ "clksrc_gp3", ++ "clksrc_gp4", ++ "clksrc_gp5", ++ "pll_sys_sec", ++ "", //"pll_audio_sec", ++ "pll_video", ++ "clk_audio_in", ++ "clk_dpi", ++ "clk_pwm0", ++ "clk_pwm1", ++ "clk_mipi0_dpi", ++ "clk_mipi1_cfg", ++ "clk_sys"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 16, ++ .oe_mask = BIT(2), ++ .ctrl_reg = CLK_GP2_CTRL, ++ .div_int_reg = CLK_GP2_DIV_INT, ++ .div_frac_reg = CLK_GP2_DIV_FRAC, ++ .sel_reg = CLK_GP2_SEL, ++ .div_int_max = DIV_INT_16BIT_MAX, ++ .max_freq = 100 * MHz, ++ .fc0_src = FC_NUM(2, 1), ++ ), ++ ++ RP1_CLK_GP3 = REGISTER_CLK( ++ .name = "clk_gp3", ++ .parents = {"xosc", ++ "clksrc_gp0", ++ "clksrc_gp1", ++ "clksrc_gp2", ++ "clksrc_gp4", ++ "clksrc_gp5", ++ "", ++ "", ++ "pll_video_pri_ph", ++ "clk_audio_out", ++ "", ++ "", ++ "clk_mipi1_dpi", ++ "", ++ "", ++ ""}, ++ .num_std_parents = 0, ++ .num_aux_parents = 16, ++ .oe_mask = BIT(3), ++ .ctrl_reg = CLK_GP3_CTRL, ++ .div_int_reg = CLK_GP3_DIV_INT, ++ .div_frac_reg = CLK_GP3_DIV_FRAC, ++ .sel_reg = CLK_GP3_SEL, ++ .div_int_max = DIV_INT_16BIT_MAX, ++ .max_freq = 100 * MHz, ++ .fc0_src = FC_NUM(3, 1), ++ ), ++ ++ RP1_CLK_GP4 = REGISTER_CLK( ++ .name = "clk_gp4", ++ .parents = {"xosc", ++ "clksrc_gp0", ++ "clksrc_gp1", ++ "clksrc_gp2", ++ "clksrc_gp3", ++ "clksrc_gp5", ++ "", //"pll_audio_tern", ++ "pll_video_sec", ++ "", ++ "", ++ "", ++ "clk_mipi0_cfg", ++ "clk_uart", ++ "", ++ "", ++ "clk_sys", ++ }, ++ .num_std_parents = 0, ++ .num_aux_parents = 16, ++ .oe_mask = BIT(4), ++ .ctrl_reg = CLK_GP4_CTRL, ++ .div_int_reg = CLK_GP4_DIV_INT, ++ .div_frac_reg = CLK_GP4_DIV_FRAC, ++ .sel_reg = CLK_GP4_SEL, ++ .div_int_max = DIV_INT_16BIT_MAX, ++ .max_freq = 100 * MHz, ++ .fc0_src = FC_NUM(4, 1), ++ ), ++ ++ RP1_CLK_GP5 = REGISTER_CLK( ++ .name = "clk_gp5", ++ .parents = {"xosc", ++ "clksrc_gp0", ++ "clksrc_gp1", ++ "clksrc_gp2", ++ "clksrc_gp3", ++ "clksrc_gp4", ++ "", //"pll_audio_tern", ++ "pll_video_sec", ++ "clk_eth_tsu", ++ "", ++ "clk_vec", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ .num_std_parents = 0, ++ .num_aux_parents = 16, ++ .oe_mask = BIT(5), ++ .ctrl_reg = CLK_GP5_CTRL, ++ .div_int_reg = CLK_GP5_DIV_INT, ++ .div_frac_reg = CLK_GP5_DIV_FRAC, ++ .sel_reg = CLK_GP5_SEL, ++ .div_int_max = DIV_INT_16BIT_MAX, ++ .max_freq = 100 * MHz, ++ .fc0_src = FC_NUM(5, 1), ++ ), ++ ++ RP1_CLK_VEC = REGISTER_CLK( ++ .name = "clk_vec", ++ .parents = {"pll_sys_pri_ph", ++ "pll_video_sec", ++ "pll_video", ++ "clksrc_gp0", ++ "clksrc_gp1", ++ "clksrc_gp2", ++ "clksrc_gp3", ++ "clksrc_gp4"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 8, /* XXX in fact there are more than 8 */ ++ .ctrl_reg = VIDEO_CLK_VEC_CTRL, ++ .div_int_reg = VIDEO_CLK_VEC_DIV_INT, ++ .sel_reg = VIDEO_CLK_VEC_SEL, ++ .flags = CLK_SET_RATE_NO_REPARENT, /* Let VEC driver set parent */ ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .max_freq = 108 * MHz, ++ .fc0_src = FC_NUM(0, 6), ++ ), ++ ++ RP1_CLK_DPI = REGISTER_CLK( ++ .name = "clk_dpi", ++ .parents = {"pll_sys", ++ "pll_video_sec", ++ "pll_video", ++ "clksrc_gp0", ++ "clksrc_gp1", ++ "clksrc_gp2", ++ "clksrc_gp3", ++ "clksrc_gp4"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 8, /* XXX in fact there are more than 8 */ ++ .ctrl_reg = VIDEO_CLK_DPI_CTRL, ++ .div_int_reg = VIDEO_CLK_DPI_DIV_INT, ++ .sel_reg = VIDEO_CLK_DPI_SEL, ++ .flags = CLK_SET_RATE_NO_REPARENT, /* Let DPI driver set parent */ ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .max_freq = 200 * MHz, ++ .fc0_src = FC_NUM(1, 6), ++ ), ++ ++ RP1_CLK_MIPI0_DPI = REGISTER_CLK( ++ .name = "clk_mipi0_dpi", ++ .parents = {"pll_sys", ++ "pll_video_sec", ++ "pll_video", ++ "clksrc_mipi0_dsi_byteclk", ++ "clksrc_gp0", ++ "clksrc_gp1", ++ "clksrc_gp2", ++ "clksrc_gp3"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 8, /* XXX in fact there are more than 8 */ ++ .ctrl_reg = VIDEO_CLK_MIPI0_DPI_CTRL, ++ .div_int_reg = VIDEO_CLK_MIPI0_DPI_DIV_INT, ++ .div_frac_reg = VIDEO_CLK_MIPI0_DPI_DIV_FRAC, ++ .sel_reg = VIDEO_CLK_MIPI0_DPI_SEL, ++ .flags = CLK_SET_RATE_NO_REPARENT, /* Let DSI driver set parent */ ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .max_freq = 200 * MHz, ++ .fc0_src = FC_NUM(2, 6), ++ ), ++ ++ RP1_CLK_MIPI1_DPI = REGISTER_CLK( ++ .name = "clk_mipi1_dpi", ++ .parents = {"pll_sys", ++ "pll_video_sec", ++ "pll_video", ++ "clksrc_mipi1_dsi_byteclk", ++ "clksrc_gp0", ++ "clksrc_gp1", ++ "clksrc_gp2", ++ "clksrc_gp3"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 8, /* XXX in fact there are more than 8 */ ++ .ctrl_reg = VIDEO_CLK_MIPI1_DPI_CTRL, ++ .div_int_reg = VIDEO_CLK_MIPI1_DPI_DIV_INT, ++ .div_frac_reg = VIDEO_CLK_MIPI1_DPI_DIV_FRAC, ++ .sel_reg = VIDEO_CLK_MIPI1_DPI_SEL, ++ .flags = CLK_SET_RATE_NO_REPARENT, /* Let DSI driver set parent */ ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .max_freq = 200 * MHz, ++ .fc0_src = FC_NUM(3, 6), ++ ), ++}; ++ ++static bool rp1_clk_claimedARRAY_SIZE(clk_desc_array); ++ ++static bool rp1_clk_is_claimed(const char *name) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(clk_desc_array); i++) { ++ if (clk_desc_arrayi.data) { ++ const char *clk_name = *(const char **)(clk_desc_arrayi.data); ++ ++ if (!strcmp(name, clk_name)) ++ return rp1_clk_claimedi; ++ } ++ } ++ ++ return false; ++} ++ ++static int rp1_clk_probe(struct platform_device *pdev) ++{ ++ const struct rp1_clk_desc *desc; ++ struct device *dev = &pdev->dev; ++ struct rp1_clockman *clockman; ++ struct resource *res; ++ struct clk_hw **hws; ++ const size_t asize = ARRAY_SIZE(clk_desc_array); ++ u32 chip_id, platform; ++ unsigned int i; ++ u32 clk_id; ++ int ret; ++ ++ clockman = devm_kzalloc(dev, struct_size(clockman, onecell.hws, asize), ++ GFP_KERNEL); ++ if (!clockman) ++ return -ENOMEM; ++ ++ rp1_get_platform(&chip_id, &platform); ++ ++ spin_lock_init(&clockman->regs_lock); ++ clockman->dev = dev; ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ clockman->regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(clockman->regs)) ++ return PTR_ERR(clockman->regs); ++ ++ memset(rp1_clk_claimed, 0, sizeof(rp1_clk_claimed)); ++ for (i = 0; ++ !of_property_read_u32_index(pdev->dev.of_node, "claim-clocks", ++ i, &clk_id); ++ i++) ++ rp1_clk_claimedclk_id = true; ++ ++ platform_set_drvdata(pdev, clockman); ++ ++ clockman->onecell.num = asize; ++ hws = clockman->onecell.hws; ++ ++ for (i = 0; i < asize; i++) { ++ desc = &clk_desc_arrayi; ++ if (desc->clk_register && desc->data) { ++ hwsi = desc->clk_register(clockman, desc->data); ++ if (!strcmp(clk_hw_get_name(hwsi), "clk_i2s")) { ++ clk_i2s = hwsi; ++ clk_xosc = clk_hw_get_parent_by_index(clk_i2s, 0); ++ clk_audio = clk_hw_get_parent_by_index(clk_i2s, 1); ++ } ++ } ++ } ++ ++ ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, ++ &clockman->onecell); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static const struct of_device_id rp1_clk_of_match = { ++ { .compatible = "raspberrypi,rp1-clocks" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, rp1_clk_of_match); ++ ++static struct platform_driver rp1_clk_driver = { ++ .driver = { ++ .name = "rp1-clk", ++ .of_match_table = rp1_clk_of_match, ++ }, ++ .probe = rp1_clk_probe, ++}; ++ ++static int __init __rp1_clk_driver_init(void) ++{ ++ return platform_driver_register(&rp1_clk_driver); ++} ++postcore_initcall(__rp1_clk_driver_init); ++ ++MODULE_AUTHOR("Naushir Patuck <naush@raspberrypi.com>"); ++MODULE_DESCRIPTION("RP1 clock driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig +index 4ccae1a3b884..7d3435a7df41 100644 +--- a/drivers/dma/Kconfig ++++ b/drivers/dma/Kconfig +@@ -669,6 +669,10 @@ config UNIPHIER_XDMAC + 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 --git a/drivers/dma/Makefile b/drivers/dma/Makefile +index 83553a97a010..b4a8e3585400 100644 +--- a/drivers/dma/Makefile ++++ b/drivers/dma/Makefile +@@ -22,6 +22,7 @@ obj-$(CONFIG_AT_HDMAC) += at_hdmac.o + obj-$(CONFIG_AT_XDMAC) += at_xdmac.o + obj-$(CONFIG_AXI_DMAC) += dma-axi-dmac.o + obj-$(CONFIG_BCM_SBA_RAID) += bcm-sba-raid.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 --git a/drivers/dma/bcm2708-dmaengine.c b/drivers/dma/bcm2708-dmaengine.c +new file mode 100644 +index 000000000000..a9a7f92584c8 +--- /dev/null ++++ b/drivers/dma/bcm2708-dmaengine.c +@@ -0,0 +1,281 @@ ++/* ++ * 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> @@ -49414,8 +69630,8 @@ +{ + struct vc_dmaman *dmaman = g_dmaman; + struct platform_device *pdev = to_platform_device(dmaman_dev); -+ struct resource *r; + int chan; ++ int irq; + + if (!dmaman_dev) + return -ENODEV; @@ -49425,8 +69641,8 @@ + if (chan < 0) + goto out; + -+ r = platform_get_resource(pdev, IORESOURCE_IRQ, (unsigned int)chan); -+ if (!r) { ++ irq = platform_get_irq(pdev, (unsigned int)chan); ++ if (irq < 0) { + dev_err(dmaman_dev, "failed to get irq for DMA channel %d\n", + chan); + vc_dmaman_chan_free(dmaman, chan); @@ -49435,7 +69651,7 @@ + } + + *out_dma_base = BCM2708_DMA_CHANIO(dmaman->dma_base, chan); -+ *out_dma_irq = r->start; ++ *out_dma_irq = irq; + dev_dbg(dmaman_dev, + "Legacy API allocated channel=%d, base=%p, irq=%i\n", + chan, *out_dma_base, *out_dma_irq); @@ -49495,10 +69711,18 @@ + +MODULE_LICENSE("GPL"); diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c -index 630dfbb01a40..94a1b40b1645 100644 +index 0807fb9eb262..e159f976a6b1 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c -@@ -25,6 +25,7 @@ +@@ -18,6 +18,7 @@ + * Copyright 2012 Marvell International Ltd. + */ + #include <linux/dmaengine.h> ++#include <linux/dma-direct.h> + #include <linux/dma-mapping.h> + #include <linux/dmapool.h> + #include <linux/err.h> +@@ -25,6 +26,7 @@ #include <linux/interrupt.h> #include <linux/list.h> #include <linux/module.h> @@ -49506,7 +69730,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/io.h> -@@ -36,6 +37,13 @@ +@@ -36,6 +38,13 @@ #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14 #define BCM2835_DMA_CHAN_NAME_SIZE 8 @@ -49520,7 +69744,7 @@ /** * struct bcm2835_dmadev - BCM2835 DMA controller -@@ -48,6 +56,7 @@ struct bcm2835_dmadev { +@@ -48,6 +57,7 @@ struct bcm2835_dmadev { struct dma_device ddev; void __iomem *base; dma_addr_t zero_page; @@ -49528,7 +69752,7 @@ }; struct bcm2835_dma_cb { -@@ -60,6 +69,17 @@ struct bcm2835_dma_cb { +@@ -60,6 +70,17 @@ struct bcm2835_dma_cb { uint32_t pad2; }; @@ -49546,18 +69770,22 @@ struct bcm2835_cb_entry { struct bcm2835_dma_cb *cb; dma_addr_t paddr; -@@ -80,6 +100,7 @@ struct bcm2835_chan { +@@ -80,6 +101,8 @@ struct bcm2835_chan { unsigned int irq_flags; bool is_lite_channel; + bool is_40bit_channel; ++ bool is_2712; }; struct bcm2835_desc { -@@ -137,10 +158,30 @@ struct bcm2835_desc { +@@ -136,11 +159,37 @@ struct bcm2835_desc { + #define BCM2835_DMA_S_WIDTH BIT(9) /* 128bit writes if set */ #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_BURST_LENGTH(x) ((x & 15) << 12) ++#define BCM2835_DMA_BURST_LENGTH(x) (((x) & 15) << 12) ++#define BCM2835_DMA_GET_BURST_LENGTH(x) (((x) >> 12) & 15) +#define BCM2835_DMA_CS_FLAGS(x) (x & (BCM2835_DMA_PRIORITY(15) | \ + BCM2835_DMA_PANIC_PRIORITY(15) | \ + BCM2835_DMA_WAIT_FOR_WRITES | \ @@ -49581,11 +69809,16 @@ +#define WIDE_DEST(x) ((x & BCM2835_DMA_WIDE_DEST) ? \ + BCM2835_DMA_D_WIDTH : 0) + ++/* A fake bit to request that the driver requires multi-beat burst */ ++#define BCM2835_DMA_BURST BIT(30) ++#define BURST_LENGTH(x) ((x & BCM2835_DMA_BURST) ? \ ++ BCM2835_DMA_BURST_LENGTH(3) : 0) ++ + /* debug register bits */ #define BCM2835_DMA_DEBUG_LAST_NOT_SET_ERR BIT(0) #define BCM2835_DMA_DEBUG_FIFO_ERR BIT(1) -@@ -165,13 +206,120 @@ struct bcm2835_desc { +@@ -165,13 +214,130 @@ struct bcm2835_desc { #define BCM2835_DMA_DATA_TYPE_S128 16 /* Valid only for channels 0 - 14, 15 has its own base address */ @@ -49619,13 +69852,17 @@ +#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 */ ++// we always want to run in supervisor mode ++#define BCM2711_DMA40_PROT (BIT(8)|BIT(9)) +#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_TRANSACTIONS BIT(25) +#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 | \ @@ -49668,7 +69905,7 @@ +/* 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_BURST_LEN(x) (((x) & 15) << 8) +#define BCM2711_DMA40_INC BIT(12) +#define BCM2711_DMA40_SIZE_32 (0 << 13) +#define BCM2711_DMA40_SIZE_64 (1 << 13) @@ -49704,10 +69941,16 @@ + .dma_mask = DMA_BIT_MASK(36), +}; + ++static const struct bcm2835_dma_cfg_data bcm2712_dma_cfg = { ++ .chan_40bit_mask = BIT(6) | BIT(7) | BIT(8) | BIT(9) | ++ BIT(10) | BIT(11), ++ .dma_mask = DMA_BIT_MASK(40), ++}; ++ static inline size_t bcm2835_dma_max_frame_length(struct bcm2835_chan *c) { /* lite and normal channels have different max frame length */ -@@ -201,6 +349,32 @@ static inline struct bcm2835_desc *to_bcm2835_dma_desc( +@@ -201,6 +367,36 @@ static inline struct bcm2835_desc *to_bcm2835_dma_desc( return container_of(t, struct bcm2835_desc, vd.tx); } @@ -49723,15 +69966,19 @@ + +static inline uint32_t to_bcm2711_srci(uint32_t info) +{ -+ return ((info & BCM2835_DMA_S_INC) ? BCM2711_DMA40_INC : 0); ++ return ((info & BCM2835_DMA_S_INC) ? BCM2711_DMA40_INC : 0) | ++ ((info & BCM2835_DMA_S_WIDTH) ? BCM2711_DMA40_SIZE_128 : 0) | ++ BCM2711_DMA40_BURST_LEN(BCM2835_DMA_GET_BURST_LENGTH(info)); +} + +static inline uint32_t to_bcm2711_dsti(uint32_t info) +{ -+ return ((info & BCM2835_DMA_D_INC) ? BCM2711_DMA40_INC : 0); ++ return ((info & BCM2835_DMA_D_INC) ? BCM2711_DMA40_INC : 0) | ++ ((info & BCM2835_DMA_D_WIDTH) ? BCM2711_DMA40_SIZE_128 : 0) | ++ BCM2711_DMA40_BURST_LEN(BCM2835_DMA_GET_BURST_LENGTH(info)); +} + -+static inline uint32_t to_bcm2711_cbaddr(dma_addr_t addr) ++static inline uint32_t to_40bit_cbaddr(dma_addr_t addr) +{ + BUG_ON(addr & 0x1f); + return (addr >> 5); @@ -49740,7 +69987,7 @@ static void bcm2835_dma_free_cb_chain(struct bcm2835_desc *desc) { size_t i; -@@ -219,45 +393,53 @@ static void bcm2835_dma_desc_free(struct virt_dma_desc *vd) +@@ -219,45 +415,53 @@ static void bcm2835_dma_desc_free(struct virt_dma_desc *vd) } static void bcm2835_dma_create_cb_set_length( @@ -49799,13 +70046,13 @@ - /* 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; + if (c->is_40bit_channel) { + struct bcm2711_dma40_scb *scb = + (struct bcm2711_dma40_scb *)control_block; +- /* reset total_length for next period */ +- *total_len = 0; +- - /* add extrainfo bits in info */ - control_block->info |= finalextrainfo; + scb->len = cb_len; @@ -49819,7 +70066,7 @@ } static inline size_t bcm2835_dma_count_frames_for_sg( -@@ -280,7 +462,7 @@ static inline size_t bcm2835_dma_count_frames_for_sg( +@@ -280,7 +484,7 @@ static inline size_t bcm2835_dma_count_frames_for_sg( /** * bcm2835_dma_create_cb_chain - create a control block and fills data in * @@ -49828,7 +70075,7 @@ * @direction: the direction in which we transfer * @cyclic: it is a cyclic transfer * @info: the default info bits to apply per controlblock -@@ -298,12 +480,11 @@ static inline size_t bcm2835_dma_count_frames_for_sg( +@@ -298,12 +502,11 @@ static inline size_t bcm2835_dma_count_frames_for_sg( * @gfp: the GFP flag to use for allocation */ static struct bcm2835_desc *bcm2835_dma_create_cb_chain( @@ -49842,7 +70089,7 @@ size_t len = buf_len, total_len; size_t frame; struct bcm2835_desc *d; -@@ -335,11 +516,23 @@ static struct bcm2835_desc *bcm2835_dma_create_cb_chain( +@@ -335,11 +538,27 @@ static struct bcm2835_desc *bcm2835_dma_create_cb_chain( /* fill in the control block */ control_block = cb_entry->cb; @@ -49864,28 +70111,57 @@ + control_block->info = info; + control_block->src = src; + control_block->dst = dst; -+ control_block->stride = 0; ++ if (c->is_2712) ++ control_block->stride = (upper_32_bits(dst) << 8) | ++ upper_32_bits(src); ++ else ++ control_block->stride = 0; + control_block->next = 0; + } + /* set up length in control_block if requested */ if (buf_len) { /* calculate length honoring period_length */ -@@ -353,7 +546,11 @@ static struct bcm2835_desc *bcm2835_dma_create_cb_chain( +@@ -349,25 +568,52 @@ static struct bcm2835_desc *bcm2835_dma_create_cb_chain( + cyclic ? finalextrainfo : 0); + + /* calculate new remaining length */ +- len -= control_block->length; ++ if (c->is_40bit_channel) ++ len -= ((struct bcm2711_dma40_scb *)control_block)->len; ++ else ++ len -= control_block->length; } /* link this the last controlblock */ - if (frame) +- d->cb_listframe - 1.cb->next = cb_entry->paddr; + if (frame && c->is_40bit_channel) + ((struct bcm2711_dma40_scb *) + d->cb_listframe - 1.cb)->next_cb = -+ to_bcm2711_cbaddr(cb_entry->paddr); ++ to_40bit_cbaddr(cb_entry->paddr); + if (frame && !c->is_40bit_channel) - d->cb_listframe - 1.cb->next = cb_entry->paddr; ++ d->cb_listframe - 1.cb->next = c->is_2712 ? ++ to_40bit_cbaddr(cb_entry->paddr) : cb_entry->paddr; /* update src and dst and length */ -@@ -363,11 +560,21 @@ static struct bcm2835_desc *bcm2835_dma_create_cb_chain( - dst += control_block->length; +- if (src && (info & BCM2835_DMA_S_INC)) +- src += control_block->length; +- if (dst && (info & BCM2835_DMA_D_INC)) +- dst += control_block->length; ++ if (src && (info & BCM2835_DMA_S_INC)) { ++ if (c->is_40bit_channel) ++ src += ((struct bcm2711_dma40_scb *)control_block)->len; ++ else ++ src += control_block->length; ++ } ++ ++ if (dst && (info & BCM2835_DMA_D_INC)) { ++ if (c->is_40bit_channel) ++ dst += ((struct bcm2711_dma40_scb *)control_block)->len; ++ else ++ dst += control_block->length; ++ } /* Length of total transfer */ - d->size += control_block->length; @@ -49908,7 +70184,7 @@ /* detect a size missmatch */ if (buf_len && (d->size != buf_len)) -@@ -381,13 +588,12 @@ static struct bcm2835_desc *bcm2835_dma_create_cb_chain( +@@ -381,13 +627,12 @@ static struct bcm2835_desc *bcm2835_dma_create_cb_chain( } static void bcm2835_dma_fill_cb_chain_with_sg( @@ -49923,7 +70199,7 @@ size_t len, max_len; unsigned int i; dma_addr_t addr; -@@ -395,14 +601,35 @@ static void bcm2835_dma_fill_cb_chain_with_sg( +@@ -395,14 +640,35 @@ static void bcm2835_dma_fill_cb_chain_with_sg( max_len = bcm2835_dma_max_frame_length(c); for_each_sg(sgl, sgent, sg_len, i) { @@ -49967,88 +70243,232 @@ } } } -@@ -411,6 +638,10 @@ static void bcm2835_dma_abort(struct bcm2835_chan *c) +@@ -410,29 +676,74 @@ static void bcm2835_dma_fill_cb_chain_with_sg( + static void bcm2835_dma_abort(struct bcm2835_chan *c) { void __iomem *chan_base = c->chan_base; - long int timeout = 10000; -+ u32 wait_mask = BCM2835_DMA_WAITING_FOR_WRITES; +- long int timeout = 10000; ++ long timeout = 100; + +- /* +- * A zero control block address means the channel is idle. +- * (The ACTIVE flag in the CS register is not a reliable indicator.) +- */ +- if (!readl(chan_base + BCM2835_DMA_ADDR)) +- return; ++ if (c->is_40bit_channel) { ++ /* ++ * A zero control block address means the channel is idle. ++ * (The ACTIVE flag in the CS register is not a reliable indicator.) ++ */ ++ if (!readl(chan_base + BCM2711_DMA40_CB)) ++ return; + -+ if (c->is_40bit_channel) -+ wait_mask = BCM2711_DMA40_WAITING_FOR_WRITES; ++ /* Pause the current DMA */ ++ writel(readl(chan_base + BCM2711_DMA40_CS) & ~BCM2711_DMA40_ACTIVE, ++ chan_base + BCM2711_DMA40_CS); ++ ++ /* wait for outstanding transactions to complete */ ++ while ((readl(chan_base + BCM2711_DMA40_CS) & BCM2711_DMA40_TRANSACTIONS) && ++ --timeout) ++ cpu_relax(); ++ ++ /* Peripheral might be stuck and fail to complete */ ++ if (!timeout) ++ dev_err(c->vc.chan.device->dev, ++ "failed to complete pause on dma %d (CS:%08x)\n", c->ch, ++ readl(chan_base + BCM2711_DMA40_CS)); ++ ++ /* Set CS back to default state */ ++ writel(BCM2711_DMA40_PROT, chan_base + BCM2711_DMA40_CS); ++ ++ /* Reset the DMA */ ++ writel(readl(chan_base + BCM2711_DMA40_DEBUG) | BCM2711_DMA40_DEBUG_RESET, ++ chan_base + BCM2711_DMA40_DEBUG); ++ } else { ++ /* ++ * A zero control block address means the channel is idle. ++ * (The ACTIVE flag in the CS register is not a reliable indicator.) ++ */ ++ if (!readl(chan_base + BCM2835_DMA_ADDR)) ++ return; - /* - * A zero control block address means the channel is idle. -@@ -423,8 +654,7 @@ static void bcm2835_dma_abort(struct bcm2835_chan *c) - writel(0, chan_base + BCM2835_DMA_CS); +- /* Write 0 to the active bit - Pause the DMA */ +- writel(0, chan_base + BCM2835_DMA_CS); ++ /* We need to clear the next DMA block pending */ ++ writel(0, chan_base + BCM2835_DMA_NEXTCB); - /* Wait for any current AXI transfer to complete */ +- /* 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(); +- cpu_relax(); ++ /* Abort the DMA, which needs to be enabled to complete */ ++ writel(readl(chan_base + BCM2835_DMA_CS) | BCM2835_DMA_ABORT | BCM2835_DMA_ACTIVE, ++ chan_base + BCM2835_DMA_CS); ++ ++ /* wait for DMA to be aborted */ ++ while ((readl(chan_base + BCM2835_DMA_CS) & BCM2835_DMA_ABORT) && --timeout) ++ cpu_relax(); + +- /* Peripheral might be stuck and fail to signal AXI write responses */ +- if (!timeout) +- dev_err(c->vc.chan.device->dev, +- "failed to complete outstanding writes\n"); ++ /* Write 0 to the active bit - Pause the DMA */ ++ writel(readl(chan_base + BCM2835_DMA_CS) & ~BCM2835_DMA_ACTIVE, ++ chan_base + BCM2835_DMA_CS); + +- writel(BCM2835_DMA_RESET, chan_base + BCM2835_DMA_CS); ++ /* ++ * Peripheral might be stuck and fail to complete ++ * This is expected when dreqs are enabled but not asserted ++ * so only report error in non dreq case ++ */ ++ if (!timeout && !(readl(chan_base + BCM2835_DMA_TI) & ++ (BCM2835_DMA_S_DREQ | BCM2835_DMA_D_DREQ))) ++ dev_err(c->vc.chan.device->dev, ++ "failed to complete pause on dma %d (CS:%08x)\n", c->ch, ++ readl(chan_base + BCM2835_DMA_CS)); ++ ++ /* Set CS back to default state and reset the DMA */ ++ writel(BCM2835_DMA_RESET, chan_base + BCM2835_DMA_CS); ++ } + } - /* Peripheral might be stuck and fail to signal AXI write responses */ -@@ -449,8 +679,16 @@ static void bcm2835_dma_start_desc(struct bcm2835_chan *c) + static void bcm2835_dma_start_desc(struct bcm2835_chan *c) +@@ -449,8 +760,19 @@ static void bcm2835_dma_start_desc(struct bcm2835_chan *c) c->desc = d = to_bcm2835_dma_desc(&vd->tx); - writel(d->cb_list0.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_list0.paddr), ++ writel(to_40bit_cbaddr(d->cb_list0.paddr), + c->chan_base + BCM2711_DMA40_CB); -+ writel(BCM2711_DMA40_ACTIVE | BCM2711_DMA40_CS_FLAGS(c->dreq), ++ writel(BCM2711_DMA40_ACTIVE | BCM2711_DMA40_PROT | BCM2711_DMA40_CS_FLAGS(c->dreq), + c->chan_base + BCM2711_DMA40_CS); + } else { -+ writel(d->cb_list0.paddr, c->chan_base + BCM2835_DMA_ADDR); ++ writel(BIT(31), c->chan_base + BCM2835_DMA_CS); ++ ++ writel(c->is_2712 ? to_40bit_cbaddr(d->cb_list0.paddr) : d->cb_list0.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) -@@ -477,7 +715,7 @@ static irqreturn_t bcm2835_dma_callback(int irq, void *data) +@@ -477,8 +799,13 @@ static irqreturn_t bcm2835_dma_callback(int irq, void *data) * 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); +- c->chan_base + BCM2835_DMA_CS); ++ if (c->is_40bit_channel) ++ writel(BCM2835_DMA_INT | BCM2711_DMA40_ACTIVE | BCM2711_DMA40_PROT | ++ BCM2711_DMA40_CS_FLAGS(c->dreq), ++ c->chan_base + BCM2711_DMA40_CS); ++ else ++ writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq), ++ c->chan_base + BCM2835_DMA_CS); d = c->desc; -@@ -580,9 +818,17 @@ static enum dma_status bcm2835_dma_tx_status(struct dma_chan *chan, + +@@ -540,20 +867,39 @@ static size_t bcm2835_dma_desc_size_pos(struct bcm2835_desc *d, dma_addr_t addr) + unsigned int i; + size_t size; + +- for (size = i = 0; i < d->frames; i++) { +- struct bcm2835_dma_cb *control_block = d->cb_listi.cb; +- size_t this_size = control_block->length; +- dma_addr_t dma; ++ if (d->c->is_40bit_channel) { ++ for (size = i = 0; i < d->frames; i++) { ++ struct bcm2711_dma40_scb *control_block = ++ (struct bcm2711_dma40_scb *)d->cb_listi.cb; ++ size_t this_size = control_block->len; ++ dma_addr_t dma; + +- if (d->dir == DMA_DEV_TO_MEM) +- dma = control_block->dst; +- else +- dma = control_block->src; ++ if (d->dir == DMA_DEV_TO_MEM) ++ dma = control_block->dst; ++ else ++ dma = control_block->src; + +- if (size) +- size += this_size; +- else if (addr >= dma && addr < dma + this_size) +- size += dma + this_size - addr; ++ if (size) ++ size += this_size; ++ else if (addr >= dma && addr < dma + this_size) ++ size += dma + this_size - addr; ++ } ++ } else { ++ for (size = i = 0; i < d->frames; i++) { ++ struct bcm2835_dma_cb *control_block = d->cb_listi.cb; ++ size_t this_size = control_block->length; ++ dma_addr_t dma; ++ ++ if (d->dir == DMA_DEV_TO_MEM) ++ dma = control_block->dst; ++ else ++ dma = control_block->src; ++ ++ if (size) ++ size += this_size; ++ else if (addr >= dma && addr < dma + this_size) ++ size += dma + this_size - addr; ++ } + } + + return size; +@@ -580,12 +926,25 @@ static enum dma_status bcm2835_dma_tx_status(struct dma_chan *chan, 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) ++ if (d->dir == DMA_MEM_TO_DEV && c->is_40bit_channel) { ++ u64 lo_bits, hi_bits; ++ ++ lo_bits = readl(c->chan_base + BCM2711_DMA40_SRC); ++ hi_bits = readl(c->chan_base + BCM2711_DMA40_SRCI) & 0xff; ++ pos = (hi_bits << 32) | lo_bits; ++ } 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) ++ } else if (d->dir == DMA_DEV_TO_MEM && c->is_40bit_channel) { ++ u64 lo_bits, hi_bits; ++ ++ lo_bits = readl(c->chan_base + BCM2711_DMA40_DEST); ++ hi_bits = readl(c->chan_base + BCM2711_DMA40_DESTI) & 0xff; ++ pos = (hi_bits << 32) | lo_bits; ++ } else if (d->dir == DMA_DEV_TO_MEM && !c->is_40bit_channel) { pos = readl(c->chan_base + BCM2835_DMA_DEST_AD); - else +- else ++ } else { pos = 0; -@@ -615,8 +861,9 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_memcpy( ++ } + + txstate->residue = bcm2835_dma_desc_size_pos(d, pos); + } else { +@@ -615,8 +974,10 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_memcpy( { 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 info = BCM2835_DMA_D_INC | BCM2835_DMA_S_INC | ++ WAIT_RESP(c->dreq) | WIDE_SOURCE(c->dreq) | ++ WIDE_DEST(c->dreq) | BURST_LENGTH(c->dreq); + u32 extra = BCM2835_DMA_INT_EN; size_t max_len = bcm2835_dma_max_frame_length(c); size_t frames; -@@ -628,7 +875,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_memcpy( +@@ -628,7 +989,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_memcpy( frames = bcm2835_dma_frames_for_length(len, max_len); /* allocate the CB chain - this also fills in the pointers */ @@ -50057,39 +70477,32 @@ info, extra, frames, src, dst, len, 0, GFP_KERNEL); if (!d) -@@ -646,7 +893,8 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( +@@ -646,7 +1007,8 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( 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 info = WAIT_RESP(c->dreq) | WIDE_SOURCE(c->dreq) | ++ WIDE_DEST(c->dreq) | BURST_LENGTH(c->dreq); u32 extra = BCM2835_DMA_INT_EN; size_t frames; -@@ -663,11 +911,21 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( +@@ -662,12 +1024,12 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( + if (direction == DMA_DEV_TO_MEM) { 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; +- src = c->cfg.src_addr; ++ src = phys_to_dma(chan->device->dev, c->cfg.src_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; +- dst = c->cfg.dst_addr; ++ dst = phys_to_dma(chan->device->dev, c->cfg.dst_addr); info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC; } -@@ -675,7 +933,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( +@@ -675,7 +1037,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( frames = bcm2835_dma_count_frames_for_sg(c, sgl, sg_len); /* allocate the CB chain */ @@ -50098,7 +70511,7 @@ info, extra, frames, src, dst, 0, 0, GFP_NOWAIT); -@@ -683,7 +941,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( +@@ -683,7 +1045,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( return NULL; /* fill in frames with scatterlist pointers */ @@ -50107,33 +70520,33 @@ sgl, sg_len); return vchan_tx_prep(&c->vc, &d->vd, flags); -@@ -698,7 +956,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( +@@ -698,7 +1060,8 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( 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 info = WAIT_RESP(c->dreq) | WIDE_SOURCE(c->dreq) | ++ WIDE_DEST(c->dreq) | BURST_LENGTH(c->dreq); u32 extra = 0; size_t max_len = bcm2835_dma_max_frame_length(c); size_t frames; -@@ -737,12 +995,16 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( +@@ -736,13 +1099,13 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( + if (direction == DMA_DEV_TO_MEM) { 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; +- src = c->cfg.src_addr; ++ src = phys_to_dma(chan->device->dev, c->cfg.src_addr); 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; +- dst = c->cfg.dst_addr; ++ dst = phys_to_dma(chan->device->dev, c->cfg.dst_addr); src = buf_addr; info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC; -@@ -762,7 +1024,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( +@@ -762,7 +1125,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( * note that we need to use GFP_NOWAIT, as the ALSA i2s dmaengine * implementation calls prep_dma_cyclic with interrupts disabled. */ @@ -50142,7 +70555,7 @@ info, extra, frames, src, dst, buf_len, period_len, GFP_NOWAIT); -@@ -770,7 +1032,12 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( +@@ -770,7 +1133,13 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( return NULL; /* wrap around into a loop */ @@ -50150,13 +70563,14 @@ + if (c->is_40bit_channel) + ((struct bcm2711_dma40_scb *) + d->cb_listframes - 1.cb)->next_cb = -+ to_bcm2711_cbaddr(d->cb_list0.paddr); ++ to_40bit_cbaddr(d->cb_list0.paddr); + else -+ d->cb_listd->frames - 1.cb->next = d->cb_list0.paddr; ++ d->cb_listd->frames - 1.cb->next = c->is_2712 ? ++ to_40bit_cbaddr(d->cb_list0.paddr) : d->cb_list0.paddr; return vchan_tx_prep(&c->vc, &d->vd, flags); } -@@ -831,9 +1098,11 @@ static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, +@@ -831,10 +1200,14 @@ static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, c->irq_number = irq; c->irq_flags = irq_flags; @@ -50169,9 +70583,12 @@ + else if (readl(c->chan_base + BCM2835_DMA_DEBUG) & + BCM2835_DMA_DEBUG_LITE) c->is_lite_channel = true; ++ if (d->cfg_data->dma_mask == DMA_BIT_MASK(40)) ++ c->is_2712 = true; return 0; -@@ -853,8 +1122,58 @@ static void bcm2835_dma_free(struct bcm2835_dmadev *od) + } +@@ -853,8 +1226,59 @@ static void bcm2835_dma_free(struct bcm2835_dmadev *od) DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); } @@ -50210,15 +70627,15 @@ + 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, ++ writel(to_40bit_cbaddr(memcpy_scb_dma), memcpy_chan + BCM2711_DMA40_CB); ++ writel(BCM2711_DMA40_MEMCPY_FLAGS | BCM2711_DMA40_ACTIVE | BCM2711_DMA40_PROT, + memcpy_chan + BCM2711_DMA40_CS); + + /* Poll for completion */ + while (!(readl(memcpy_chan + BCM2711_DMA40_CS) & BCM2711_DMA40_END)) + cpu_relax(); + -+ writel(BCM2711_DMA40_END, memcpy_chan + BCM2711_DMA40_CS); ++ writel(BCM2711_DMA40_END | BCM2711_DMA40_PROT, memcpy_chan + BCM2711_DMA40_CS); + + spin_unlock_irqrestore(&memcpy_lock, flags); +} @@ -50228,19 +70645,22 @@ - { .compatible = "brcm,bcm2835-dma", }, + { .compatible = "brcm,bcm2835-dma", .data = &bcm2835_dma_cfg }, + { .compatible = "brcm,bcm2711-dma", .data = &bcm2711_dma_cfg }, ++ { .compatible = "brcm,bcm2712-dma", .data = &bcm2712_dma_cfg }, {}, }; MODULE_DEVICE_TABLE(of, bcm2835_dma_of_match); -@@ -877,6 +1196,8 @@ static struct dma_chan *bcm2835_dma_xlate(struct of_phandle_args *spec, +@@ -877,7 +1301,10 @@ static struct dma_chan *bcm2835_dma_xlate(struct of_phandle_args *spec, 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; ++ struct resource *res; void __iomem *base; -@@ -886,11 +1207,20 @@ static int bcm2835_dma_probe(struct platform_device *pdev) + int rc; + int i, j; +@@ -885,11 +1312,20 @@ static int bcm2835_dma_probe(struct platform_device *pdev) int irq_flags; uint32_t chans_available; char chan_nameBCM2835_DMA_CHAN_NAME_SIZE; @@ -50262,7 +70682,12 @@ if (rc) { dev_err(&pdev->dev, "Unable to set DMA mask\n"); return rc; -@@ -907,6 +1237,13 @@ static int bcm2835_dma_probe(struct platform_device *pdev) +@@ -901,10 +1337,17 @@ static int bcm2835_dma_probe(struct platform_device *pdev) + + dma_set_max_seg_size(&pdev->dev, 0x3FFFFFFF); + +- base = devm_platform_ioremap_resource(pdev, 0); ++ base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) return PTR_ERR(base); @@ -50276,7 +70701,7 @@ od->base = base; dma_cap_set(DMA_SLAVE, od->ddev.cap_mask); -@@ -942,6 +1279,14 @@ static int bcm2835_dma_probe(struct platform_device *pdev) +@@ -940,6 +1383,14 @@ static int bcm2835_dma_probe(struct platform_device *pdev) return -ENOMEM; } @@ -50291,7 +70716,7 @@ /* Request DMA channel mask from device tree */ if (of_property_read_u32(pdev->dev.of_node, "brcm,dma-channel-mask", -@@ -951,8 +1296,36 @@ static int bcm2835_dma_probe(struct platform_device *pdev) +@@ -949,8 +1400,36 @@ static int bcm2835_dma_probe(struct platform_device *pdev) goto err_no_dma; } @@ -50329,7 +70754,7 @@ /* skip masked out channels */ if (!(chans_available & (1 << i))) { irqi = -1; -@@ -975,13 +1348,17 @@ static int bcm2835_dma_probe(struct platform_device *pdev) +@@ -973,13 +1452,17 @@ static int bcm2835_dma_probe(struct platform_device *pdev) irqi = platform_get_irq(pdev, i < 11 ? i : 11); } @@ -50348,7 +70773,7 @@ irq_flags = 0; for (j = 0; j <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; j++) if ((i != j) && (irqj == irqi)) { -@@ -993,9 +1370,10 @@ static int bcm2835_dma_probe(struct platform_device *pdev) +@@ -991,9 +1474,10 @@ static int bcm2835_dma_probe(struct platform_device *pdev) rc = bcm2835_dma_chan_init(od, i, irqi, irq_flags); if (rc) goto err_no_dma; @@ -50360,7 +70785,7 @@ /* Device-tree DMA controller registration */ rc = of_dma_controller_register(pdev->dev.of_node, -@@ -1025,7 +1403,15 @@ static int bcm2835_dma_remove(struct platform_device *pdev) +@@ -1023,7 +1507,15 @@ static int bcm2835_dma_remove(struct platform_device *pdev) { struct bcm2835_dmadev *od = platform_get_drvdata(pdev); @@ -50376,7 +70801,7 @@ bcm2835_dma_free(od); return 0; -@@ -1040,7 +1426,22 @@ static struct platform_driver bcm2835_dma_driver = { +@@ -1038,7 +1530,22 @@ static struct platform_driver bcm2835_dma_driver = { }, }; @@ -50400,25 +70825,337 @@ MODULE_ALIAS("platform:bcm2835-dma"); MODULE_DESCRIPTION("BCM2835 DMA engine driver"); +diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +index dd02f84e404d..5874620bf7ed 100644 +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +@@ -12,6 +12,7 @@ + #include <linux/device.h> + #include <linux/dmaengine.h> + #include <linux/dmapool.h> ++#include <linux/dma-direct.h> + #include <linux/dma-mapping.h> + #include <linux/err.h> + #include <linux/interrupt.h> +@@ -84,6 +85,17 @@ axi_chan_iowrite64(struct axi_dma_chan *chan, u32 reg, u64 val) + iowrite32(upper_32_bits(val), chan->chan_regs + reg + 4); + } + ++static inline u64 ++axi_chan_ioread64(struct axi_dma_chan *chan, u32 reg) ++{ ++ /* ++ * We split one 64 bit read into two 32 bit reads as some HW doesn't ++ * support 64 bit access. ++ */ ++ return ((u64)ioread32(chan->chan_regs + reg + 4) << 32) + ++ ioread32(chan->chan_regs + reg); ++} ++ + static inline void axi_chan_config_write(struct axi_dma_chan *chan, + struct axi_dma_chan_config *config) + { +@@ -220,7 +232,18 @@ static void axi_dma_hw_init(struct axi_dma_chip *chip) + { + int ret; + u32 i; +- ++ int retries = 1000; ++ ++ axi_dma_iowrite32(chip, DMAC_RESET, 1); ++ while (axi_dma_ioread32(chip, DMAC_RESET)) { ++ retries--; ++ if (!retries) { ++ dev_err(chip->dev, "%s: DMAC failed to reset\n", ++ __func__); ++ return; ++ } ++ cpu_relax(); ++ } + for (i = 0; i < chip->dw->hdata->nr_channels; i++) { + axi_chan_irq_disable(&chip->dw->chani, DWAXIDMAC_IRQ_ALL); + axi_chan_disable(&chip->dw->chani); +@@ -282,7 +305,7 @@ static struct axi_dma_lli *axi_desc_get(struct axi_dma_chan *chan, + static void axi_desc_put(struct axi_dma_desc *desc) + { + struct axi_dma_chan *chan = desc->chan; +- int count = atomic_read(&chan->descs_allocated); ++ u32 count = desc->hw_desc_count; + struct axi_dma_hw_desc *hw_desc; + int descs_put; + +@@ -304,6 +327,48 @@ static void vchan_desc_put(struct virt_dma_desc *vdesc) + axi_desc_put(vd_to_axi_desc(vdesc)); + } + ++static u32 axi_dma_desc_src_pos(struct axi_dma_desc *desc, dma_addr_t addr) ++{ ++ unsigned int idx = 0; ++ u32 pos = 0; ++ ++ while (pos < desc->length) { ++ struct axi_dma_hw_desc *hw_desc = &desc->hw_descidx++; ++ u32 len = hw_desc->len; ++ dma_addr_t start = le64_to_cpu(hw_desc->lli->sar); ++ ++ if (addr >= start && addr <= (start + len)) { ++ pos += addr - start; ++ break; ++ } ++ ++ pos += len; ++ } ++ ++ return pos; ++} ++ ++static u32 axi_dma_desc_dst_pos(struct axi_dma_desc *desc, dma_addr_t addr) ++{ ++ unsigned int idx = 0; ++ u32 pos = 0; ++ ++ while (pos < desc->length) { ++ struct axi_dma_hw_desc *hw_desc = &desc->hw_descidx++; ++ u32 len = hw_desc->len; ++ dma_addr_t start = le64_to_cpu(hw_desc->lli->dar); ++ ++ if (addr >= start && addr <= (start + len)) { ++ pos += addr - start; ++ break; ++ } ++ ++ pos += len; ++ } ++ ++ return pos; ++} ++ + static enum dma_status + dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie, + struct dma_tx_state *txstate) +@@ -313,10 +378,7 @@ dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie, + enum dma_status status; + u32 completed_length; + unsigned long flags; +- u32 completed_blocks; + size_t bytes = 0; +- u32 length; +- u32 len; + + status = dma_cookie_status(dchan, cookie, txstate); + if (status == DMA_COMPLETE || !txstate) +@@ -325,16 +387,31 @@ dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie, + spin_lock_irqsave(&chan->vc.lock, flags); + + vdesc = vchan_find_desc(&chan->vc, cookie); +- if (vdesc) { +- length = vd_to_axi_desc(vdesc)->length; +- completed_blocks = vd_to_axi_desc(vdesc)->completed_blocks; +- len = vd_to_axi_desc(vdesc)->hw_desc0.len; +- completed_length = completed_blocks * len; +- bytes = length - completed_length; ++ if (vdesc && vdesc == vchan_next_desc(&chan->vc)) { ++ /* This descriptor is in-progress */ ++ struct axi_dma_desc *desc = vd_to_axi_desc(vdesc); ++ dma_addr_t addr; ++ ++ if (chan->direction == DMA_MEM_TO_DEV) { ++ addr = axi_chan_ioread64(chan, CH_SAR); ++ completed_length = axi_dma_desc_src_pos(desc, addr); ++ } else if (chan->direction == DMA_DEV_TO_MEM) { ++ addr = axi_chan_ioread64(chan, CH_DAR); ++ completed_length = axi_dma_desc_dst_pos(desc, addr); ++ } else { ++ completed_length = 0; ++ } ++ bytes = desc->length - completed_length; ++ } else if (vdesc) { ++ /* Still in the queue so not started */ ++ bytes = vd_to_axi_desc(vdesc)->length; + } + +- spin_unlock_irqrestore(&chan->vc.lock, flags); ++ if (chan->is_paused && status == DMA_IN_PROGRESS) ++ status = DMA_PAUSED; ++ + dma_set_residue(txstate, bytes); ++ spin_unlock_irqrestore(&chan->vc.lock, flags); + + return status; + } +@@ -388,8 +465,6 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan, + return; + } + +- axi_dma_enable(chan->chip); +- + config.dst_multblk_type = DWAXIDMAC_MBLK_TYPE_LL; + config.src_multblk_type = DWAXIDMAC_MBLK_TYPE_LL; + config.tt_fc = DWAXIDMAC_TT_FC_MEM_TO_MEM_DMAC; +@@ -522,7 +597,7 @@ static void dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set) + unsigned long reg_value, val; + + if (!chip->apb_regs) { +- dev_err(chip->dev, "apb_regs not initialized\n"); ++ dev_dbg(chip->dev, "apb_regs not initialized\n"); + return; + } + +@@ -626,18 +701,25 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan, + switch (chan->direction) { + case DMA_MEM_TO_DEV: + reg_width = __ffs(chan->config.dst_addr_width); +- device_addr = chan->config.dst_addr; ++ device_addr = phys_to_dma(chan->chip->dev, chan->config.dst_addr); + ctllo = reg_width << CH_CTL_L_DST_WIDTH_POS | + mem_width << CH_CTL_L_SRC_WIDTH_POS | ++ DWAXIDMAC_BURST_TRANS_LEN_1 << CH_CTL_L_DST_MSIZE_POS | ++ DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS | + DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_DST_INC_POS | + DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS; + block_ts = len >> mem_width; + break; + case DMA_DEV_TO_MEM: + reg_width = __ffs(chan->config.src_addr_width); +- device_addr = chan->config.src_addr; ++ /* Prevent partial access units getting lost */ ++ if (mem_width > reg_width) ++ mem_width = reg_width; ++ device_addr = phys_to_dma(chan->chip->dev, chan->config.src_addr); + ctllo = reg_width << CH_CTL_L_SRC_WIDTH_POS | + mem_width << CH_CTL_L_DST_WIDTH_POS | ++ DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS | ++ DWAXIDMAC_BURST_TRANS_LEN_1 << CH_CTL_L_SRC_MSIZE_POS | + DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS | + DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_SRC_INC_POS; + block_ts = len >> reg_width; +@@ -673,9 +755,6 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan, + } + + hw_desc->lli->block_ts_lo = cpu_to_le32(block_ts - 1); +- +- ctllo |= DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS | +- DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS; + hw_desc->lli->ctl_lo = cpu_to_le32(ctllo); + + set_desc_src_master(hw_desc); +@@ -770,6 +849,8 @@ dw_axi_dma_chan_prep_cyclic(struct dma_chan *dchan, dma_addr_t dma_addr, + src_addr += segment_len; + } + ++ desc->hw_desc_count = total_segments; ++ + llp = desc->hw_desc0.llp; + + /* Managed transfer list */ +@@ -849,6 +930,8 @@ dw_axi_dma_chan_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl, + } while (len >= segment_len); + } + ++ desc->hw_desc_count = loop; ++ + /* Set end-of-link to the last link descriptor of list */ + set_desc_last(&desc->hw_descnum_sgs - 1); + +@@ -956,6 +1039,8 @@ dma_chan_prep_dma_memcpy(struct dma_chan *dchan, dma_addr_t dst_adr, + num++; + } + ++ desc->hw_desc_count = num; ++ + /* Set end-of-link to the last link descriptor of list */ + set_desc_last(&desc->hw_descnum - 1); + /* Managed transfer list */ +@@ -1004,7 +1089,7 @@ static void axi_chan_dump_lli(struct axi_dma_chan *chan, + static void axi_chan_list_dump_lli(struct axi_dma_chan *chan, + struct axi_dma_desc *desc_head) + { +- int count = atomic_read(&chan->descs_allocated); ++ u32 count = desc_head->hw_desc_count; + int i; + + for (i = 0; i < count; i++) +@@ -1047,11 +1132,11 @@ static noinline void axi_chan_handle_err(struct axi_dma_chan *chan, u32 status) + + static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan) + { +- int count = atomic_read(&chan->descs_allocated); + struct axi_dma_hw_desc *hw_desc; + struct axi_dma_desc *desc; + struct virt_dma_desc *vd; + unsigned long flags; ++ u32 count; + u64 llp; + int i; + +@@ -1073,6 +1158,7 @@ static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan) + if (chan->cyclic) { + desc = vd_to_axi_desc(vd); + if (desc) { ++ count = desc->hw_desc_count; + llp = lo_hi_readq(chan->chan_regs + CH_LLP); + for (i = 0; i < count; i++) { + hw_desc = &desc->hw_desci; +@@ -1325,6 +1411,10 @@ static int parse_device_properties(struct axi_dma_chip *chip) + + chip->dw->hdata->nr_masters = tmp; + ++ ret = device_property_read_u32(dev, "snps,dma-targets", &tmp); ++ if (!ret && tmp > 16) ++ chip->dw->hdata->use_cfg2 = true; ++ + ret = device_property_read_u32(dev, "snps,data-width", &tmp); + if (ret) + return ret; +diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +index eb267cb24f67..47c3a4f0dac3 100644 +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +@@ -101,6 +101,7 @@ struct axi_dma_desc { + + struct virt_dma_desc vd; + struct axi_dma_chan *chan; ++ u32 hw_desc_count; + u32 completed_blocks; + u32 length; + u32 period_len; +diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c +index d9629ff87861..e2ffd734d5e8 100644 +--- a/drivers/firmware/psci/psci.c ++++ b/drivers/firmware/psci/psci.c +@@ -315,7 +315,14 @@ static int psci_sys_reset(struct notifier_block *nb, unsigned long action, + * reset_type30:0 = 0 (SYSTEM_WARM_RESET) + * cookie = 0 (ignored by the implementation) + */ +- invoke_psci_fn(PSCI_FN_NATIVE(1_1, SYSTEM_RESET2), 0, 0, 0); ++ // Allow extra arguments separated by spaces after ++ // the partition number. ++ unsigned long val; ++ u8 partition = 0; ++ ++ if (data && sscanf(data, "%lu", &val) == 1 && val < 63) ++ partition = val; ++ invoke_psci_fn(PSCI_FN_NATIVE(1_1, SYSTEM_RESET2), 0, partition, 0); + } else { + invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); + } diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c -index 1d965c1252ca..849e63bb426d 100644 +index f66efaa5196d..17abde1e7d55 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c -@@ -12,6 +12,7 @@ - #include <linux/module.h> +@@ -13,6 +13,7 @@ + #include <linux/of.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> -@@ -28,10 +29,13 @@ struct rpi_firmware { - struct mbox_chan *chan; /* The property channel. */ - struct completion c; +@@ -31,8 +32,11 @@ struct rpi_firmware { u32 enabled; -+ u32 get_throttled; struct kref consumers; ++ u32 get_throttled; }; +static struct platform_device *g_pdev; @@ -50426,7 +71163,7 @@ static DEFINE_MUTEX(transaction_lock); static void response_callback(struct mbox_client *cl, void *msg) -@@ -173,15 +177,92 @@ int rpi_firmware_property(struct rpi_firmware *fw, +@@ -174,15 +178,92 @@ int rpi_firmware_property(struct rpi_firmware *fw, kfree(data); @@ -50519,7 +71256,7 @@ int ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_FIRMWARE_REVISION, &packet, sizeof(packet)); -@@ -191,7 +272,35 @@ rpi_firmware_print_firmware_revision(struct rpi_firmware *fw) +@@ -192,7 +273,35 @@ rpi_firmware_print_firmware_revision(struct rpi_firmware *fw) /* This is not compatible with y2038 */ date_and_time = packet; @@ -50556,7 +71293,7 @@ } static void -@@ -206,6 +315,11 @@ rpi_register_hwmon_driver(struct device *dev, struct rpi_firmware *fw) +@@ -207,6 +316,11 @@ rpi_register_hwmon_driver(struct device *dev, struct rpi_firmware *fw) rpi_hwmon = platform_device_register_data(dev, "raspberrypi-hwmon", -1, NULL, 0); @@ -50568,7 +71305,7 @@ } static void rpi_register_clk_driver(struct device *dev) -@@ -272,8 +386,10 @@ static int rpi_firmware_probe(struct platform_device *pdev) +@@ -299,8 +413,10 @@ static int rpi_firmware_probe(struct platform_device *pdev) kref_init(&fw->consumers); platform_set_drvdata(pdev, fw); @@ -50579,15 +71316,15 @@ rpi_register_hwmon_driver(dev, fw); rpi_register_clk_driver(dev); -@@ -298,6 +414,7 @@ static int rpi_firmware_remove(struct platform_device *pdev) - rpi_hwmon = NULL; - platform_device_unregister(rpi_clk); +@@ -327,6 +443,7 @@ static int rpi_firmware_remove(struct platform_device *pdev) rpi_clk = NULL; -+ g_pdev = NULL; rpi_firmware_put(fw); ++ g_pdev = NULL; -@@ -352,7 +469,35 @@ static struct platform_driver rpi_firmware_driver = { + return 0; + } +@@ -407,7 +524,35 @@ static struct platform_driver rpi_firmware_driver = { .shutdown = rpi_firmware_shutdown, .remove = rpi_firmware_remove, }; @@ -50625,10 +71362,10 @@ MODULE_AUTHOR("Eric Anholt <eric@anholt.net>"); MODULE_DESCRIPTION("Raspberry Pi firmware driver"); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig -index c91355c89ec6..344405baf78e 100644 +index 3d186a39dd71..7d651afd4c20 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig -@@ -193,6 +193,12 @@ config GPIO_BCM_XGS_IPROC +@@ -207,10 +207,16 @@ config GPIO_BCM_XGS_IPROC help Say yes here to enable GPIO support for Broadcom XGS iProc SoCs. @@ -50641,9 +71378,14 @@ config GPIO_BRCMSTB tristate "BRCMSTB GPIO support" default y if (ARCH_BRCMSTB || BMIPS_GENERIC) -@@ -487,6 +493,14 @@ config GPIO_PMIC_EIC_SPRD +- depends on OF_GPIO && (ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST) ++ depends on OF_GPIO && (ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM2835 || COMPILE_TEST) + select GPIO_GENERIC + select IRQ_DOMAIN help - Say yes here to support Spreadtrum PMIC EIC device. +@@ -512,6 +518,14 @@ config GPIO_PL061 + help + Say yes here to support the PrimeCell PL061 GPIO device. +config GPIO_PWM + tristate "PWM chip GPIO" @@ -50656,9 +71398,9 @@ config GPIO_PXA bool "PXA GPIO support" depends on ARCH_PXA || ARCH_MMP || COMPILE_TEST -@@ -1178,6 +1192,15 @@ config HTC_EGPIO - several HTC phones. It provides basic support for input - pins, output pins, and irqs. +@@ -1301,6 +1315,15 @@ config GPIO_ELKHARTLAKE + To compile this driver as a module, choose M here: the module will + be called gpio-elkhartlake. +config GPIO_FSM + tristate "GPIO FSM support" @@ -50673,7 +71415,7 @@ tristate "Janz VMOD-TTL Digital IO Module" depends on MFD_JANZ_CMODIO diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile -index 1af147d8ad71..cb5a275692d5 100644 +index e44a700ec7d3..b24942a691bb 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_GPIO_ASPEED_SGPIO) += gpio-aspeed-sgpio.o @@ -50681,18 +71423,18 @@ 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_BD71815) += gpio-bd71815.o obj-$(CONFIG_GPIO_BD71828) += gpio-bd71828.o obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o -@@ -59,6 +60,7 @@ obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o +@@ -61,6 +62,7 @@ obj-$(CONFIG_GPIO_EN7523) += gpio-en7523.o + obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o 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_FTGPIO010) += gpio-ftgpio010.o + obj-$(CONFIG_GPIO_FXL6408) += gpio-fxl6408.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 -@@ -119,6 +121,7 @@ obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o +@@ -128,6 +130,7 @@ obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_PMIC_EIC_SPRD) += gpio-pmic-eic-sprd.o @@ -50702,7 +71444,7 @@ obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o diff --git a/drivers/gpio/gpio-bcm-virt.c b/drivers/gpio/gpio-bcm-virt.c new file mode 100644 -index 000000000000..55c40190e88a +index 000000000000..3b1ae097cd7b --- /dev/null +++ b/drivers/gpio/gpio-bcm-virt.c @@ -0,0 +1,214 @@ @@ -50719,7 +71461,7 @@ + */ + +#include <linux/err.h> -+#include <linux/gpio.h> ++#include <linux/gpio/driver.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> @@ -50787,19 +71529,20 @@ +{ + int err = 0; + struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; ++ struct device_node *np = dev_of_node(dev); + struct device_node *fw_node; + struct rpi_firmware *fw; + struct brcmvirt_gpio *ucb; + u32 gpiovirtbuf; + -+ fw_node = of_parse_phandle(np, "firmware", 0); ++ fw_node = of_get_parent(np); + if (!fw_node) { + dev_err(dev, "Missing firmware node\n"); + return -ENOENT; + } + -+ fw = rpi_firmware_get(fw_node); ++ fw = devm_rpi_firmware_get(&pdev->dev, fw_node); ++ of_node_put(fw_node); + if (!fw) + return -EPROBE_DEFER; + @@ -50853,11 +71596,10 @@ + } + ucb->bus_addr = 0; + } ++ ucb->gc.parent = dev; + 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.base = -1; + ucb->gc.ngpio = NUM_GPIO; + + ucb->gc.direction_input = brcmvirt_gpio_dir_in; @@ -50920,12 +71662,151 @@ +MODULE_AUTHOR("Dom Cobley <popcornmix@gmail.com>"); +MODULE_DESCRIPTION("brcmvirt GPIO driver"); +MODULE_ALIAS("platform:brcmvirt-gpio"); +diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c +index bccdbfd5ec80..5f7e93335dcb 100644 +--- a/drivers/gpio/gpio-brcmstb.c ++++ b/drivers/gpio/gpio-brcmstb.c +@@ -50,7 +50,6 @@ struct brcmstb_gpio_priv { + struct irq_domain *irq_domain; + struct irq_chip irq_chip; + int parent_irq; +- int gpio_base; + int num_gpios; + int parent_wake_irq; + }; +@@ -92,7 +91,7 @@ brcmstb_gpio_get_active_irqs(struct brcmstb_gpio_bank *bank) + static int brcmstb_gpio_hwirq_to_offset(irq_hw_number_t hwirq, + struct brcmstb_gpio_bank *bank) + { +- return hwirq - (bank->gc.base - bank->parent_priv->gpio_base); ++ return hwirq - bank->id * 32; + } + + static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank, +@@ -117,8 +116,9 @@ static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank, + static int brcmstb_gpio_to_irq(struct gpio_chip *gc, unsigned offset) + { + struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc); ++ struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc); + /* gc_offset is relative to this gpio_chip; want real offset */ +- int hwirq = offset + (gc->base - priv->gpio_base); ++ int hwirq = offset + bank->id * 32; + + if (hwirq >= priv->num_gpios) + return -ENXIO; +@@ -263,7 +263,7 @@ static void brcmstb_gpio_irq_bank_handler(struct brcmstb_gpio_bank *bank) + { + struct brcmstb_gpio_priv *priv = bank->parent_priv; + struct irq_domain *domain = priv->irq_domain; +- int hwbase = bank->gc.base - priv->gpio_base; ++ int hwbase = bank->id * 32; + unsigned long status; + + while ((status = brcmstb_gpio_get_active_irqs(bank))) { +@@ -414,7 +414,7 @@ static int brcmstb_gpio_of_xlate(struct gpio_chip *gc, + if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) + return -EINVAL; + +- offset = gpiospec->args0 - (gc->base - priv->gpio_base); ++ offset = gpiospec->args0 - bank->id * 32; + if (offset >= gc->ngpio || offset < 0) + return -EINVAL; + +@@ -598,8 +598,8 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) + const __be32 *p; + u32 bank_width; + int num_banks = 0; ++ int num_gpios = 0; + int err; +- static int gpio_base; + unsigned long flags = 0; + bool need_wakeup_event = false; + +@@ -613,7 +613,6 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) + if (IS_ERR(reg_base)) + return PTR_ERR(reg_base); + +- priv->gpio_base = gpio_base; + priv->reg_base = reg_base; + priv->pdev = pdev; + +@@ -639,6 +638,8 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) + #if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN) + flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER; + #endif ++ if (of_property_read_bool(np, "brcm,gpio-direct")) ++ flags |= BGPIOF_REG_DIRECT; + + of_property_for_each_u32(np, "brcm,gpio-bank-widths", prop, p, + bank_width) { +@@ -653,7 +654,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) + dev_dbg(dev, "Width 0 found: Empty bank @ %d\n", + num_banks); + num_banks++; +- gpio_base += MAX_GPIO_PER_BANK; ++ num_gpios += MAX_GPIO_PER_BANK; + continue; + } + +@@ -688,16 +689,18 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) + } + + gc->owner = THIS_MODULE; +- gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np); ++ gc->label = devm_kasprintf(dev, GFP_KERNEL, "gpio-brcmstb@%zx", ++ (size_t)res->start + ++ GIO_BANK_OFF(bank->id, 0)); + if (!gc->label) { + err = -ENOMEM; + goto fail; + } +- gc->base = gpio_base; ++ gc->base = -1; + gc->of_gpio_n_cells = 2; + gc->of_xlate = brcmstb_gpio_of_xlate; + /* not all ngpio lines are valid, will use bank width later */ +- gc->ngpio = MAX_GPIO_PER_BANK; ++ gc->ngpio = bank_width; + gc->offset = bank->id * MAX_GPIO_PER_BANK; + if (priv->parent_irq > 0) + gc->to_irq = brcmstb_gpio_to_irq; +@@ -706,8 +709,10 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) + * Mask all interrupts by default, since wakeup interrupts may + * be retained from S5 cold boot + */ +- need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank); +- gc->write_reg(reg_base + GIO_MASK(bank->id), 0); ++ if (priv->parent_irq > 0) { ++ need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank); ++ gc->write_reg(reg_base + GIO_MASK(bank->id), 0); ++ } + + err = gpiochip_add_data(gc, bank); + if (err) { +@@ -715,7 +720,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) + bank->id); + goto fail; + } +- gpio_base += gc->ngpio; ++ num_gpios += gc->ngpio; + + dev_dbg(dev, "bank=%d, base=%d, ngpio=%d, width=%d\n", bank->id, + gc->base, gc->ngpio, bank->width); +@@ -726,7 +731,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) + num_banks++; + } + +- priv->num_gpios = gpio_base - priv->gpio_base; ++ priv->num_gpios = num_gpios; + if (priv->parent_irq > 0) { + err = brcmstb_gpio_irq_setup(pdev, priv); + if (err) diff --git a/drivers/gpio/gpio-fsm.c b/drivers/gpio/gpio-fsm.c new file mode 100644 -index 000000000000..3a348f1c6514 +index 000000000000..ad8cbd894ca6 --- /dev/null +++ b/drivers/gpio/gpio-fsm.c -@@ -0,0 +1,1210 @@ +@@ -0,0 +1,1212 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * GPIO FSM driver @@ -50946,6 +71827,7 @@ +#include <linux/gpio.h> +#include <linux/gpio/driver.h> +#include <linux/interrupt.h> ++#include <linux/kdev_t.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/sysfs.h> @@ -51049,7 +71931,7 @@ + struct fsm_state *current_state; + struct fsm_state *next_state; + struct fsm_state *delay_target_state; -+ unsigned int delay_jiffies; ++ unsigned long delay_jiffies; + int delay_ms; + unsigned int debug; + bool shutting_down; @@ -51121,131 +72003,11 @@ + } +} + -+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_gpiosoff; -+ -+ 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_gpiosoff; -+ -+ 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_eventsi; -+ inp_state = &gf->input_gpio_statesgp_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_gpiosoff; -+ 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_eventsi; -+ 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_gpiosoff; -+ 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_gpiosoff; -+ sg->dir = GPIOF_DIR_OUT; -+ gpio_fsm_set_soft(gf, off, value); -+ -+ return 0; -+} -+ -+static void gpio_fsm_set(struct gpio_chip *gc, unsigned int off, int val) -+{ -+ struct gpio_fsm *gf; -+ -+ gf = gpiochip_get_data(gc); -+ if (off < gf->num_soft_gpios) -+ gpio_fsm_set_soft(gf, off, val); -+} ++ unsigned int off, int val); + +static void gpio_fsm_enter_state(struct gpio_fsm *gf, -+ struct fsm_state *state) ++ struct fsm_state *state) +{ + struct input_gpio_state *inp_state; + struct output_signal *signal; @@ -51258,6 +72020,7 @@ + dev_dbg(gf->dev, "enter_state(%s)\n", state->name); + + gf->current_state = state; ++ gf->delay_target_state = NULL; + + // 1. Apply any listed signals + for (i = 0; i < state->num_signals; i++) { @@ -51316,7 +72079,7 @@ + dev_info(gf->dev, + "GF_SOFT %d=%d -> %s\n", event->index, + event->value, event->target->name); -+ gpio_fsm_go_to_state(gf, event->target); ++ gpio_fsm_enter_state(gf, event->target); + return; + } + } @@ -51329,7 +72092,7 @@ + inp_state->value = event->value; + inp_state->enabled = true; + -+ value = gpiod_get_value(gf->input_gpios->descevent->index); ++ value = gpiod_get_value_cansleep(gf->input_gpios->descevent->index); + + // Clear stale event state + disable_irq(inp_state->irq); @@ -51344,7 +72107,7 @@ + dev_info(gf->dev, + "GF_IN %d=%d -> %s\n", event->index, + event->value, event->target->name); -+ gpio_fsm_go_to_state(gf, event->target); ++ gpio_fsm_enter_state(gf, event->target); + return; + } + } @@ -51359,40 +72122,79 @@ + } +} + -+static void gpio_fsm_work(struct work_struct *work) ++static void gpio_fsm_go_to_state(struct gpio_fsm *gf, ++ struct fsm_state *new_state) +{ + struct input_gpio_state *inp_state; -+ struct fsm_state *new_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>"); ++ ++ state = gf->current_state; ++ ++ /* Disable any enabled GPIO IRQs */ ++ for (i = 0; i < state->num_gpio_events; i++) { ++ gp_ev = &state->gpio_eventsi; ++ inp_state = &gf->input_gpio_statesgp_ev->index; ++ if (inp_state->enabled) { ++ inp_state->enabled = false; ++ irq_set_irq_type(inp_state->irq, ++ IRQF_TRIGGER_NONE); ++ } ++ } ++ ++ gpio_fsm_enter_state(gf, new_state); ++} ++ ++static void gpio_fsm_go_to_state_deferred(struct gpio_fsm *gf, ++ struct fsm_state *new_state) ++{ ++ struct input_gpio_state *inp_state; + struct gpio_event *gp_ev; -+ struct gpio_fsm *gf; ++ struct fsm_state *state; + int i; + -+ gf = container_of(work, struct gpio_fsm, work); ++ dev_dbg(gf->dev, "go_to_state_deferred(%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; ++ ++ /* Disarm any GPIO IRQs */ ++ for (i = 0; i < state->num_gpio_events; i++) { ++ gp_ev = &state->gpio_eventsi; ++ inp_state = &gf->input_gpio_statesgp_ev->index; ++ inp_state->target = NULL; ++ } ++ ++ spin_unlock(&gf->spinlock); ++ ++ schedule_work(&gf->work); ++} ++ ++static void gpio_fsm_work(struct work_struct *work) ++{ ++ struct fsm_state *new_state; ++ struct gpio_fsm *gf; ++ ++ gf = container_of(work, struct gpio_fsm, work); ++ spin_lock(&gf->spinlock); + 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_eventsi; -+ inp_state = &gf->input_gpio_statesgp_ev->index; -+ if (inp_state->enabled) { -+ inp_state->enabled = false; -+ irq_set_irq_type(inp_state->irq, -+ IRQF_TRIGGER_NONE); -+ } -+ } -+ } -+ -+ if (new_state) -+ gpio_fsm_enter_state(gf, new_state); ++ gpio_fsm_go_to_state(gf, new_state); +} + +static irqreturn_t gpio_fsm_gpio_irq_handler(int irq, void *dev_id) @@ -51411,7 +72213,7 @@ + if (gf->debug) + dev_info(gf->dev, "GF_IN %d->%d -> %s\n", + inp_state->index, inp_state->value, target->name); -+ gpio_fsm_go_to_state(gf, target); ++ gpio_fsm_go_to_state_deferred(gf, target); + return IRQ_HANDLED; +} + @@ -51423,12 +72225,11 @@ + target = gf->delay_target_state; + if (!target) + return; -+ + if (gf->debug) + dev_info(gf->dev, "GF_DELAY %d -> %s\n", gf->delay_ms, + target->name); + -+ gpio_fsm_go_to_state(gf, target); ++ gpio_fsm_go_to_state_deferred(gf, target); +} + +int gpio_fsm_parse_signals(struct gpio_fsm *gf, struct fsm_state *state, @@ -51779,6 +72580,90 @@ + return 0; +} + ++static void gpio_fsm_set_soft(struct gpio_fsm *gf, ++ unsigned int off, int val) ++{ ++ struct soft_gpio *sg = &gf->soft_gpiosoff; ++ 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_eventsi; ++ if (gp_ev->index == off && gp_ev->value == val) { ++ if (gf->debug) ++ dev_info(gf->dev, ++ "GF_SOFT %d->%d -> %s\n", gp_ev->index, ++ gp_ev->value, gp_ev->target->name); ++ gpio_fsm_go_to_state(gf, gp_ev->target); ++ break; ++ } ++ } ++} ++ ++static int gpio_fsm_get(struct gpio_chip *gc, unsigned int off) ++{ ++ struct gpio_fsm *gf = gpiochip_get_data(gc); ++ struct soft_gpio *sg; ++ ++ if (off >= gf->num_soft_gpios) ++ return -EINVAL; ++ sg = &gf->soft_gpiosoff; ++ ++ return sg->value; ++} ++ ++static void gpio_fsm_set(struct gpio_chip *gc, unsigned int off, int val) ++{ ++ struct gpio_fsm *gf; ++ ++ gf = gpiochip_get_data(gc); ++ if (off < gf->num_soft_gpios) ++ gpio_fsm_set_soft(gf, off, val); ++} ++ ++static int gpio_fsm_get_direction(struct gpio_chip *gc, unsigned int off) ++{ ++ struct gpio_fsm *gf = gpiochip_get_data(gc); ++ struct soft_gpio *sg; ++ ++ if (off >= gf->num_soft_gpios) ++ return -EINVAL; ++ sg = &gf->soft_gpiosoff; ++ ++ return sg->dir; ++} ++ ++static int gpio_fsm_direction_input(struct gpio_chip *gc, unsigned int off) ++{ ++ struct gpio_fsm *gf = gpiochip_get_data(gc); ++ struct soft_gpio *sg; ++ ++ if (off >= gf->num_soft_gpios) ++ return -EINVAL; ++ sg = &gf->soft_gpiosoff; ++ 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_gpiosoff; ++ sg->dir = GPIOF_DIR_OUT; ++ gpio_fsm_set_soft(gf, off, value); ++ ++ return 0; ++} + +/* + * /sys/class/gpio-fsm/<fsm-name>/ @@ -51844,7 +72729,6 @@ + +static struct class gpio_fsm_class = { + .name = MODULE_NAME, -+ .owner = THIS_MODULE, + + .class_groups = gpio_fsm_class_groups, +}; @@ -51854,7 +72738,7 @@ + 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 *np = dev_of_node(dev); + struct device_node *cp; + struct gpio_fsm *gf; + u32 debug = 0; @@ -52015,7 +72899,6 @@ + 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; + @@ -52042,7 +72925,7 @@ + if (gf->debug) + dev_info(gf->dev, "Start -> %s\n", gf->start_state->name); + -+ gpio_fsm_go_to_state(gf, gf->start_state); ++ gpio_fsm_enter_state(gf, gf->start_state); + + return devm_gpiochip_add_data(dev, &gf->gc, gf); +} @@ -52136,9 +73019,198 @@ +MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.com>"); +MODULE_DESCRIPTION("GPIO FSM driver"); +MODULE_ALIAS("platform:gpio-fsm"); +diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c +index 74fdf0d87b2c..7e26fa957d5e 100644 +--- a/drivers/gpio/gpio-mmio.c ++++ b/drivers/gpio/gpio-mmio.c +@@ -234,6 +234,25 @@ static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); + } + ++static void bgpio_set_direct(struct gpio_chip *gc, unsigned int gpio, int val) ++{ ++ unsigned long mask = bgpio_line2mask(gc, gpio); ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&gc->bgpio_lock, flags); ++ ++ gc->bgpio_data = gc->read_reg(gc->reg_dat); ++ ++ if (val) ++ gc->bgpio_data |= mask; ++ else ++ gc->bgpio_data &= ~mask; ++ ++ gc->write_reg(gc->reg_dat, gc->bgpio_data); ++ ++ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); ++} ++ + static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio, + int val) + { +@@ -326,6 +345,27 @@ static void bgpio_set_multiple_with_clear(struct gpio_chip *gc, + gc->write_reg(gc->reg_clr, clear_mask); + } + ++static void bgpio_set_multiple_direct(struct gpio_chip *gc, ++ unsigned long *mask, ++ unsigned long *bits) ++{ ++ unsigned long flags; ++ unsigned long set_mask, clear_mask; ++ ++ raw_spin_lock_irqsave(&gc->bgpio_lock, flags); ++ ++ bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask); ++ ++ gc->bgpio_data = gc->read_reg(gc->reg_dat); ++ ++ gc->bgpio_data |= set_mask; ++ gc->bgpio_data &= ~clear_mask; ++ ++ gc->write_reg(gc->reg_dat, gc->bgpio_data); ++ ++ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); ++} ++ + static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) + { + return 0; +@@ -363,6 +403,29 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) + return 0; + } + ++static int bgpio_dir_in_direct(struct gpio_chip *gc, unsigned int gpio) ++{ ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&gc->bgpio_lock, flags); ++ ++ if (gc->reg_dir_in) ++ gc->bgpio_dir = ~gc->read_reg(gc->reg_dir_in); ++ if (gc->reg_dir_out) ++ gc->bgpio_dir = gc->read_reg(gc->reg_dir_out); ++ ++ gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio); ++ ++ if (gc->reg_dir_in) ++ gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir); ++ if (gc->reg_dir_out) ++ gc->write_reg(gc->reg_dir_out, gc->bgpio_dir); ++ ++ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); ++ ++ return 0; ++} ++ + static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) + { + /* Return 0 if output, 1 if input */ +@@ -401,6 +464,28 @@ static void bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); + } + ++static void bgpio_dir_out_direct(struct gpio_chip *gc, unsigned int gpio, ++ int val) ++{ ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&gc->bgpio_lock, flags); ++ ++ if (gc->reg_dir_in) ++ gc->bgpio_dir = ~gc->read_reg(gc->reg_dir_in); ++ if (gc->reg_dir_out) ++ gc->bgpio_dir = gc->read_reg(gc->reg_dir_out); ++ ++ gc->bgpio_dir |= bgpio_line2mask(gc, gpio); ++ ++ if (gc->reg_dir_in) ++ gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir); ++ if (gc->reg_dir_out) ++ gc->write_reg(gc->reg_dir_out, gc->bgpio_dir); ++ ++ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); ++} ++ + static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio, + int val) + { +@@ -417,6 +502,22 @@ static int bgpio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio, + return 0; + } + ++static int bgpio_dir_out_dir_first_direct(struct gpio_chip *gc, ++ unsigned int gpio, int val) ++{ ++ bgpio_dir_out_direct(gc, gpio, val); ++ gc->set(gc, gpio, val); ++ return 0; ++} ++ ++static int bgpio_dir_out_val_first_direct(struct gpio_chip *gc, ++ unsigned int gpio, int val) ++{ ++ gc->set(gc, gpio, val); ++ bgpio_dir_out_direct(gc, gpio, val); ++ return 0; ++} ++ + static int bgpio_setup_accessors(struct device *dev, + struct gpio_chip *gc, + bool byte_be) +@@ -510,6 +611,9 @@ static int bgpio_setup_io(struct gpio_chip *gc, + } else if (flags & BGPIOF_NO_OUTPUT) { + gc->set = bgpio_set_none; + gc->set_multiple = NULL; ++ } else if (flags & BGPIOF_REG_DIRECT) { ++ gc->set = bgpio_set_direct; ++ gc->set_multiple = bgpio_set_multiple_direct; + } else { + gc->set = bgpio_set; + gc->set_multiple = bgpio_set_multiple; +@@ -546,11 +650,21 @@ static int bgpio_setup_direction(struct gpio_chip *gc, + if (dirout || dirin) { + gc->reg_dir_out = dirout; + gc->reg_dir_in = dirin; +- if (flags & BGPIOF_NO_SET_ON_INPUT) +- gc->direction_output = bgpio_dir_out_dir_first; +- else +- gc->direction_output = bgpio_dir_out_val_first; +- gc->direction_input = bgpio_dir_in; ++ if (flags & BGPIOF_REG_DIRECT) { ++ if (flags & BGPIOF_NO_SET_ON_INPUT) ++ gc->direction_output = ++ bgpio_dir_out_dir_first_direct; ++ else ++ gc->direction_output = ++ bgpio_dir_out_val_first_direct; ++ gc->direction_input = bgpio_dir_in_direct; ++ } else { ++ if (flags & BGPIOF_NO_SET_ON_INPUT) ++ gc->direction_output = bgpio_dir_out_dir_first; ++ else ++ gc->direction_output = bgpio_dir_out_val_first; ++ gc->direction_input = bgpio_dir_in; ++ } + gc->get_direction = bgpio_get_dir; + } else { + if (flags & BGPIOF_NO_OUTPUT) +diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c +index bdd50a78e414..52923f616222 100644 +--- a/drivers/gpio/gpio-pca953x.c ++++ b/drivers/gpio/gpio-pca953x.c +@@ -1345,6 +1345,7 @@ static const struct of_device_id pca953x_dt_ids = { + { .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), }, + { .compatible = "ti,tca9538", .data = OF_953X( 8, PCA_INT), }, + { .compatible = "ti,tca9539", .data = OF_953X(16, PCA_INT), }, ++ { .compatible = "ti,tca9554", .data = OF_953X( 8, PCA_INT), }, + + { .compatible = "onnn,cat9554", .data = OF_953X( 8, PCA_INT), }, + { .compatible = "onnn,pca9654", .data = OF_953X( 8, PCA_INT), }, diff --git a/drivers/gpio/gpio-pwm.c b/drivers/gpio/gpio-pwm.c new file mode 100644 -index 000000000000..89f5d6b353ab +index 000000000000..4a718b365a6f --- /dev/null +++ b/drivers/gpio/gpio-pwm.c @@ -0,0 +1,144 @@ @@ -52245,7 +73317,7 @@ + pwm_gpio->gc.parent = dev; + pwm_gpio->gc.label = "pwm-gpio"; + pwm_gpio->gc.owner = THIS_MODULE; -+ pwm_gpio->gc.of_node = dev->of_node; ++ pwm_gpio->gc.fwnode = dev->fwnode; + pwm_gpio->gc.base = -1; + + pwm_gpio->gc.get_direction = pwm_gpio_get_direction; @@ -52287,10 +73359,10 @@ +MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com>"); +MODULE_DESCRIPTION("PWM GPIO driver"); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c -index af5bb8fedfea..2bd26c985246 100644 +index deca1d43de9c..48acc58cdf2d 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c -@@ -51,6 +51,8 @@ +@@ -57,6 +57,8 @@ #define extra_checks 0 #endif @@ -52299,7 +73371,7 @@ /* Device and char device-related information */ static DEFINE_IDA(gpio_ida); static dev_t gpio_devt; -@@ -2444,8 +2446,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) +@@ -2591,8 +2593,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) value = !!value; /* GPIOs used for enabled IRQs shall not be set as output */ @@ -52310,7 +73382,7 @@ gpiod_err(desc, "%s: tried to set a GPIO tied to an IRQ as output\n", __func__); -@@ -3250,8 +3252,8 @@ int gpiochip_lock_as_irq(struct gpio_chip *gc, unsigned int offset) +@@ -3470,8 +3472,8 @@ int gpiochip_lock_as_irq(struct gpio_chip *gc, unsigned int offset) } /* To be valid for IRQ the line needs to be input or open drain */ @@ -52322,648 +73394,57 @@ "%s: tried to flag a GPIO set as output for IRQ\n", __func__); diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig -index ca868271f4c4..74872b157233 100644 +index c4a0e10b9704..a67248eb854e 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig -@@ -392,6 +392,8 @@ source "drivers/gpu/drm/tidss/Kconfig" +@@ -345,6 +345,8 @@ source "drivers/gpu/drm/v3d/Kconfig" - source "drivers/gpu/drm/xlnx/Kconfig" + source "drivers/gpu/drm/vc4/Kconfig" -+source "drivers/gpu/drm/gud/Kconfig" ++source "drivers/gpu/drm/rp1/Kconfig" + - # Keep legacy drivers last + source "drivers/gpu/drm/loongson/Kconfig" - menuconfig DRM_LEGACY + source "drivers/gpu/drm/etnaviv/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile -index 81569009f884..78dd8e12525d 100644 +index a670c0d95023..0df4a7d4f8e2 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile -@@ -124,3 +124,4 @@ obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/ - obj-$(CONFIG_DRM_MCDE) += mcde/ - obj-$(CONFIG_DRM_TIDSS) += tidss/ - obj-y += xlnx/ -+obj-y += gud/ -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -index 6c8f141103da..374f2bf06c3a 100644 ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -@@ -4992,7 +4992,6 @@ static void dm_disable_vblank(struct drm_crtc *crtc) - 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, -@@ -5476,25 +5475,6 @@ static int fill_hdr_info_packet(const struct drm_connector_state *state, - 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) -@@ -5510,7 +5490,7 @@ amdgpu_dm_connector_atomic_check(struct drm_connector *conn, - 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); -@@ -5605,17 +5585,19 @@ static void dm_update_crtc_active_planes(struct drm_crtc *crtc, - } - - 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; - } -@@ -5626,8 +5608,8 @@ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc, - * 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 */ -@@ -6526,9 +6508,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, - 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); -@@ -7778,7 +7758,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) - dm_old_crtc_state->abm_level; - - hdr_changed = -- is_hdr_metadata_different(old_con_state, new_con_state); -+ !drm_connector_atomic_hdr_metadata_equal(old_con_state, new_con_state); - - if (!scaling_changed && !abm_changed && !hdr_changed) - continue; -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c -index d617e98afb76..935e351e8ec4 100644 ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c -@@ -24,6 +24,7 @@ - */ - - #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> -@@ -264,8 +265,10 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) - - 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 --git a/drivers/gpu/drm/arc/arcpgu_crtc.c b/drivers/gpu/drm/arc/arcpgu_crtc.c -index be7c29cec318..042d7b54a6de 100644 ---- a/drivers/gpu/drm/arc/arcpgu_crtc.c -+++ b/drivers/gpu/drm/arc/arcpgu_crtc.c -@@ -116,7 +116,7 @@ static void arc_pgu_crtc_mode_set_nofb(struct drm_crtc *crtc) - } - - 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); - -@@ -127,7 +127,7 @@ static void arc_pgu_crtc_atomic_enable(struct drm_crtc *crtc, - } - - 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 --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c -index f33418d6e1a0..00472e15ba0b 100644 ---- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c -+++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c -@@ -74,16 +74,18 @@ static void komeda_crtc_update_clock_ratio(struct komeda_crtc_state *kcrtc_st) - */ - 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; -@@ -273,8 +275,10 @@ komeda_crtc_do_flush(struct drm_crtc *crtc, - - 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); -@@ -319,8 +323,10 @@ komeda_crtc_flush_and_wait_for_flip_done(struct komeda_crtc *kcrtc, - - 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; -@@ -379,8 +385,10 @@ komeda_crtc_atomic_disable(struct drm_crtc *crtc, - - 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; -@@ -540,7 +548,6 @@ static void komeda_crtc_vblank_disable(struct drm_crtc *crtc) - } - - 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 --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c -index af67fefed38d..a3234bfb0917 100644 ---- a/drivers/gpu/drm/arm/hdlcd_crtc.c -+++ b/drivers/gpu/drm/arm/hdlcd_crtc.c -@@ -168,7 +168,7 @@ static void hdlcd_crtc_mode_set_nofb(struct drm_crtc *crtc) - } - - 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); - -@@ -179,7 +179,7 @@ static void hdlcd_crtc_atomic_enable(struct drm_crtc *crtc, - } - - 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); - -@@ -205,7 +205,7 @@ static enum drm_mode_status hdlcd_crtc_mode_valid(struct drm_crtc *crtc, - } - - 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 --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c -index 587d94798f5c..494075ddbef6 100644 ---- a/drivers/gpu/drm/arm/malidp_crtc.c -+++ b/drivers/gpu/drm/arm/malidp_crtc.c -@@ -46,7 +46,7 @@ static enum drm_mode_status malidp_crtc_mode_valid(struct drm_crtc *crtc, - } - - 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; -@@ -70,8 +70,10 @@ static void malidp_crtc_atomic_enable(struct drm_crtc *crtc, - } - - 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; -@@ -335,8 +337,10 @@ static int malidp_crtc_atomic_check_scaling(struct drm_crtc *crtc, - } - - 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; -@@ -371,7 +375,7 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc, - */ - - /* 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) -@@ -387,7 +391,7 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc, - rot_mem_free += hwdev->rotation_memory1; - - /* 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; -@@ -415,18 +419,18 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc, - } - - /* 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; - } -@@ -506,7 +510,6 @@ static void malidp_crtc_disable_vblank(struct drm_crtc *crtc) - } - - 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 --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c -index a887b6a5f8bd..f10a063b338c 100644 ---- a/drivers/gpu/drm/armada/armada_crtc.c -+++ b/drivers/gpu/drm/armada/armada_crtc.c -@@ -413,21 +413,23 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) - } - - 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); - -@@ -441,7 +443,7 @@ static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc, - } - - 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); - -@@ -467,8 +469,10 @@ static void armada_drm_crtc_atomic_flush(struct drm_crtc *crtc, - } - - 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; - -@@ -503,8 +507,10 @@ static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc, - } - - 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); -@@ -810,7 +816,6 @@ static const struct drm_crtc_funcs armada_crtc_funcs = { - .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 --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c -index d27f2840b955..9f3b8152becd 100644 ---- a/drivers/gpu/drm/ast/ast_mode.c -+++ b/drivers/gpu/drm/ast/ast_mode.c -@@ -751,24 +751,26 @@ static void ast_crtc_dpms(struct drm_crtc *crtc, int mode) - } - - 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; -@@ -793,7 +795,7 @@ ast_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_c - - 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); -@@ -816,8 +818,10 @@ ast_crtc_helper_atomic_enable(struct drm_crtc *crtc, - - 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); - -@@ -897,7 +901,6 @@ static void ast_crtc_atomic_destroy_state(struct drm_crtc *crtc, - - 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 --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c -index ce246b96330b..c8471bd4abbb 100644 ---- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c -+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c -@@ -165,7 +165,7 @@ atmel_hlcdc_crtc_mode_valid(struct drm_crtc *c, - } - - 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); -@@ -200,7 +200,7 @@ static void atmel_hlcdc_crtc_atomic_disable(struct drm_crtc *c, - } - - 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); -@@ -325,8 +325,9 @@ static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state) - } - - 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); -@@ -341,7 +342,7 @@ static int atmel_hlcdc_crtc_atomic_check(struct drm_crtc *c, - } - - 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); - -@@ -356,7 +357,7 @@ static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c, - } - - 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 */ - } -@@ -472,7 +473,6 @@ static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = { - .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 --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c -index c916f4b8907e..a63d6d238e3c 100644 ---- a/drivers/gpu/drm/bridge/panel.c -+++ b/drivers/gpu/drm/bridge/panel.c -@@ -79,6 +79,10 @@ static int panel_bridge_attach(struct drm_bridge *bridge, - return ret; +@@ -199,3 +199,4 @@ obj-y += solomon/ + obj-$(CONFIG_DRM_SPRD) += sprd/ + obj-$(CONFIG_DRM_LOONGSON) += loongson/ + obj-$(CONFIG_DRM_PHYTIUM) += phytium/ ++obj-y += rp1/ +diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig +index 3e6a4e2044c0..b1c5ef817598 100644 +--- a/drivers/gpu/drm/bridge/Kconfig ++++ b/drivers/gpu/drm/bridge/Kconfig +@@ -56,6 +56,7 @@ config DRM_CROS_EC_ANX7688 + config DRM_DISPLAY_CONNECTOR + tristate "Display connector support" + depends on OF ++ select DRM_KMS_HELPER + help + Driver for display connectors with support for DDC and hot-plug + detection. Most display controllers handle display connectors +diff --git a/drivers/gpu/drm/bridge/tc358762.c b/drivers/gpu/drm/bridge/tc358762.c +index 46198af9eebb..8b856bc2ed5b 100644 +--- a/drivers/gpu/drm/bridge/tc358762.c ++++ b/drivers/gpu/drm/bridge/tc358762.c +@@ -294,7 +294,7 @@ static int tc358762_probe(struct mipi_dsi_device *dsi) + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + drm_bridge_remove(&ctx->bridge); +- dev_err(dev, "failed to attach dsi\n"); ++ dev_err_probe(dev, ret, "failed to attach dsi\n"); } -+ /* set up connector's "panel orientation" property */ -+ drm_connector_set_panel_orientation(&panel_bridge->connector, -+ panel_bridge->panel->orientation); -+ - drm_connector_attach_encoder(&panel_bridge->connector, - bridge->encoder); - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 29c0eb4bd754..f7830acb45ea 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -2403,21 +2403,6 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) 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) - { -@@ -2431,7 +2416,7 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, - 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); -@@ -2500,8 +2485,7 @@ static int dw_hdmi_connector_create(struct dw_hdmi *hdmi) - 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 --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c -index 8a871e5c3e26..95addc0070ac 100644 +index 554d4468aa7c..d759c5ebd410 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c -@@ -122,7 +122,8 @@ static int handle_conflicting_encoders(struct drm_atomic_state *state, - 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 -@@ -345,8 +346,7 @@ update_connector_routing(struct drm_atomic_state *state, - 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 -@@ -430,6 +430,11 @@ mode_fixup(struct drm_atomic_state *state) +@@ -443,6 +443,11 @@ mode_fixup(struct drm_atomic_state *state) new_crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc); @@ -52975,4057 +73456,1039 @@ /* * Each encoder has at most one connector (since we always steal * it away), so we won't call ->mode_fixup twice. -@@ -918,7 +923,7 @@ drm_atomic_helper_check_planes(struct drm_device *dev, - 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); -@@ -1093,7 +1098,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) - 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) -@@ -1313,7 +1318,7 @@ static void drm_atomic_helper_commit_writebacks(struct drm_device *dev, - - 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); - } - } - } -@@ -1358,7 +1363,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, - 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); - } -@@ -2034,6 +2039,9 @@ crtc_or_fake_commit(struct drm_atomic_state *state, struct drm_crtc *crtc) - * 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 -@@ -2077,8 +2085,11 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, - 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; +@@ -1648,13 +1653,6 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev, int i, ret; + unsigned int crtc_mask = 0; -+ 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) -@@ -2155,6 +2166,9 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, - 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); -@@ -2507,7 +2521,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, - if (active_only && !new_crtc_state->active) +- /* +- * Legacy cursor ioctls are completely unsynced, and userspace +- * relies on that (by doing tons of cursor updates). +- */ +- if (old_state->legacy_cursor_update) +- return; +- + for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) { + if (!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) { -@@ -2565,7 +2579,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, - if (active_only && !new_crtc_state->active) +@@ -2305,12 +2303,6 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, continue; + } -- funcs->atomic_flush(crtc, old_crtc_state); -+ funcs->atomic_flush(crtc, old_state); - } - } - EXPORT_SYMBOL(drm_atomic_helper_commit_planes); -@@ -2603,7 +2617,7 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state) - - 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); +- /* Legacy cursor updates are fully unsynced. */ +- if (state->legacy_cursor_update) { +- complete_all(&commit->flip_done); +- continue; +- } +- + if (!new_crtc_state->event) { + commit->event = kzalloc(sizeof(*commit->event), + GFP_KERNEL); +diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c +index 784e63d70a42..d7c761d9fb72 100644 +--- a/drivers/gpu/drm/drm_atomic_state_helper.c ++++ b/drivers/gpu/drm/drm_atomic_state_helper.c +@@ -267,6 +267,20 @@ void __drm_atomic_helper_plane_state_reset(struct drm_plane_state *plane_state, + plane_state->color_range = val; + } + ++ if (plane->chroma_siting_h_property) { ++ if (!drm_object_property_get_default_value(&plane->base, ++ plane->chroma_siting_h_property, ++ &val)) ++ plane_state->chroma_siting_h = val; ++ } ++ ++ if (plane->chroma_siting_v_property) { ++ if (!drm_object_property_get_default_value(&plane->base, ++ plane->chroma_siting_v_property, ++ &val)) ++ plane_state->chroma_siting_v = val; ++ } ++ + if (plane->zpos_property) { + if (!drm_object_property_get_default_value(&plane->base, + plane->zpos_property, +diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c +index 98d3b10c08ae..1e7c35b36a39 100644 +--- a/drivers/gpu/drm/drm_atomic_uapi.c ++++ b/drivers/gpu/drm/drm_atomic_uapi.c +@@ -580,6 +580,10 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, + state->color_encoding = val; + } else if (property == plane->color_range_property) { + state->color_range = val; ++ } else if (property == plane->chroma_siting_h_property) { ++ state->chroma_siting_h = val; ++ } else if (property == plane->chroma_siting_v_property) { ++ state->chroma_siting_v = val; + } else if (property == config->prop_fb_damage_clips) { + ret = drm_atomic_replace_property_blob_from_id(dev, + &state->fb_damage_clips, +@@ -646,6 +650,10 @@ drm_atomic_plane_get_property(struct drm_plane *plane, + *val = state->color_encoding; + } else if (property == plane->color_range_property) { + *val = state->color_range; ++ } else if (property == plane->chroma_siting_h_property) { ++ *val = state->chroma_siting_h; ++ } else if (property == plane->chroma_siting_v_property) { ++ *val = state->chroma_siting_v; + } else if (property == config->prop_fb_damage_clips) { + *val = (state->fb_damage_clips) ? + state->fb_damage_clips->base.id : 0; +@@ -693,6 +701,7 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, + { + struct drm_device *dev = connector->dev; + struct drm_mode_config *config = &dev->mode_config; ++ bool margins_updated = false; + bool replaced = false; + int ret; - drm_for_each_plane_mask(plane, crtc->dev, plane_mask) { - struct drm_plane_state *old_plane_state = -@@ -2629,7 +2643,7 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state) +@@ -721,12 +730,16 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, + state->tv.subconnector = val; + } else if (property == config->tv_left_margin_property) { + state->tv.margins.left = val; ++ margins_updated = true; + } else if (property == config->tv_right_margin_property) { + state->tv.margins.right = val; ++ margins_updated = true; + } else if (property == config->tv_top_margin_property) { + state->tv.margins.top = val; ++ margins_updated = true; + } else if (property == config->tv_bottom_margin_property) { + state->tv.margins.bottom = val; ++ margins_updated = true; + } else if (property == config->legacy_tv_mode_property) { + state->tv.legacy_mode = val; + } else if (property == config->tv_mode_property) { +@@ -809,6 +822,12 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, + return -EINVAL; } - 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); - -@@ -3485,76 +3499,6 @@ int drm_atomic_helper_page_flip_target(struct drm_crtc *crtc, ++ if (margins_updated && state->crtc) { ++ ret = drm_atomic_add_affected_planes(state->state, state->crtc); ++ ++ return ret; ++ } ++ + return 0; } - 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_datai.red = redi; -- blob_datai.green = greeni; -- blob_datai.blue = bluei; -- } -- -- 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 diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c -index 138ff34b31db..78933e2a5f44 100644 +index d021497841b8..973c6aeff8a1 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c -@@ -22,6 +22,7 @@ - - #include <linux/uaccess.h> +@@ -330,7 +330,9 @@ static int drm_crtc_legacy_gamma_set(struct drm_crtc *crtc, + replaced = drm_property_replace_blob(&crtc_state->degamma_lut, + use_gamma_lut ? NULL : blob); + replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL); +- replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, ++ if (!crtc_state->gamma_lut || !crtc_state->gamma_lut->data || ++ memcmp(crtc_state->gamma_lut->data, blob_data, blob->length)) ++ replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, + use_gamma_lut ? blob : NULL); + crtc_state->color_mgmt_changed |= replaced; -+#include <drm/drm_atomic.h> - #include <drm/drm_color_mgmt.h> - #include <drm/drm_crtc.h> - #include <drm/drm_device.h> -@@ -89,9 +90,8 @@ - * 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 -@@ -156,9 +156,6 @@ EXPORT_SYMBOL(drm_color_ctm_s31_32_to_qm_n); - * 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, -@@ -231,6 +228,105 @@ int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, +@@ -588,6 +590,42 @@ int drm_plane_create_color_properties(struct drm_plane *plane, } - EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); + EXPORT_SYMBOL(drm_plane_create_color_properties); +/** -+ * drm_crtc_supports_legacy_gamma - does the crtc support legacy gamma correction table -+ * @crtc: CRTC object ++ * drm_plane_create_chroma_siting_properties - chroma siting related plane properties ++ * @plane: plane object + * -+ * Returns true/false if the given crtc supports setting the legacy gamma -+ * correction table. ++ * Create and attach plane specific CHROMA_SITING ++ * properties to @plane. + */ -+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) ++int drm_plane_create_chroma_siting_properties(struct drm_plane *plane, ++ int32_t default_chroma_siting_h, ++ int32_t default_chroma_siting_v) +{ -+ 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); ++ struct drm_device *dev = plane->dev; ++ struct drm_property *prop; + -+ state = drm_atomic_state_alloc(crtc->dev); -+ if (!state) ++ prop = drm_property_create_range(dev, 0, "CHROMA_SITING_H", ++ 0, 1<<16); ++ if (!prop) + return -ENOMEM; ++ plane->chroma_siting_h_property = prop; ++ drm_object_attach_property(&plane->base, prop, default_chroma_siting_h); + -+ 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_datai.red = redi; -+ blob_datai.green = greeni; -+ blob_datai.blue = bluei; -+ } ++ prop = drm_property_create_range(dev, 0, "CHROMA_SITING_V", ++ 0, 1<<16); ++ if (!prop) ++ return -ENOMEM; ++ plane->chroma_siting_v_property = prop; ++ drm_object_attach_property(&plane->base, prop, default_chroma_siting_v); + -+ 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; ++ if (plane->state) { ++ plane->state->chroma_siting_h = default_chroma_siting_h; ++ plane->state->chroma_siting_v = default_chroma_siting_v; + } -+ -+ /* 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); -+ if (!crtc_state->gamma_lut || !crtc_state->gamma_lut->data || -+ memcmp(crtc_state->gamma_lut->data, blob_data, blob->length)) -+ 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; ++ return 0; +} ++EXPORT_SYMBOL(drm_plane_create_chroma_siting_properties); + /** - * drm_mode_gamma_set_ioctl - set the gamma table - * @dev: DRM device -@@ -262,7 +358,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, - if (!crtc) - return -ENOENT; - -- if (crtc->funcs->gamma_set == NULL) -+ if (!drm_crtc_supports_legacy_gamma(crtc)) - return -ENOSYS; - - /* memcpy into gamma store */ -@@ -290,8 +386,8 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, - 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); + * drm_color_lut_check - check validity of lookup table + * @lut: property blob containing LUT to check diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c -index 717c4e7271b0..c0beaa2ea6ee 100644 +index c44d5bcf1284..75ce5af3502b 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c -@@ -94,6 +94,7 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list = { - { DRM_MODE_CONNECTOR_DPI, "DPI" }, - { DRM_MODE_CONNECTOR_WRITEBACK, "Writeback" }, - { DRM_MODE_CONNECTOR_SPI, "SPI" }, -+ { DRM_MODE_CONNECTOR_USB, "USB" }, +@@ -33,6 +33,7 @@ + #include <drm/drm_sysfs.h> + #include <drm/drm_utils.h> + ++#include <linux/of.h> + #include <linux/property.h> + #include <linux/uaccess.h> + +@@ -83,6 +84,7 @@ struct drm_conn_prop_enum_list { + int type; + const char *name; + struct ida ida; ++ int first_dyn_num; }; - void drm_connector_ida_init(void) -@@ -2143,6 +2144,75 @@ int drm_connector_attach_max_bpc_property(struct drm_connector *connector, - } - EXPORT_SYMBOL(drm_connector_attach_max_bpc_property); + /* +@@ -112,12 +114,41 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list = { + { DRM_MODE_CONNECTOR_USB, "USB" }, + }; -+/** -+ * 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); ++#define MAX_DT_NODE_NAME_LEN 20 ++#define DT_DRM_NODE_PREFIX "drm-" + -+/** -+ * 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) ++static void drm_connector_get_of_name(int type, char *node_name, int length) +{ -+ 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); ++ int i = 0; + -+/** -+ * 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; ++ strcpy(node_name, DT_DRM_NODE_PREFIX); + -+ if (!old_blob || !new_blob) -+ return old_blob == new_blob; ++ do { ++ node_namei + strlen(DT_DRM_NODE_PREFIX) = ++ tolower(drm_connector_enum_listtype.namei); + -+ if (old_blob->length != new_blob->length) -+ return false; ++ } while (drm_connector_enum_listtype.namei++ && ++ i < length); + -+ return !memcmp(old_blob->data, new_blob->data, old_blob->length); ++ node_namelength - 1 = '\0'; +} -+EXPORT_SYMBOL(drm_connector_atomic_hdr_metadata_equal); + - /** - * drm_connector_set_vrr_capable_property - sets the variable refresh rate - * capable property for a connector -diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c -index add317bd8d55..46e41ad5e44f 100644 ---- a/drivers/gpu/drm/drm_edid.c -+++ b/drivers/gpu/drm/drm_edid.c -@@ -4961,10 +4961,9 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, - - /* - * Deep color support mandates RGB444 support for all video -- * modes and forbids YCRCB422 support for all video modes per -- * HDMI 1.3 spec. -+ * modes. - */ -- info->color_formats = DRM_COLOR_FORMAT_RGB444; -+ info->color_formats |= DRM_COLOR_FORMAT_RGB444; - - /* YCRCB444 is optional according to spec. */ - if (hdmi6 & DRM_EDID_HDMI_DC_Y444) { -@@ -5712,13 +5711,13 @@ static const u32 hdmi_colorimetry_val = { - #undef ACE + void drm_connector_ida_init(void) + { +- int i; ++ int i, id; ++ char node_nameMAX_DT_NODE_NAME_LEN; - /** -- * drm_hdmi_avi_infoframe_colorspace() - fill the HDMI AVI infoframe -- * colorspace information -+ * drm_hdmi_avi_infoframe_colorimetry() - fill the HDMI AVI infoframe -+ * colorimetry information - * @frame: HDMI AVI infoframe - * @conn_state: connector state - */ - void --drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, -+drm_hdmi_avi_infoframe_colorimetry(struct hdmi_avi_infoframe *frame, - const struct drm_connector_state *conn_state) - { - u32 colorimetry_val; -@@ -5737,7 +5736,7 @@ drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, - frame->extended_colorimetry = (colorimetry_val >> 2) & - EXTENDED_COLORIMETRY_MASK; +- for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) ++ for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) { + ida_init(&drm_connector_enum_listi.ida); ++ ++ drm_connector_get_of_name(i, node_name, MAX_DT_NODE_NAME_LEN); ++ ++ id = of_alias_get_highest_id(node_name); ++ if (id > 0) ++ drm_connector_enum_listi.first_dyn_num = id + 1; ++ else ++ drm_connector_enum_listi.first_dyn_num = 1; ++ } } --EXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorspace); -+EXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorimetry); - - /** - * drm_hdmi_avi_infoframe_quant_range() - fill the HDMI AVI infoframe -diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c -index 722c7ebe4e88..bdc7c605f43e 100644 ---- a/drivers/gpu/drm/drm_fourcc.c -+++ b/drivers/gpu/drm/drm_fourcc.c -@@ -286,6 +286,9 @@ const struct drm_format_info *__drm_format_info(u32 format) - .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 --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c -index 2f5b0c2bb0fe..89ced6af9c5c 100644 ---- a/drivers/gpu/drm/drm_framebuffer.c -+++ b/drivers/gpu/drm/drm_framebuffer.c -@@ -217,12 +217,16 @@ static int framebuffer_check(struct drm_device *dev, - if (min_pitch > UINT_MAX) - return -ERANGE; -- if ((uint64_t) height * r->pitchesi + r->offsetsi > UINT_MAX) -- return -ERANGE; -- -- if (block_size && r->pitchesi < min_pitch) { -- DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitchesi, i); -- return -EINVAL; -+ if (r->modifieri == DRM_FORMAT_MOD_LINEAR) { -+ if ((uint64_t)height * r->pitchesi + r->offsetsi > -+ UINT_MAX) -+ return -ERANGE; -+ -+ if (block_size && r->pitchesi < min_pitch) { -+ DRM_DEBUG_KMS("bad pitch %u for plane %d\n", -+ r->pitchesi, i); -+ return -EINVAL; -+ } - } - - if (r->modifieri && !(r->flags & DRM_MODE_FB_MODIFIERS)) { -diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c -index f634371c717a..bee5066e9227 100644 ---- a/drivers/gpu/drm/drm_panel.c -+++ b/drivers/gpu/drm/drm_panel.c -@@ -61,6 +61,9 @@ void drm_panel_init(struct drm_panel *panel, struct device *dev, - panel->dev = dev; - panel->funcs = funcs; - panel->connector_type = connector_type; + void drm_connector_ida_destroy(void) +@@ -225,7 +256,9 @@ static int __drm_connector_init(struct drm_device *dev, + struct i2c_adapter *ddc) + { + struct drm_mode_config *config = &dev->mode_config; ++ char node_nameMAX_DT_NODE_NAME_LEN; + int ret; ++ int id; + struct ida *connector_ida = + &drm_connector_enum_listconnector_type.ida; + +@@ -255,8 +288,28 @@ static int __drm_connector_init(struct drm_device *dev, + ret = 0; + + connector->connector_type = connector_type; +- connector->connector_type_id = +- ida_alloc_min(connector_ida, 1, GFP_KERNEL); ++ connector->connector_type_id = 0; ++ ++ drm_connector_get_of_name(connector_type, node_name, MAX_DT_NODE_NAME_LEN); ++ id = of_alias_get_id(dev->dev->of_node, node_name); ++ if (id > 0) { ++ /* Try and allocate the requested ID ++ * Valid range is 1 to 31, hence ignoring 0 as an error ++ */ ++ int type_id = ida_alloc_range(connector_ida, id, id, GFP_KERNEL); + -+ panel->orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN; -+ of_drm_get_panel_orientation(dev->of_node, &panel->orientation); - } - EXPORT_SYMBOL(drm_panel_init); ++ if (type_id > 0) ++ connector->connector_type_id = type_id; ++ else ++ drm_err(dev, "Failed to acquire type ID %d for interface type %s, ret %d\n", ++ id, drm_connector_enum_listconnector_type.name, ++ type_id); ++ } ++ if (!connector->connector_type_id) ++ connector->connector_type_id = ++ ida_alloc_min(connector_ida, ++ drm_connector_enum_listconnector_type.first_dyn_num, ++ GFP_KERNEL); + if (connector->connector_type_id < 0) { + ret = connector->connector_type_id; + goto out_put_id; +@@ -996,6 +1049,7 @@ static const struct drm_prop_enum_list drm_tv_mode_enum_list = { + { DRM_MODE_TV_MODE_PAL_M, "PAL-M" }, + { DRM_MODE_TV_MODE_PAL_N, "PAL-N" }, + { DRM_MODE_TV_MODE_SECAM, "SECAM" }, ++ { DRM_MODE_TV_MODE_MONOCHROME, "Mono" }, + }; + DRM_ENUM_NAME_FN(drm_get_tv_mode_name, drm_tv_mode_enum_list) + +@@ -1682,6 +1736,12 @@ EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property); + * TV Mode is CCIR System B (aka 625-lines) together with + * the SECAM Color Encoding. + * ++ * Mono: ++ * ++ * Use timings appropriate to the DRM mode, including ++ * equalizing pulses for a 525-line or 625-line mode, ++ * with no pedestal or color encoding. ++ * + * Drivers can set up this property by calling + * drm_mode_create_tv_properties(). + */ +diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c +index d612133e2cf7..7d4ed1530ac2 100644 +--- a/drivers/gpu/drm/drm_fb_helper.c ++++ b/drivers/gpu/drm/drm_fb_helper.c +@@ -1837,7 +1837,7 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper) + struct drm_device *dev = fb_helper->dev; + struct fb_info *info; + unsigned int width, height; +- int ret; ++ int ret, id; -@@ -289,16 +292,18 @@ int of_drm_get_panel_orientation(const struct device_node *np, + width = dev->mode_config.max_width; + height = dev->mode_config.max_height; +@@ -1868,6 +1868,15 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper) + * register the fbdev emulation instance in kernel_fb_helper_list. */ + mutex_unlock(&fb_helper->lock); + ++ id = of_alias_get_highest_id("drm-fb"); ++ if (id >= 0) ++ fb_set_lowest_dynamic_fb(id + 1); ++ ++ id = of_alias_get_id(dev->dev->of_node, "drm-fb"); ++ if (id >= 0) { ++ info->node = id; ++ info->custom_fb_num = true; ++ } + ret = register_framebuffer(info); if (ret < 0) return ret; +diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c +index ac9a406250c5..5a6d966f7ada 100644 +--- a/drivers/gpu/drm/drm_modes.c ++++ b/drivers/gpu/drm/drm_modes.c +@@ -530,7 +530,8 @@ static int fill_analog_mode(struct drm_device *dev, + * @interlace: whether to compute an interlaced mode + * + * This function creates a struct drm_display_mode instance suited for +- * an analog TV output, for one of the usual analog TV mode. ++ * an analog TV output, for one of the usual analog TV modes. Where ++ * this is DRM_MODE_TV_MODE_MONOCHROME, a 625-line mode will be created. + * + * Note that @hdisplay is larger than the usual constraints for the PAL + * and NTSC timings, and we'll choose to ignore most timings constraints +@@ -568,6 +569,8 @@ struct drm_display_mode *drm_analog_tv_mode(struct drm_device *dev, + case DRM_MODE_TV_MODE_PAL_N: + fallthrough; + case DRM_MODE_TV_MODE_SECAM: ++ fallthrough; ++ case DRM_MODE_TV_MODE_MONOCHROME: + analog = DRM_MODE_ANALOG_PAL; + break; -- if (rotation == 0) -+ if (rotation == 0) { - *orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL; -- else if (rotation == 90) -+ } else if (rotation == 90) { - *orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP; -- else if (rotation == 180) -+ } else if (rotation == 180) { - *orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP; -- else if (rotation == 270) -+ } else if (rotation == 270) { - *orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP; -- else -+ } else { -+ DRM_ERROR("%pOF: invalid orientation %d\n", np, ret); - return -EINVAL; -+ } - - return 0; - } diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c -index e5432dcf6999..f8eb1061a55f 100644 +index 3f479483d7d8..cb9c201250d5 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c -@@ -794,6 +794,84 @@ void drm_kms_helper_poll_fini(struct drm_device *dev) - } - EXPORT_SYMBOL(drm_kms_helper_poll_fini); - -+static bool -+_drm_connector_helper_hpd_irq_event(struct drm_connector *connector) -+{ -+ struct drm_device *dev = connector->dev; -+ enum drm_connector_status old_status; -+ u64 old_epoch_counter; -+ bool changed = false; -+ -+ /* Only handle HPD capable connectors. */ -+ drm_WARN_ON(dev, !(connector->polled & DRM_CONNECTOR_POLL_HPD)); -+ -+ drm_WARN_ON(dev, !mutex_is_locked(&dev->mode_config.mutex)); -+ -+ old_status = connector->status; -+ old_epoch_counter = connector->epoch_counter; -+ -+ DRM_DEBUG_KMS("CONNECTOR:%d:%s Old epoch counter %llu\n", -+ connector->base.id, -+ connector->name, -+ old_epoch_counter); -+ -+ connector->status = drm_helper_probe_detect(connector, NULL, -+ false); -+ DRM_DEBUG_KMS("CONNECTOR:%d:%s status updated from %s to %s\n", -+ connector->base.id, -+ connector->name, -+ drm_get_connector_status_name(old_status), -+ drm_get_connector_status_name(connector->status)); -+ -+ DRM_DEBUG_KMS("CONNECTOR:%d:%s New epoch counter %llu\n", -+ connector->base.id, -+ connector->name, -+ connector->epoch_counter); -+ -+ /* -+ * Check if epoch counter had changed, meaning that we need -+ * to send a uevent. -+ */ -+ if (old_epoch_counter != connector->epoch_counter) -+ changed = true; -+ -+ return changed; -+} -+ -+/** -+ * drm_connector_helper_hpd_irq_event - hotplug processing -+ * @connector: drm_connector -+ * -+ * Drivers can use this helper function to run a detect cycle on a connector -+ * which has the DRM_CONNECTOR_POLL_HPD flag set in its &polled member. -+ * -+ * This helper function is useful for drivers which can track hotplug -+ * interrupts for a single connector. -+ * -+ * This function must be called from process context with no mode -+ * setting locks held. -+ * -+ * Note that a connector can be both polled and probed from the hotplug -+ * handler, in case the hotplug interrupt is known to be unreliable. -+ */ -+bool drm_connector_helper_hpd_irq_event(struct drm_connector *connector) -+{ -+ struct drm_device *dev = connector->dev; -+ bool changed; -+ -+ mutex_lock(&dev->mode_config.mutex); -+ changed = _drm_connector_helper_hpd_irq_event(connector); -+ mutex_unlock(&dev->mode_config.mutex); -+ -+ if (changed) { -+ drm_kms_helper_hotplug_event(dev); -+ DRM_DEBUG_KMS("Sent hotplug event\n"); -+ } -+ -+ return changed; -+} -+EXPORT_SYMBOL(drm_connector_helper_hpd_irq_event); -+ - /** - * drm_helper_hpd_irq_event - hotplug processing - * @dev: drm_device -@@ -821,9 +899,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) - { - struct drm_connector *connector; - struct drm_connector_list_iter conn_iter; -- enum drm_connector_status old_status; - bool changed = false; -- u64 old_epoch_counter; - - if (!dev->mode_config.poll_enabled) - return false; -@@ -831,37 +907,8 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) - mutex_lock(&dev->mode_config.mutex); - drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { -- /* Only handle HPD capable connectors. */ -- if (!(connector->polled & DRM_CONNECTOR_POLL_HPD)) -- continue; -- -- old_status = connector->status; -- -- old_epoch_counter = connector->epoch_counter; -- -- DRM_DEBUG_KMS("CONNECTOR:%d:%s Old epoch counter %llu\n", connector->base.id, -- connector->name, -- old_epoch_counter); -- -- connector->status = drm_helper_probe_detect(connector, NULL, false); -- DRM_DEBUG_KMS("CONNECTOR:%d:%s status updated from %s to %s\n", -- connector->base.id, -- connector->name, -- drm_get_connector_status_name(old_status), -- drm_get_connector_status_name(connector->status)); -- -- DRM_DEBUG_KMS("CONNECTOR:%d:%s New epoch counter %llu\n", -- connector->base.id, -- connector->name, -- connector->epoch_counter); -- -- /* -- * Check if epoch counter had changed, meaning that we need -- * to send a uevent. -- */ -- if (old_epoch_counter != connector->epoch_counter) -+ if (_drm_connector_helper_hpd_irq_event(connector)) - changed = true; -- - } - drm_connector_list_iter_end(&conn_iter); - mutex_unlock(&dev->mode_config.mutex); -diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c -index 74946690aba4..743e57c1b44f 100644 ---- a/drivers/gpu/drm/drm_simple_kms_helper.c -+++ b/drivers/gpu/drm/drm_simple_kms_helper.c -@@ -86,20 +86,22 @@ drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc, - } - - 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; -@@ -113,7 +115,7 @@ static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc, - } - - 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 --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c -index 1c03485676ef..4153f302de7c 100644 ---- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c -+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c -@@ -19,7 +19,7 @@ - #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); - -@@ -30,7 +30,7 @@ static void exynos_drm_crtc_atomic_enable(struct drm_crtc *crtc, - } - - 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); - -@@ -49,21 +49,23 @@ static void exynos_drm_crtc_atomic_disable(struct drm_crtc *crtc, - } - - 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; +@@ -1247,8 +1247,9 @@ int drm_connector_helper_tv_get_modes(struct drm_connector *connector) + for (i = 0; i < tv_mode_property->num_values; i++) + supported_tv_modes |= BIT(tv_mode_property->valuesi); + +- if ((supported_tv_modes & ntsc_modes) && +- (supported_tv_modes & pal_modes)) { ++ if (((supported_tv_modes & ntsc_modes) && ++ (supported_tv_modes & pal_modes)) || ++ (supported_tv_modes & BIT(DRM_MODE_TV_MODE_MONOCHROME))) { + uint64_t default_mode; + + if (drm_object_property_get_default_value(&connector->base, +diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c +index 2e8f17c04522..ff9b9918b0a1 100644 +--- a/drivers/gpu/drm/i915/display/intel_backlight.c ++++ b/drivers/gpu/drm/i915/display/intel_backlight.c +@@ -274,7 +274,7 @@ static void ext_pwm_set_backlight(const struct drm_connector_state *conn_state, + struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel; + + pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); +- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); ++ pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state); } - 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); + static void +@@ -427,7 +427,7 @@ static void ext_pwm_disable_backlight(const struct drm_connector_state *old_conn + intel_backlight_set_pwm_level(old_conn_state, level); -@@ -72,7 +74,7 @@ static void exynos_crtc_atomic_begin(struct drm_crtc *crtc, + panel->backlight.pwm_state.enabled = false; +- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); ++ pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state); } - 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 --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c -index b9ca81a6f80f..2af60d98f48f 100644 ---- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c -+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c -@@ -21,7 +21,7 @@ - #include "fsl_dcu_drm_plane.h" + void intel_backlight_disable(const struct drm_connector_state *old_conn_state) +@@ -749,7 +749,7 @@ static void ext_pwm_enable_backlight(const struct intel_crtc_state *crtc_state, - 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; -@@ -43,8 +43,10 @@ static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc, + pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); + panel->backlight.pwm_state.enabled = true; +- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); ++ pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state); } - 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; + static void __intel_backlight_enable(const struct intel_crtc_state *crtc_state, +diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c +index a072fbb9872a..066a3cd74df1 100644 +--- a/drivers/gpu/drm/i915/display/intel_display.c ++++ b/drivers/gpu/drm/i915/display/intel_display.c +@@ -7267,6 +7267,19 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state, + state->base.legacy_cursor_update = false; + } -@@ -62,7 +64,7 @@ static void fsl_dcu_drm_crtc_atomic_disable(struct drm_crtc *crtc, - } ++ /* ++ * FIXME: Cut over to (async) commit helpers instead of hand-rolling ++ * everything. ++ */ ++ if (state->base.legacy_cursor_update) { ++ struct intel_crtc_state *new_crtc_state; ++ struct intel_crtc *crtc; ++ int i; ++ ++ for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) ++ complete_all(&new_crtc_state->uapi.commit->flip_done); ++ } ++ + ret = intel_atomic_prepare_commit(state); + if (ret) { + drm_dbg_atomic(&dev_priv->drm, +diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c +index 9c45d641b521..5c8e5611304f 100644 +--- a/drivers/gpu/drm/msm/msm_atomic.c ++++ b/drivers/gpu/drm/msm/msm_atomic.c +@@ -242,6 +242,8 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state) + /* async updates are limited to single-crtc updates: */ + WARN_ON(crtc_mask != drm_crtc_mask(async_crtc)); - 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 --git a/drivers/gpu/drm/gud/Kconfig b/drivers/gpu/drm/gud/Kconfig -new file mode 100644 -index 000000000000..1c8601bf4d91 ---- /dev/null -+++ b/drivers/gpu/drm/gud/Kconfig -@@ -0,0 +1,14 @@ -+# SPDX-License-Identifier: GPL-2.0 ++ complete_all(&async_crtc->state->commit->flip_done); + -+config DRM_GUD -+ tristate "GUD USB Display" -+ depends on DRM && USB -+ select LZ4_COMPRESS + /* + * Start timer if we don't already have an update pending + * on this crtc: +diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig +index 869e535faefa..d3109ea534fe 100644 +--- a/drivers/gpu/drm/panel/Kconfig ++++ b/drivers/gpu/drm/panel/Kconfig +@@ -194,6 +194,17 @@ config DRM_PANEL_ILITEK_ILI9341 + QVGA (240x320) RGB panels. support serial & parallel rgb + interface. + ++config DRM_PANEL_ILITEK_ILI9806E ++ tristate "Ilitek ILI9806E-based panels" ++ depends on OF && SPI + select DRM_KMS_HELPER -+ select DRM_GEM_SHMEM_HELPER -+ select BACKLIGHT_CLASS_DEVICE ++ depends on DRM_GEM_DMA_HELPER ++ depends on BACKLIGHT_CLASS_DEVICE ++ select DRM_MIPI_DBI + help -+ This is a DRM display driver for GUD USB Displays or display -+ adapters. ++ Say Y if you want to enable support for panels based on the ++ Ilitek ILI9806e controller. + -+ If M is selected the module will be called gud. -diff --git a/drivers/gpu/drm/gud/Makefile b/drivers/gpu/drm/gud/Makefile -new file mode 100644 -index 000000000000..68a1c622cf33 ---- /dev/null -+++ b/drivers/gpu/drm/gud/Makefile -@@ -0,0 +1,4 @@ -+# SPDX-License-Identifier: GPL-2.0 + config DRM_PANEL_ILITEK_ILI9881C + tristate "Ilitek ILI9881C-based panels" + depends on OF +@@ -756,6 +767,17 @@ config DRM_PANEL_TDO_TL070WSH30 + 24 bit RGB per pixel. It provides a MIPI DSI interface to + the host, a built-in LED backlight and touch controller. + ++config DRM_PANEL_TPO_Y17P ++ tristate "TDO Y17P-based panels" ++ depends on OF && SPI ++ select DRM_KMS_HELPER ++ depends on DRM_GEM_DMA_HELPER ++ depends on BACKLIGHT_CLASS_DEVICE ++ select DRM_MIPI_DBI ++ help ++ Say Y if you want to enable support for panels based on the ++ TDO Y17P controller. + -+gud-y := gud_drv.o gud_pipe.o gud_connector.o -+obj-$(CONFIG_DRM_GUD) += gud.o -diff --git a/drivers/gpu/drm/gud/gud_connector.c b/drivers/gpu/drm/gud/gud_connector.c + config DRM_PANEL_TPO_TD028TTEC1 + tristate "Toppoly (TPO) TD028TTEC1 panel driver" + depends on OF && SPI +@@ -816,6 +838,16 @@ config DRM_PANEL_VISIONOX_R66451 + Say Y here if you want to enable support for Visionox + R66451 1080x2340 AMOLED DSI panel. + ++config DRM_PANEL_WAVESHARE_TOUCHSCREEN ++ tristate "Waveshare touchscreen panels" ++ depends on DRM_MIPI_DSI ++ depends on I2C ++ depends on BACKLIGHT_CLASS_DEVICE ++ help ++ Say Y here if you want to enable support for the Waveshare ++ DSI Touchscreens. To compile this driver as a module, ++ choose M here. ++ + config DRM_PANEL_WIDECHIPS_WS2401 + tristate "Widechips WS2401 DPI panel driver" + depends on SPI && GPIOLIB +diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile +index 433e93d57949..9dd9b3503802 100644 +--- a/drivers/gpu/drm/panel/Makefile ++++ b/drivers/gpu/drm/panel/Makefile +@@ -17,6 +17,7 @@ obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d + obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o + obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o + obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o ++obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9806E) += panel-ilitek-ili9806e.o + obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o + obj-$(CONFIG_DRM_PANEL_INNOLUX_EJ030NA) += panel-innolux-ej030na.o + obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o +@@ -76,6 +77,7 @@ obj-$(CONFIG_DRM_PANEL_SONY_TD4353_JDI) += panel-sony-td4353-jdi.o + obj-$(CONFIG_DRM_PANEL_SONY_TULIP_TRULY_NT35521) += panel-sony-tulip-truly-nt35521.o + obj-$(CONFIG_DRM_PANEL_STARTEK_KD070FHFID015) += panel-startek-kd070fhfid015.o + obj-$(CONFIG_DRM_PANEL_TDO_TL070WSH30) += panel-tdo-tl070wsh30.o ++obj-$(CONFIG_DRM_PANEL_TPO_Y17P) += panel-tdo-y17p.o + obj-$(CONFIG_DRM_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o + obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o + obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o +@@ -83,5 +85,6 @@ obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o + obj-$(CONFIG_DRM_PANEL_VISIONOX_RM69299) += panel-visionox-rm69299.o + obj-$(CONFIG_DRM_PANEL_VISIONOX_VTDR6130) += panel-visionox-vtdr6130.o + obj-$(CONFIG_DRM_PANEL_VISIONOX_R66451) += panel-visionox-r66451.o ++obj-$(CONFIG_DRM_PANEL_WAVESHARE_TOUCHSCREEN) += panel-waveshare-dsi.o + obj-$(CONFIG_DRM_PANEL_WIDECHIPS_WS2401) += panel-widechips-ws2401.o + obj-$(CONFIG_DRM_PANEL_XINPENG_XPP055C272) += panel-xinpeng-xpp055c272.o +diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9806e.c b/drivers/gpu/drm/panel/panel-ilitek-ili9806e.c new file mode 100644 -index 000000000000..ae051133e050 +index 000000000000..80e5bbe7a041 --- /dev/null -+++ b/drivers/gpu/drm/gud/gud_connector.c -@@ -0,0 +1,729 @@ -+// 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); -+} -+ ++++ b/drivers/gpu/drm/panel/panel-ilitek-ili9806e.c +@@ -0,0 +1,484 @@ ++// SPDX-License-Identifier: GPL-2.0-only +/* -+ * 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. ++ * Ilitek ILI9806E TFT LCD drm_panel driver. ++ * ++ * Copyright (C) 2022 Raspberry Pi Ltd ++ * ++ * Derived from drivers/drm/gpu/panel/panel-sitronix-st7789v.c ++ * Copyright (C) 2017 Free Electrons + */ -+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); ++#include <drm/drm_modes.h> ++#include <drm/drm_panel.h> + -+ /* The USB timeout is 5 seconds so use system_long_wq for worst case scenario */ -+ queue_work(system_long_wq, &gconn->backlight_work); ++#include <linux/bitops.h> ++#include <linux/gpio/consumer.h> ++#include <linux/media-bus-format.h> ++#include <linux/module.h> ++#include <linux/of_device.h> ++#include <linux/regmap.h> ++#include <linux/regulator/consumer.h> ++#include <linux/spi/spi.h> + -+ return 0; -+} ++#include <video/mipi_display.h> ++#include <video/of_videomode.h> ++#include <video/videomode.h> + -+static const struct backlight_ops gud_connector_backlight_ops = { -+ .update_status = gud_connector_backlight_update_status, ++struct ili9806 { ++ struct drm_panel panel; ++ struct spi_device *spi; ++ struct gpio_desc *reset; ++ struct regulator *power; ++ u32 bus_format; +}; + -+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); ++#define ILI9806_DATA BIT(8) + -+ gconn->backlight = bd; -+ -+ return 0; -+} ++#define ILI9806_MAX_MSG_LEN 6 + -+static int gud_connector_detect(struct drm_connector *connector, -+ struct drm_modeset_acquire_ctx *ctx, bool force) ++struct ili9806e_msg { ++ unsigned int len; ++ u16 msgILI9806_MAX_MSG_LEN; ++}; ++ ++#define ILI9806_SET_PAGE(page) \ ++ { \ ++ .len = 6, \ ++ .msg = { \ ++ 0xFF, \ ++ ILI9806_DATA | 0xFF, \ ++ ILI9806_DATA | 0x98, \ ++ ILI9806_DATA | 0x06, \ ++ ILI9806_DATA | 0x04, \ ++ ILI9806_DATA | (page) \ ++ }, \ ++ } ++ ++#define ILI9806_SET_REG_PARAM(reg, data) \ ++ { \ ++ .len = 2, \ ++ .msg = { \ ++ (reg), \ ++ ILI9806_DATA | (data), \ ++ }, \ ++ } ++ ++#define ILI9806_SET_REG(reg) \ ++ { \ ++ .len = 1, \ ++ .msg = { (reg) }, \ ++ } ++ ++static const struct ili9806e_msg panel_init = { ++ ILI9806_SET_PAGE(1), ++ ++ /* interface mode ++ * SEPT_SDIO = 0 (spi interface transfer through SDA pin) ++ * SDO_STATUS = 1 (always output, but without output tri-state) ++ */ ++ ILI9806_SET_REG_PARAM(0x08, 0x10), ++ /* display control ++ * VSPL = 1 (vertical sync polarity) ++ * HSPL = 0 (horizontal sync polarity) ++ * DPL = 0 (PCLK polarity) ++ * EPL = 1 (data enable polarity) ++ */ ++ ILI9806_SET_REG_PARAM(0x21, 0x0d), ++ /* resolution control (0x02 = 480x800) */ ++ ILI9806_SET_REG_PARAM(0x30, 0x02), ++ /* display inversion control (0x00 = column inversion) */ ++ ILI9806_SET_REG_PARAM(0x31, 0x00), ++ /* power control ++ * EXB1T = 0 (internal charge pump) ++ * EXT_CPCK_SEL = 1 (pump clock control signal = output 2 x waveform) ++ * BT = 0 (DDVDH / DDVDL voltage = VCI x 2 / VCI x -2) ++ */ ++ ILI9806_SET_REG_PARAM(0x40, 0x10), ++ /* power control ++ * DDVDH_CLP = 5.6 (DDVDH clamp leve) ++ * DDVDL_CLP = -5.6 (DDVDL clamp leve) ++ */ ++ ILI9806_SET_REG_PARAM(0x41, 0x55), ++ /* power control ++ * VGH_CP = 2DDVDH - DDVDL (step up factor for VGH) ++ * VGL_CP = DDVDL + VCL - VCIP (step up factor for VGL) ++ */ ++ ILI9806_SET_REG_PARAM(0x42, 0x02), ++ /* power control ++ * VGH_CLPEN = 0 (disable VGH clamp level) ++ * VGH_CLP = 9 (15.0 VGH clamp level - but this is disabled so not used?) ++ */ ++ ILI9806_SET_REG_PARAM(0x43, 0x84), ++ /* power control ++ * VGL_CLPEN = 0 (disable VGL clamp level) ++ * VGL_CLP = 9 (-11.0 VGL clamp level - but this is disabled so not used?) ++ */ ++ ILI9806_SET_REG_PARAM(0x44, 0x84), ++ ++ /* power control ++ * VREG1OUT voltage for positive gamma? ++ */ ++ ILI9806_SET_REG_PARAM(0x50, 0x78), ++ /* power control ++ * VREG2OUT voltage for negative gamma? ++ */ ++ ILI9806_SET_REG_PARAM(0x51, 0x78), ++ ++ ILI9806_SET_REG_PARAM(0x52, 0x00), ++ ILI9806_SET_REG_PARAM(0x53, 0x77), ++ ILI9806_SET_REG_PARAM(0x57, 0x60), ++ ILI9806_SET_REG_PARAM(0x60, 0x07), ++ ILI9806_SET_REG_PARAM(0x61, 0x00), ++ ILI9806_SET_REG_PARAM(0x62, 0x08), ++ ILI9806_SET_REG_PARAM(0x63, 0x00), ++ ILI9806_SET_REG_PARAM(0xA0, 0x00), ++ ILI9806_SET_REG_PARAM(0xA1, 0x07), ++ ILI9806_SET_REG_PARAM(0xA2, 0x0C), ++ ILI9806_SET_REG_PARAM(0xA3, 0x0B), ++ ILI9806_SET_REG_PARAM(0xA4, 0x03), ++ ILI9806_SET_REG_PARAM(0xA5, 0x07), ++ ILI9806_SET_REG_PARAM(0xA6, 0x06), ++ ILI9806_SET_REG_PARAM(0xA7, 0x04), ++ ILI9806_SET_REG_PARAM(0xA8, 0x08), ++ ILI9806_SET_REG_PARAM(0xA9, 0x0C), ++ ILI9806_SET_REG_PARAM(0xAA, 0x13), ++ ILI9806_SET_REG_PARAM(0xAB, 0x06), ++ ILI9806_SET_REG_PARAM(0xAC, 0x0D), ++ ILI9806_SET_REG_PARAM(0xAD, 0x19), ++ ILI9806_SET_REG_PARAM(0xAE, 0x10), ++ ILI9806_SET_REG_PARAM(0xAF, 0x00), ++ /* negative gamma control ++ * set the gray scale voltage to adjust the gamma characteristics of the panel ++ */ ++ ILI9806_SET_REG_PARAM(0xC0, 0x00), ++ ILI9806_SET_REG_PARAM(0xC1, 0x07), ++ ILI9806_SET_REG_PARAM(0xC2, 0x0C), ++ ILI9806_SET_REG_PARAM(0xC3, 0x0B), ++ ILI9806_SET_REG_PARAM(0xC4, 0x03), ++ ILI9806_SET_REG_PARAM(0xC5, 0x07), ++ ILI9806_SET_REG_PARAM(0xC6, 0x07), ++ ILI9806_SET_REG_PARAM(0xC7, 0x04), ++ ILI9806_SET_REG_PARAM(0xC8, 0x08), ++ ILI9806_SET_REG_PARAM(0xC9, 0x0C), ++ ILI9806_SET_REG_PARAM(0xCA, 0x13), ++ ILI9806_SET_REG_PARAM(0xCB, 0x06), ++ ILI9806_SET_REG_PARAM(0xCC, 0x0D), ++ ILI9806_SET_REG_PARAM(0xCD, 0x18), ++ ILI9806_SET_REG_PARAM(0xCE, 0x10), ++ ILI9806_SET_REG_PARAM(0xCF, 0x00), ++ ++ ILI9806_SET_PAGE(6), ++ ++ ILI9806_SET_REG_PARAM(0x00, 0x20), ++ ILI9806_SET_REG_PARAM(0x01, 0x0A), ++ ILI9806_SET_REG_PARAM(0x02, 0x00), ++ ILI9806_SET_REG_PARAM(0x03, 0x00), ++ ILI9806_SET_REG_PARAM(0x04, 0x01), ++ ILI9806_SET_REG_PARAM(0x05, 0x01), ++ ILI9806_SET_REG_PARAM(0x06, 0x98), ++ ILI9806_SET_REG_PARAM(0x07, 0x06), ++ ILI9806_SET_REG_PARAM(0x08, 0x01), ++ ILI9806_SET_REG_PARAM(0x09, 0x80), ++ ILI9806_SET_REG_PARAM(0x0A, 0x00), ++ ILI9806_SET_REG_PARAM(0x0B, 0x00), ++ ILI9806_SET_REG_PARAM(0x0C, 0x01), ++ ILI9806_SET_REG_PARAM(0x0D, 0x01), ++ ILI9806_SET_REG_PARAM(0x0E, 0x00), ++ ILI9806_SET_REG_PARAM(0x0F, 0x00), ++ ILI9806_SET_REG_PARAM(0x10, 0xF0), ++ ILI9806_SET_REG_PARAM(0x11, 0xF4), ++ ILI9806_SET_REG_PARAM(0x12, 0x01), ++ ILI9806_SET_REG_PARAM(0x13, 0x00), ++ ILI9806_SET_REG_PARAM(0x14, 0x00), ++ ILI9806_SET_REG_PARAM(0x15, 0xC0), ++ ILI9806_SET_REG_PARAM(0x16, 0x08), ++ ILI9806_SET_REG_PARAM(0x17, 0x00), ++ ILI9806_SET_REG_PARAM(0x18, 0x00), ++ ILI9806_SET_REG_PARAM(0x19, 0x00), ++ ILI9806_SET_REG_PARAM(0x1A, 0x00), ++ ILI9806_SET_REG_PARAM(0x1B, 0x00), ++ ILI9806_SET_REG_PARAM(0x1C, 0x00), ++ ILI9806_SET_REG_PARAM(0x1D, 0x00), ++ ILI9806_SET_REG_PARAM(0x20, 0x01), ++ ILI9806_SET_REG_PARAM(0x21, 0x23), ++ ILI9806_SET_REG_PARAM(0x22, 0x45), ++ ILI9806_SET_REG_PARAM(0x23, 0x67), ++ ILI9806_SET_REG_PARAM(0x24, 0x01), ++ ILI9806_SET_REG_PARAM(0x25, 0x23), ++ ILI9806_SET_REG_PARAM(0x26, 0x45), ++ ILI9806_SET_REG_PARAM(0x27, 0x67), ++ ILI9806_SET_REG_PARAM(0x30, 0x11), ++ ILI9806_SET_REG_PARAM(0x31, 0x11), ++ ILI9806_SET_REG_PARAM(0x32, 0x00), ++ ILI9806_SET_REG_PARAM(0x33, 0xEE), ++ ILI9806_SET_REG_PARAM(0x34, 0xFF), ++ ILI9806_SET_REG_PARAM(0x35, 0xBB), ++ ILI9806_SET_REG_PARAM(0x36, 0xAA), ++ ILI9806_SET_REG_PARAM(0x37, 0xDD), ++ ILI9806_SET_REG_PARAM(0x38, 0xCC), ++ ILI9806_SET_REG_PARAM(0x39, 0x66), ++ ILI9806_SET_REG_PARAM(0x3A, 0x77), ++ ILI9806_SET_REG_PARAM(0x3B, 0x22), ++ ILI9806_SET_REG_PARAM(0x3C, 0x22), ++ ILI9806_SET_REG_PARAM(0x3D, 0x22), ++ ILI9806_SET_REG_PARAM(0x3E, 0x22), ++ ILI9806_SET_REG_PARAM(0x3F, 0x22), ++ ILI9806_SET_REG_PARAM(0x40, 0x22), ++ /* register doesn't exist on page 6? */ ++ ILI9806_SET_REG_PARAM(0x52, 0x10), ++ /* doesn't make sense, not valid according to datasheet */ ++ ILI9806_SET_REG_PARAM(0x53, 0x10), ++ /* doesn't make sense, not valid according to datasheet */ ++ ILI9806_SET_REG_PARAM(0x54, 0x13), ++ ++ ILI9806_SET_PAGE(7), ++ ++ /* enable VREG */ ++ ILI9806_SET_REG_PARAM(0x18, 0x1D), ++ /* enable VGL_REG */ ++ ILI9806_SET_REG_PARAM(0x17, 0x22), ++ /* register doesn't exist on page 7? */ ++ ILI9806_SET_REG_PARAM(0x02, 0x77), ++ /* register doesn't exist on page 7? */ ++ ILI9806_SET_REG_PARAM(0x26, 0xB2), ++ /* register doesn't exist on page 7? */ ++ ILI9806_SET_REG_PARAM(0xE1, 0x79), ++ ++ ILI9806_SET_PAGE(0), ++ ++ ILI9806_SET_REG_PARAM(MIPI_DCS_SET_PIXEL_FORMAT, ++ MIPI_DCS_PIXEL_FMT_18BIT << 4), ++ ILI9806_SET_REG_PARAM(MIPI_DCS_SET_TEAR_ON, 0x00), ++ ILI9806_SET_REG(MIPI_DCS_EXIT_SLEEP_MODE), ++}; ++ ++#define NUM_INIT_REGS ARRAY_SIZE(panel_init) ++ ++static inline struct ili9806 *panel_to_ili9806(struct drm_panel *panel) ++{ ++ return container_of(panel, struct ili9806, panel); ++} ++ ++static int ili9806_write_msg(struct ili9806 *ctx, const struct ili9806e_msg *msg) ++{ ++ struct spi_transfer xfer = { }; ++ struct spi_message spi; ++ //u16 txbuf = { msg->, ILI9806_DATA | data }; ++ ++ spi_message_init(&spi); ++ ++ xfer.tx_buf = msg->msg; ++ xfer.bits_per_word = 9; ++ xfer.len = sizeof(u16) * msg->len; ++ ++ spi_message_add_tail(&xfer, &spi); ++ return spi_sync(ctx->spi, &spi); ++} ++ ++static int ili9806e_write_msg_list(struct ili9806 *ctx, ++ const struct ili9806e_msg msgs, ++ unsigned int num_msgs) +{ -+ 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; -+ } ++ int ret, i; + -+ 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; ++ for (i = 0; i < num_msgs; i++) { ++ ret = ili9806_write_msg(ctx, &msgsi); ++ if (ret) ++ 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, &reqmodesi); -+ 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, ++static const struct drm_display_mode ili9806e_480x800_mode = { ++ .clock = 32000, ++ .hdisplay = 480, ++ .hsync_start = 480 + 10, ++ .hsync_end = 480 + 10 + 16, ++ .htotal = 480 + 10 + 16 + 59, ++ .vdisplay = 800, ++ .vsync_start = 800 + 15, ++ .vsync_end = 800 + 15 + 113, ++ .vtotal = 800 + 15 + 113 + 15, ++ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, +}; + -+/* -+ * 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) ++static int ili9806_get_modes(struct drm_panel *panel, ++ struct drm_connector *connector) +{ -+ size_t buf_len = GUD_CONNECTOR_TV_MODE_MAX_NUM * GUD_CONNECTOR_TV_MODE_NAME_LEN; -+ const char *modesGUD_CONNECTOR_TV_MODE_MAX_NUM; -+ unsigned int i, num_modes; -+ char *buf; -+ int ret; ++ struct ili9806 *ctx = panel_to_ili9806(panel); ++ struct drm_display_mode *mode; + -+ buf = kmalloc(buf_len, GFP_KERNEL); -+ if (!buf) ++ mode = drm_mode_duplicate(connector->dev, &ili9806e_480x800_mode); ++ if (!mode) { ++ dev_err(panel->dev, "failed to add mode %ux%ux@%u\n", ++ ili9806e_480x800_mode.hdisplay, ++ ili9806e_480x800_mode.vdisplay, ++ drm_mode_vrefresh(&ili9806e_480x800_mode)); + 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++) -+ modesi = &bufi * GUD_CONNECTOR_TV_MODE_NAME_LEN; ++ drm_mode_set_name(mode); + -+ 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; -+} ++ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; ++ drm_mode_probed_add(connector, mode); + -+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); -+ } -+} ++ connector->display_info.width_mm = 61; ++ connector->display_info.height_mm = 103; ++ drm_display_info_set_bus_formats(&connector->display_info, ++ &ctx->bus_format, 1); ++ connector->display_info.bus_flags = ++ DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE; + -+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); -+ } ++ return 1; +} + -+static int gud_connector_add_properties(struct gud_device *gdrm, struct gud_connector *gconn) ++static int ili9806_prepare(struct drm_panel *panel) +{ -+ struct drm_connector *connector = &gconn->connector; -+ struct drm_device *drm = &gdrm->drm; -+ struct gud_property_req *properties; -+ unsigned int i, num_properties; ++ struct ili9806 *ctx = panel_to_ili9806(panel); + 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(propertiesi.prop); -+ u64 val = le64_to_cpu(propertiesi.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->propertiesgconn->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->propertiesi; -+ 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; -+ } -+ -+ propertiesi.prop = cpu_to_le16(prop); -+ propertiesi.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); ++ ret = regulator_enable(ctx->power); ++ if (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, &descsi); -+ if (ret) -+ goto free; -+ } -+free: -+ kfree(descs); ++ ret = ili9806e_write_msg_list(ctx, panel_init, NUM_INIT_REGS); + + return ret; +} -diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c -new file mode 100644 -index 000000000000..3afad229bb78 ---- /dev/null -+++ b/drivers/gpu/drm/gud/gud_drv.c -@@ -0,0 +1,696 @@ -+// 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) ++static int ili9806_enable(struct drm_panel *panel) +{ -+ void *buf; ++ struct ili9806 *ctx = panel_to_ili9806(panel); ++ const struct ili9806e_msg msg = ILI9806_SET_REG(MIPI_DCS_SET_DISPLAY_ON); + 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); ++ ret = ili9806_write_msg(ctx, &msg); + + 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) ++static int ili9806_disable(struct drm_panel *panel) +{ -+ u8 *buf; ++ struct ili9806 *ctx = panel_to_ili9806(panel); ++ const struct ili9806e_msg msg = ILI9806_SET_REG(MIPI_DCS_SET_DISPLAY_OFF); + 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; -+} ++ ret = ili9806_write_msg(ctx, &msg); + -+/* 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)); ++ return ret; +} + -+static int gud_get_properties(struct gud_device *gdrm) ++static int ili9806_unprepare(struct drm_panel *panel) +{ -+ struct gud_property_req *properties; -+ unsigned int i, num_properties; ++ struct ili9806 *ctx = panel_to_ili9806(panel); ++ const struct ili9806e_msg msg = ILI9806_SET_REG(MIPI_DCS_ENTER_SLEEP_MODE); + 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(propertiesi.prop); -+ u64 val = le64_to_cpu(propertiesi.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->propertiesgdrm->num_properties++ = prop; -+ } -+out: -+ kfree(properties); ++ ret = ili9806_write_msg(ctx, &msg); + + 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 buf10; -+ -+ 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 struct drm_panel_funcs ili9806_drm_funcs = { ++ .disable = ili9806_disable, ++ .enable = ili9806_enable, ++ .get_modes = ili9806_get_modes, ++ .prepare = ili9806_prepare, ++ .unprepare = ili9806_unprepare, +}; + -+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 const struct of_device_id ili9806_of_match = { ++ { .compatible = "txw,txw397017s2", ++ .data = (void *)MEDIA_BUS_FMT_RGB888_1X24, ++ }, { ++ .compatible = "pimoroni,hyperpixel4", ++ .data = (void *)MEDIA_BUS_FMT_RGB666_1X24_CPADHI, ++ }, { ++ .compatible = "ilitek,ili9806e", ++ .data = (void *)MEDIA_BUS_FMT_RGB888_1X24, ++ }, { ++ /* sentinel */ ++ } +}; ++MODULE_DEVICE_TABLE(of, ili9806_of_match); + -+static int gud_alloc_bulk_buffer(struct gud_device *gdrm) ++static int ili9806_probe(struct spi_device *spi) +{ -+ unsigned int i, num_pages; -+ struct page **pages; -+ void *ptr; ++ const struct ili9806e_msg panel_reset = { ++ ILI9806_SET_PAGE(0), ++ ILI9806_SET_REG_PARAM(0x01, 0x00) ++ }; ++ const struct of_device_id *id; ++ struct ili9806 *ctx; + 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) ++ ctx = devm_kzalloc(&spi->dev, sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) + return -ENOMEM; + -+ for (i = 0, ptr = gdrm->bulk_buf; i < num_pages; i++, ptr += PAGE_SIZE) -+ pagesi = 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); ++ id = of_match_node(ili9806_of_match, spi->dev.of_node); ++ if (!id) + 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_devi); -+ if (!format) { -+ drm_dbg(drm, "Unsupported format: 0x%02x\n", formats_devi); -+ 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 */ ++ ctx->bus_format = (u32)(uintptr_t)id->data; + -+ formatsnum_formats++ = format; -+ } ++ spi_set_drvdata(spi, ctx); ++ ctx->spi = spi; + -+ if (!num_formats && !xrgb8888_emulation_format) { -+ dev_err(dev, "No supported pixel formats found\n"); -+ return -EINVAL; -+ } ++ drm_panel_init(&ctx->panel, &spi->dev, &ili9806_drm_funcs, ++ DRM_MODE_CONNECTOR_DPI); + -+ /* Prefer speed over color depth */ -+ if (rgb565_supported) -+ drm->mode_config.preferred_depth = 16; ++ ctx->power = devm_regulator_get(&spi->dev, "power"); ++ if (IS_ERR(ctx->power)) ++ return PTR_ERR(ctx->power); + -+ if (!xrgb8888_supported && xrgb8888_emulation_format) { -+ gdrm->xrgb8888_emulation_format = xrgb8888_emulation_format; -+ formatsnum_formats++ = DRM_FORMAT_XRGB8888; ++ ctx->reset = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW); ++ if (IS_ERR(ctx->reset)) { ++ dev_err(&spi->dev, "Couldn't get our reset line\n"); ++ return PTR_ERR(ctx->reset); + } + -+ 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; -+ } ++ /* Soft reset */ ++ ili9806e_write_msg_list(ctx, panel_reset, ARRAY_SIZE(panel_reset)); ++ msleep(200); + -+ ret = drm_simple_display_pipe_init(drm, &gdrm->pipe, &gud_pipe_funcs, -+ formats, num_formats, -+ gud_pipe_modifiers, NULL); ++ ret = drm_panel_of_backlight(&ctx->panel); + 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); ++ drm_panel_add(&ctx->panel); + + 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) ++static void ili9806_remove(struct spi_device *spi) +{ -+ struct gud_device *gdrm = usb_get_intfdata(intf); -+ -+ drm_mode_config_helper_resume(&gdrm->drm); ++ struct ili9806 *ctx = spi_get_drvdata(spi); + -+ return 0; ++ drm_panel_remove(&ctx->panel); +} + -+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 --git a/drivers/gpu/drm/gud/gud_internal.h b/drivers/gpu/drm/gud/gud_internal.h -new file mode 100644 -index 000000000000..2a388e27d5d7 ---- /dev/null -+++ b/drivers/gpu/drm/gud/gud_internal.h -@@ -0,0 +1,156 @@ -+/* 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 const struct spi_device_id ili9806_ids = { ++ { "txw397017s2", 0 }, ++ { "ili9806e", 0 }, ++ { "hyperpixel4", 0 }, ++ { /* sentinel */ } +}; + -+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 --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c -new file mode 100644 -index 000000000000..d04e777ccb37 ---- /dev/null -+++ b/drivers/gpu/drm/gud/gud_pipe.c -@@ -0,0 +1,601 @@ -+// 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_block0 != 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->pitches0); -+ 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->obj0->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->obj0); -+ if (!vmap) -+ return -ENOMEM; -+ -+ vaddr = vmap + fb->offsets0; -+ -+ 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->cpp0 > 1) { -+ drm_fb_swab(buf, vaddr, fb, rect, !import_attach); -+ } else if (compression && !import_attach && pitch == fb->pitches0) { -+ /* 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->obj0, vmap); ++MODULE_DEVICE_TABLE(spi, ili9806_ids); + -+ return ret; -+} -+ -+struct gud_usb_bulk_context { -+ struct timer_list timer; -+ struct usb_sg_request sgr; ++static struct spi_driver ili9806_driver = { ++ .probe = ili9806_probe, ++ .remove = ili9806_remove, ++ .driver = { ++ .name = "ili9806e", ++ .of_match_table = ili9806_of_match, ++ }, ++ .id_table = ili9806_ids, +}; ++module_spi_driver(ili9806_driver); + -+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->propertiesi; -+ 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->propertiesnum_properties + i.prop = cpu_to_le16(prop); -+ req->propertiesnum_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 --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c -index 4d57ec688f82..567f578740bd 100644 ---- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c -+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c -@@ -172,7 +172,7 @@ static void hibmc_crtc_dpms(struct drm_crtc *crtc, int dpms) - } - - 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; -@@ -191,7 +191,7 @@ static void hibmc_crtc_atomic_enable(struct drm_crtc *crtc, - } - - 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; -@@ -393,7 +393,7 @@ static void hibmc_crtc_mode_set_nofb(struct drm_crtc *crtc) - } - - 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; -@@ -413,7 +413,7 @@ static void hibmc_crtc_atomic_begin(struct drm_crtc *crtc, - } - - 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 --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c -index e1108c1735ad..d84d41f3e78f 100644 ---- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c -+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c -@@ -436,7 +436,7 @@ static void ade_dump_regs(void __iomem *base) { } - #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; -@@ -459,7 +459,7 @@ static void ade_crtc_atomic_enable(struct drm_crtc *crtc, - } - - 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; -@@ -485,7 +485,7 @@ static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc) - } - - 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; -@@ -498,7 +498,7 @@ static void ade_crtc_atomic_begin(struct drm_crtc *crtc, - } - - 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 --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c -index 86be032bcf96..b18417a393af 100644 ---- a/drivers/gpu/drm/i915/display/intel_atomic.c -+++ b/drivers/gpu/drm/i915/display/intel_atomic.c -@@ -109,16 +109,6 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector, - 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) - { -@@ -150,8 +140,7 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn, - 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 --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c -index 406e96785c76..d1f8c7f3d197 100644 ---- a/drivers/gpu/drm/i915/display/intel_connector.c -+++ b/drivers/gpu/drm/i915/display/intel_connector.c -@@ -297,6 +297,5 @@ intel_attach_colorspace_property(struct drm_connector *connector) - return; - } - -- drm_object_attach_property(&connector->base, -- connector->colorspace_property, 0); -+ drm_connector_attach_colorspace_property(connector); - } -diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c -index 45c2556d6395..32f440223bd1 100644 ---- a/drivers/gpu/drm/i915/display/intel_display.c -+++ b/drivers/gpu/drm/i915/display/intel_display.c -@@ -16562,7 +16562,6 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv, - } - - #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 --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c -index ecaa538b2d35..3e5558def1c5 100644 ---- a/drivers/gpu/drm/i915/display/intel_dp_mst.c -+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c -@@ -23,6 +23,7 @@ - * - */ - -+#include <drm/drm_atomic.h> - #include <drm/drm_atomic_helper.h> - #include <drm/drm_edid.h> - #include <drm/drm_probe_helper.h> -@@ -708,11 +709,13 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, - } - - 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_encoderscrtc->pipe->base.base; - } -diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c -index 1d616da4f165..030b4d5ab829 100644 ---- a/drivers/gpu/drm/i915/display/intel_hdmi.c -+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c -@@ -746,7 +746,7 @@ intel_hdmi_compute_avi_infoframe(struct intel_encoder *encoder, - else - frame->colorspace = HDMI_COLORSPACE_RGB; - -- drm_hdmi_avi_infoframe_colorspace(frame, conn_state); -+ drm_hdmi_avi_infoframe_colorimetry(frame, conn_state); - - /* nonsense combination */ - drm_WARN_ON(encoder->base.dev, crtc_state->limited_color_range && -@@ -2971,8 +2971,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c - 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 --git a/drivers/gpu/drm/imx/dcss/dcss-crtc.c b/drivers/gpu/drm/imx/dcss/dcss-crtc.c -index 36abff0890b2..31267c00782f 100644 ---- a/drivers/gpu/drm/imx/dcss/dcss-crtc.c -+++ b/drivers/gpu/drm/imx/dcss/dcss-crtc.c -@@ -3,6 +3,7 @@ - * Copyright 2019 NXP. - */ - -+#include <drm/drm_atomic.h> - #include <drm/drm_atomic_helper.h> - #include <drm/drm_vblank.h> - #include <linux/platform_device.h> -@@ -52,13 +53,13 @@ static const struct drm_crtc_funcs dcss_crtc_funcs = { - }; - - 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); -@@ -77,8 +78,10 @@ static void dcss_crtc_atomic_flush(struct drm_crtc *crtc, - } - - 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; -@@ -111,8 +114,10 @@ static void dcss_crtc_atomic_enable(struct drm_crtc *crtc, - } - - 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 --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c -index d412fc265395..7ebd99ee3240 100644 ---- a/drivers/gpu/drm/imx/ipuv3-crtc.c -+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c -@@ -47,7 +47,7 @@ static inline struct ipu_crtc *to_ipu_crtc(struct drm_crtc *crtc) - } - - 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); -@@ -79,8 +79,10 @@ static void ipu_crtc_disable_planes(struct ipu_crtc *ipu_crtc, - } - - 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); - -@@ -225,24 +227,26 @@ static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc, - } - - 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 --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c -index b6bb5fc7d183..0f52e5f4aa2f 100644 ---- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c -+++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c -@@ -112,7 +112,7 @@ static inline struct ingenic_drm *drm_crtc_get_priv(struct drm_crtc *crtc) - } - - 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); - -@@ -126,7 +126,7 @@ static void ingenic_drm_crtc_atomic_enable(struct drm_crtc *crtc, - } - - 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; -@@ -195,22 +195,27 @@ static void ingenic_drm_crtc_update_timings(struct ingenic_drm *priv, - } - - 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); - -@@ -248,7 +253,7 @@ ingenic_drm_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode - } - - 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; -@@ -268,20 +273,20 @@ static void ingenic_drm_crtc_atomic_begin(struct drm_crtc *crtc, - } - - 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) -@@ -642,8 +647,6 @@ static const struct drm_crtc_funcs ingenic_drm_crtc_funcs = { - - .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 --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c -index dfd5ed15a7f4..3d698cd10626 100644 ---- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c -+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c -@@ -517,7 +517,7 @@ void mtk_drm_crtc_async_update(struct drm_crtc *crtc, struct drm_plane *plane, - } - - 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_comp0; -@@ -542,7 +542,7 @@ static void mtk_drm_crtc_atomic_enable(struct drm_crtc *crtc, - } - - 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_comp0; -@@ -575,24 +575,24 @@ static void mtk_drm_crtc_atomic_disable(struct drm_crtc *crtc, - } - - 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; -@@ -614,7 +614,6 @@ static const struct drm_crtc_funcs mtk_crtc_funcs = { - .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 --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c -index 2854272dc2d9..d70616da8ce2 100644 ---- a/drivers/gpu/drm/meson/meson_crtc.c -+++ b/drivers/gpu/drm/meson/meson_crtc.c -@@ -82,7 +82,7 @@ static const struct drm_crtc_funcs meson_crtc_funcs = { - }; - - 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; -@@ -118,7 +118,7 @@ static void meson_g12a_crtc_atomic_enable(struct drm_crtc *crtc, - } - - 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; -@@ -146,7 +146,7 @@ static void meson_crtc_atomic_enable(struct drm_crtc *crtc, - } - - 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; -@@ -171,7 +171,7 @@ static void meson_g12a_crtc_atomic_disable(struct drm_crtc *crtc, - } - - 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; -@@ -201,7 +201,7 @@ static void meson_crtc_atomic_disable(struct drm_crtc *crtc, - } - - 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; -@@ -217,7 +217,7 @@ static void meson_crtc_atomic_begin(struct drm_crtc *crtc, - } - - 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 --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c -index f56414a06ec4..5bc1ead269d3 100644 ---- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c -+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c -@@ -11,6 +11,7 @@ - #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> -@@ -485,7 +486,7 @@ static void _dpu_crtc_setup_cp_blocks(struct drm_crtc *crtc) - } - - 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; -@@ -526,7 +527,7 @@ static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, - } - - 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; -@@ -706,10 +707,12 @@ static struct drm_crtc_state *dpu_crtc_duplicate_state(struct drm_crtc *crtc) - } - - 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; -@@ -770,7 +773,7 @@ static void dpu_crtc_disable(struct drm_crtc *crtc, - } - - 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; -@@ -812,10 +815,12 @@ struct plane_state { - }; - - 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; -@@ -832,32 +837,33 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc, - - 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)) { -@@ -963,7 +969,7 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc, - - 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 --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c -index a0253297bc76..34e3186e236d 100644 ---- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c -+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c -@@ -264,7 +264,7 @@ static void mdp4_crtc_mode_set_nofb(struct drm_crtc *crtc) - } - - 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); -@@ -284,7 +284,7 @@ static void mdp4_crtc_atomic_disable(struct drm_crtc *crtc, - } - - 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); -@@ -307,7 +307,7 @@ static void mdp4_crtc_atomic_enable(struct drm_crtc *crtc, - } - - 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); -@@ -316,14 +316,14 @@ static int mdp4_crtc_atomic_check(struct drm_crtc *crtc, - } - - 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 --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c -index a8fa084dfa49..58dd302950d9 100644 ---- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c -+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c -@@ -7,6 +7,7 @@ - - #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> -@@ -483,7 +484,7 @@ static u32 mdp5_crtc_get_vblank_counter(struct drm_crtc *crtc) - } - - 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); -@@ -529,7 +530,7 @@ static void mdp5_crtc_vblank_on(struct drm_crtc *crtc) - } - - 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); -@@ -682,15 +683,17 @@ static enum mdp_mixer_stage_id get_start_stage(struct drm_crtc *crtc, - } - - 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 pstatesSTAGE_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; -@@ -699,7 +702,7 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, - - 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; - -@@ -731,7 +734,7 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, - 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; -@@ -744,7 +747,7 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, - WARN_ON(cursor_plane && - (pstatescnt - 1.plane->type != DRM_PLANE_TYPE_CURSOR)); - -- start = get_start_stage(crtc, state, &pstates0.state->base); -+ start = get_start_stage(crtc, crtc_state, &pstates0.state->base); - - /* verify that there are not too many planes attached to crtc - * and that we don't have conflicting mixer stages: -@@ -769,13 +772,13 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, - } - - 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 --git a/drivers/gpu/drm/mxsfb/mxsfb_kms.c b/drivers/gpu/drm/mxsfb/mxsfb_kms.c -index b535621f4f78..d2f747d3695a 100644 ---- a/drivers/gpu/drm/mxsfb/mxsfb_kms.c -+++ b/drivers/gpu/drm/mxsfb/mxsfb_kms.c -@@ -310,21 +310,23 @@ static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) - } - - 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; - -@@ -343,7 +345,7 @@ static void mxsfb_crtc_atomic_flush(struct drm_crtc *crtc, - } - - 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; -@@ -367,7 +369,7 @@ static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc, - } - - 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 --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c -index c2d34c91e840..afd2736f040d 100644 ---- a/drivers/gpu/drm/nouveau/dispnv50/disp.c -+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c -@@ -32,6 +32,7 @@ - #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> -@@ -1161,8 +1162,10 @@ nv50_msto_new(struct drm_device *dev, struct nv50_head *head, int id) - - 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 --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c -index be649d14f879..32f80b69f9a7 100644 ---- a/drivers/gpu/drm/nouveau/dispnv50/head.c -+++ b/drivers/gpu/drm/nouveau/dispnv50/head.c -@@ -30,6 +30,7 @@ - #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> -@@ -315,12 +316,14 @@ nv50_head_atomic_check_mode(struct nv50_head *head, struct nv50_head_atom *asyh) - } - - 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; -@@ -503,7 +506,6 @@ nv50_head_destroy(struct drm_crtc *crtc) - 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, -@@ -518,7 +520,6 @@ nv50_head_func = { - 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 --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c -index 328a4a74f534..84101e27cfb7 100644 ---- a/drivers/gpu/drm/omapdrm/omap_crtc.c -+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c -@@ -436,7 +436,7 @@ static void omap_crtc_arm_event(struct drm_crtc *crtc) - } - - 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); -@@ -462,7 +462,7 @@ static void omap_crtc_atomic_enable(struct drm_crtc *crtc, - } - - 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); -@@ -569,22 +569,25 @@ static bool omap_crtc_is_manually_updated(struct drm_crtc *crtc) - } - - 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; -@@ -598,12 +601,12 @@ static int omap_crtc_atomic_check(struct drm_crtc *crtc, - } - - 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); -@@ -738,7 +741,6 @@ static const struct drm_crtc_funcs omap_crtc_funcs = { - .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, ++MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com>"); ++MODULE_DESCRIPTION("ili9806 LCD panel driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c -index 534dd7414d42..6e03d9b0be60 100644 +index 7838947a1bf3..971f8ee56308 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c -@@ -1,6 +1,8 @@ +@@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2017-2018, Bootlin + * Copyright (C) 2021, Henson Li <henson@cutiepi.io> + * Copyright (C) 2021, Penk Chen <penk@cutiepi.io> ++ * Copyright (C) 2022, Mark Williams <mark@crystalfontz.com> */ #include <linux/delay.h> -@@ -42,6 +44,7 @@ struct ili9881c_desc { - const struct ili9881c_instr *init; +@@ -42,6 +45,7 @@ struct ili9881c_desc { const size_t init_length; const struct drm_display_mode *mode; -+ const unsigned flags; + const unsigned long mode_flags; ++ unsigned int lanes; }; struct ili9881c { -@@ -453,6 +456,225 @@ static const struct ili9881c_instr k101_im2byl02_init = { +@@ -455,6 +459,228 @@ static const struct ili9881c_instr k101_im2byl02_init = { ILI9881C_COMMAND_INSTR(0xD3, 0x3F), /* VN0 */ }; @@ -57079,6 +74542,7 @@ + ILI9881C_COMMAND_INSTR(0x2D, 0x00), + ILI9881C_COMMAND_INSTR(0x2E, 0x00), + ILI9881C_COMMAND_INSTR(0x2F, 0x00), ++ + ILI9881C_COMMAND_INSTR(0x30, 0x00), + ILI9881C_COMMAND_INSTR(0x31, 0x00), + ILI9881C_COMMAND_INSTR(0x32, 0x00), @@ -57095,6 +74559,7 @@ + ILI9881C_COMMAND_INSTR(0x3D, 0x00), + ILI9881C_COMMAND_INSTR(0x3E, 0x00), + ILI9881C_COMMAND_INSTR(0x3F, 0x00), ++ + ILI9881C_COMMAND_INSTR(0x40, 0x00), + ILI9881C_COMMAND_INSTR(0x41, 0x00), + ILI9881C_COMMAND_INSTR(0x42, 0x00), @@ -57135,12 +74600,12 @@ + ILI9881C_COMMAND_INSTR(0x6D, 0x02), + ILI9881C_COMMAND_INSTR(0x6E, 0x07), + ILI9881C_COMMAND_INSTR(0x6F, 0x02), ++ + ILI9881C_COMMAND_INSTR(0x70, 0x02), + ILI9881C_COMMAND_INSTR(0x71, 0x02), + ILI9881C_COMMAND_INSTR(0x72, 0x02), + ILI9881C_COMMAND_INSTR(0x73, 0x02), + ILI9881C_COMMAND_INSTR(0x74, 0x02), -+ + ILI9881C_COMMAND_INSTR(0x75, 0x01), + ILI9881C_COMMAND_INSTR(0x76, 0x00), + ILI9881C_COMMAND_INSTR(0x77, 0x14), @@ -57152,6 +74617,7 @@ + ILI9881C_COMMAND_INSTR(0x7D, 0x06), + ILI9881C_COMMAND_INSTR(0x7E, 0x02), + ILI9881C_COMMAND_INSTR(0x7F, 0x02), ++ + ILI9881C_COMMAND_INSTR(0x80, 0x02), + ILI9881C_COMMAND_INSTR(0x81, 0x02), + ILI9881C_COMMAND_INSTR(0x82, 0x02), @@ -57248,74 +74714,828 @@ + ILI9881C_COMMAND_INSTR(0x35, 0x00), +}; + - static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel) - { - return container_of(panel, struct ili9881c, panel); -@@ -603,6 +825,23 @@ static const struct drm_display_mode k101_im2byl02_default_mode = { + static const struct ili9881c_instr tl050hdv35_init = { + ILI9881C_SWITCH_PAGE_INSTR(3), + ILI9881C_COMMAND_INSTR(0x01, 0x00), +@@ -830,17 +1056,604 @@ static const struct ili9881c_instr w552946ab_init = { + ILI9881C_SWITCH_PAGE_INSTR(0), + }; + +-static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel) +-{ +- return container_of(panel, struct ili9881c, panel); +-} ++static const struct ili9881c_instr cfaf7201280a0_050tx_init = { ++ //ILI9881C PAGE3 ++ ILI9881C_SWITCH_PAGE_INSTR(3), ++ //GIP_1 ++ ILI9881C_COMMAND_INSTR(0x01, 0x00), //added ++ ILI9881C_COMMAND_INSTR(0x02, 0x00), ++ ILI9881C_COMMAND_INSTR(0x03, 0x73), ++ ILI9881C_COMMAND_INSTR(0x04, 0x00), ++ ILI9881C_COMMAND_INSTR(0x05, 0x00), ++ ILI9881C_COMMAND_INSTR(0x06, 0x0A), ++ ILI9881C_COMMAND_INSTR(0x07, 0x00), ++ ILI9881C_COMMAND_INSTR(0x08, 0x00), ++ ILI9881C_COMMAND_INSTR(0x09, 0x01), ++ ILI9881C_COMMAND_INSTR(0x0A, 0x00), ++ ILI9881C_COMMAND_INSTR(0x0B, 0x00), ++ ILI9881C_COMMAND_INSTR(0x0C, 0x01), ++ ILI9881C_COMMAND_INSTR(0x0D, 0x00), ++ ILI9881C_COMMAND_INSTR(0x0E, 0x00), ++ ILI9881C_COMMAND_INSTR(0x0F, 0x1D), ++ ILI9881C_COMMAND_INSTR(0x10, 0x1D), ++ ILI9881C_COMMAND_INSTR(0x11, 0x00), ++ ILI9881C_COMMAND_INSTR(0x12, 0x00), ++ ILI9881C_COMMAND_INSTR(0x13, 0x00), ++ ILI9881C_COMMAND_INSTR(0x14, 0x00), ++ ILI9881C_COMMAND_INSTR(0x15, 0x00), ++ ILI9881C_COMMAND_INSTR(0x16, 0x00), ++ ILI9881C_COMMAND_INSTR(0x17, 0x00), ++ ILI9881C_COMMAND_INSTR(0x18, 0x00), ++ ILI9881C_COMMAND_INSTR(0x19, 0x00), ++ ILI9881C_COMMAND_INSTR(0x1A, 0x00), ++ ILI9881C_COMMAND_INSTR(0x1B, 0x00), ++ ILI9881C_COMMAND_INSTR(0x1C, 0x00), ++ ILI9881C_COMMAND_INSTR(0x1D, 0x00), ++ ILI9881C_COMMAND_INSTR(0x1E, 0x40), ++ ILI9881C_COMMAND_INSTR(0x1F, 0x80), ++ ILI9881C_COMMAND_INSTR(0x20, 0x06), ++ ILI9881C_COMMAND_INSTR(0x21, 0x02), ++ ILI9881C_COMMAND_INSTR(0x22, 0x00), ++ ILI9881C_COMMAND_INSTR(0x23, 0x00), ++ ILI9881C_COMMAND_INSTR(0x24, 0x00), ++ ILI9881C_COMMAND_INSTR(0x25, 0x00), ++ ILI9881C_COMMAND_INSTR(0x26, 0x00), ++ ILI9881C_COMMAND_INSTR(0x27, 0x00), ++ ILI9881C_COMMAND_INSTR(0x28, 0x33), ++ ILI9881C_COMMAND_INSTR(0x29, 0x03), ++ ILI9881C_COMMAND_INSTR(0x2A, 0x00), ++ ILI9881C_COMMAND_INSTR(0x2B, 0x00), ++ ILI9881C_COMMAND_INSTR(0x2C, 0x00), ++ ILI9881C_COMMAND_INSTR(0x2D, 0x00), ++ ILI9881C_COMMAND_INSTR(0x2E, 0x00), ++ ILI9881C_COMMAND_INSTR(0x2F, 0x00), ++ ILI9881C_COMMAND_INSTR(0x30, 0x00), ++ ILI9881C_COMMAND_INSTR(0x31, 0x00), ++ ILI9881C_COMMAND_INSTR(0x32, 0x00), ++ ILI9881C_COMMAND_INSTR(0x33, 0x00), ++ ILI9881C_COMMAND_INSTR(0x34, 0x04), ++ ILI9881C_COMMAND_INSTR(0x35, 0x00), ++ ILI9881C_COMMAND_INSTR(0x36, 0x00), ++ ILI9881C_COMMAND_INSTR(0x37, 0x00), ++ ILI9881C_COMMAND_INSTR(0x38, 0x3C), ++ ILI9881C_COMMAND_INSTR(0x39, 0x00), ++ ILI9881C_COMMAND_INSTR(0x3A, 0x40), ++ ILI9881C_COMMAND_INSTR(0x3B, 0x40), ++ ILI9881C_COMMAND_INSTR(0x3C, 0x00), ++ ILI9881C_COMMAND_INSTR(0x3D, 0x00), ++ ILI9881C_COMMAND_INSTR(0x3E, 0x00), ++ ILI9881C_COMMAND_INSTR(0x3F, 0x00), ++ ILI9881C_COMMAND_INSTR(0x40, 0x00), ++ ILI9881C_COMMAND_INSTR(0x41, 0x00), ++ ILI9881C_COMMAND_INSTR(0x42, 0x00), ++ ILI9881C_COMMAND_INSTR(0x43, 0x00), ++ ILI9881C_COMMAND_INSTR(0x44, 0x00), ++ //GIP_2 ++ ILI9881C_COMMAND_INSTR(0x50, 0x01), ++ ILI9881C_COMMAND_INSTR(0x51, 0x23), ++ ILI9881C_COMMAND_INSTR(0x52, 0x45), ++ ILI9881C_COMMAND_INSTR(0x53, 0x67), ++ ILI9881C_COMMAND_INSTR(0x54, 0x89), ++ ILI9881C_COMMAND_INSTR(0x55, 0xAB), ++ ILI9881C_COMMAND_INSTR(0x56, 0x01), ++ ILI9881C_COMMAND_INSTR(0x57, 0x23), ++ ILI9881C_COMMAND_INSTR(0x58, 0x45), ++ ILI9881C_COMMAND_INSTR(0x59, 0x67), ++ ILI9881C_COMMAND_INSTR(0x5A, 0x89), ++ ILI9881C_COMMAND_INSTR(0x5B, 0xAB), ++ ILI9881C_COMMAND_INSTR(0x5C, 0xCD), ++ ILI9881C_COMMAND_INSTR(0x5D, 0xEF), ++ //GIP_3 ++ ILI9881C_COMMAND_INSTR(0x5E, 0x11), ++ ILI9881C_COMMAND_INSTR(0x5F, 0x01), ++ ILI9881C_COMMAND_INSTR(0x60, 0x00), ++ ILI9881C_COMMAND_INSTR(0x61, 0x15), ++ ILI9881C_COMMAND_INSTR(0x62, 0x14), ++ ILI9881C_COMMAND_INSTR(0x63, 0x0E), ++ ILI9881C_COMMAND_INSTR(0x64, 0x0F), ++ ILI9881C_COMMAND_INSTR(0x65, 0x0C), ++ ILI9881C_COMMAND_INSTR(0x66, 0x0D), ++ ILI9881C_COMMAND_INSTR(0x67, 0x06), ++ ILI9881C_COMMAND_INSTR(0x68, 0x02), ++ ILI9881C_COMMAND_INSTR(0x69, 0x07), ++ ILI9881C_COMMAND_INSTR(0x6A, 0x02), ++ ILI9881C_COMMAND_INSTR(0x6B, 0x02), ++ ILI9881C_COMMAND_INSTR(0x6C, 0x02), ++ ILI9881C_COMMAND_INSTR(0x6D, 0x02), ++ ILI9881C_COMMAND_INSTR(0x6E, 0x02), ++ ILI9881C_COMMAND_INSTR(0x6F, 0x02), ++ ILI9881C_COMMAND_INSTR(0x70, 0x02), ++ ILI9881C_COMMAND_INSTR(0x71, 0x02), ++ ILI9881C_COMMAND_INSTR(0x72, 0x02), ++ ILI9881C_COMMAND_INSTR(0x73, 0x02), ++ ILI9881C_COMMAND_INSTR(0x74, 0x02), ++ ILI9881C_COMMAND_INSTR(0x75, 0x01), ++ ILI9881C_COMMAND_INSTR(0x76, 0x00), ++ ILI9881C_COMMAND_INSTR(0x77, 0x14), ++ ILI9881C_COMMAND_INSTR(0x78, 0x15), ++ ILI9881C_COMMAND_INSTR(0x79, 0x0E), ++ ILI9881C_COMMAND_INSTR(0x7A, 0x0F), ++ ILI9881C_COMMAND_INSTR(0x7B, 0x0C), ++ ILI9881C_COMMAND_INSTR(0x7C, 0x0D), ++ ILI9881C_COMMAND_INSTR(0x7D, 0x06), ++ ILI9881C_COMMAND_INSTR(0x7E, 0x02), ++ ILI9881C_COMMAND_INSTR(0x7F, 0x07), ++ ILI9881C_COMMAND_INSTR(0x80, 0x02), ++ ILI9881C_COMMAND_INSTR(0x81, 0x02), ++ ILI9881C_COMMAND_INSTR(0x82, 0x02), ++ ILI9881C_COMMAND_INSTR(0x83, 0x02), ++ ILI9881C_COMMAND_INSTR(0x84, 0x02), ++ ILI9881C_COMMAND_INSTR(0x85, 0x02), ++ ILI9881C_COMMAND_INSTR(0x86, 0x02), ++ ILI9881C_COMMAND_INSTR(0x87, 0x02), ++ ILI9881C_COMMAND_INSTR(0x88, 0x02), ++ ILI9881C_COMMAND_INSTR(0x89, 0x02), ++ ILI9881C_COMMAND_INSTR(0x8A, 0x02), ++ //ILI9881C PAGE4 ++ ILI9881C_SWITCH_PAGE_INSTR(4), ++ ILI9881C_COMMAND_INSTR(0x6C, 0x15), ++ ILI9881C_COMMAND_INSTR(0x6E, 0x2B), ++ // VGH & VGL OUTPUT ++ ILI9881C_COMMAND_INSTR(0x6F, 0x33), ++ ILI9881C_COMMAND_INSTR(0x8D, 0x18), ++ ILI9881C_COMMAND_INSTR(0x87, 0xBA), ++ ILI9881C_COMMAND_INSTR(0x26, 0x76), ++ //Reload Gamma setting ++ ILI9881C_COMMAND_INSTR(0xB2, 0xD1), ++ ILI9881C_COMMAND_INSTR(0xB5, 0x06), ++ ILI9881C_COMMAND_INSTR(0x3A, 0x24), ++ ILI9881C_COMMAND_INSTR(0x35, 0x1F), + +-/* +- * The panel seems to accept some private DCS commands that map +- * directly to registers. +- * +- * It is organised by page, with each page having its own set of +- * registers, and the first page looks like it's holding the standard ++ //ILI9881C PAGE1 ++ ILI9881C_SWITCH_PAGE_INSTR(1), ++ ILI9881C_COMMAND_INSTR(0x22, 0x09), ++ //Column inversion ++ ILI9881C_COMMAND_INSTR(0x31, 0x00), ++ ILI9881C_COMMAND_INSTR(0x40, 0x33), ++ ILI9881C_COMMAND_INSTR(0x53, 0xA2), ++ ILI9881C_COMMAND_INSTR(0x55, 0x92), ++ ILI9881C_COMMAND_INSTR(0x50, 0x96), ++ ILI9881C_COMMAND_INSTR(0x51, 0x96), ++ ILI9881C_COMMAND_INSTR(0x60, 0x22), ++ ILI9881C_COMMAND_INSTR(0x61, 0x00), ++ ILI9881C_COMMAND_INSTR(0x62, 0x19), ++ ILI9881C_COMMAND_INSTR(0x63, 0x00), ++ //---P-GAMMA START--- ++ ILI9881C_COMMAND_INSTR(0xA0, 0x08), ++ ILI9881C_COMMAND_INSTR(0xA1, 0x11), ++ ILI9881C_COMMAND_INSTR(0xA2, 0x19), ++ ILI9881C_COMMAND_INSTR(0xA3, 0x0D), ++ ILI9881C_COMMAND_INSTR(0xA4, 0x0D), ++ ILI9881C_COMMAND_INSTR(0xA5, 0x1E), ++ ILI9881C_COMMAND_INSTR(0xA6, 0x14), ++ ILI9881C_COMMAND_INSTR(0xA7, 0x17), ++ ILI9881C_COMMAND_INSTR(0xA8, 0x4F), ++ ILI9881C_COMMAND_INSTR(0xA9, 0x1A), ++ ILI9881C_COMMAND_INSTR(0xAA, 0x27), ++ ILI9881C_COMMAND_INSTR(0xAB, 0x49), ++ ILI9881C_COMMAND_INSTR(0xAC, 0x1A), ++ ILI9881C_COMMAND_INSTR(0xAD, 0x18), ++ ILI9881C_COMMAND_INSTR(0xAE, 0x4C), ++ ILI9881C_COMMAND_INSTR(0xAF, 0x22), ++ ILI9881C_COMMAND_INSTR(0xB0, 0x27), ++ ILI9881C_COMMAND_INSTR(0xB1, 0x4B), ++ ILI9881C_COMMAND_INSTR(0xB2, 0x60), ++ ILI9881C_COMMAND_INSTR(0xB3, 0x39), ++ //--- N-GAMMA START--- ++ ILI9881C_COMMAND_INSTR(0xC0, 0x08), ++ ILI9881C_COMMAND_INSTR(0xC1, 0x11), ++ ILI9881C_COMMAND_INSTR(0xC2, 0x19), ++ ILI9881C_COMMAND_INSTR(0xC3, 0x0D), ++ ILI9881C_COMMAND_INSTR(0xC4, 0x0D), ++ ILI9881C_COMMAND_INSTR(0xC5, 0x1E), ++ ILI9881C_COMMAND_INSTR(0xC6, 0x14), ++ ILI9881C_COMMAND_INSTR(0xC7, 0x17), ++ ILI9881C_COMMAND_INSTR(0xC8, 0x4F), ++ ILI9881C_COMMAND_INSTR(0xC9, 0x1A), ++ ILI9881C_COMMAND_INSTR(0xCA, 0x27), ++ ILI9881C_COMMAND_INSTR(0xCB, 0x49), ++ ILI9881C_COMMAND_INSTR(0xCC, 0x1A), ++ ILI9881C_COMMAND_INSTR(0xCD, 0x18), ++ ILI9881C_COMMAND_INSTR(0xCE, 0x4C), ++ ILI9881C_COMMAND_INSTR(0xCF, 0x33), ++ ILI9881C_COMMAND_INSTR(0xD0, 0x27), ++ ILI9881C_COMMAND_INSTR(0xD1, 0x4B), ++ ILI9881C_COMMAND_INSTR(0xD2, 0x60), ++ ILI9881C_COMMAND_INSTR(0xD3, 0x39), ++}; ++ ++static const struct ili9881c_instr rpi_5inch_init = { ++ ILI9881C_SWITCH_PAGE_INSTR(3), ++ ILI9881C_COMMAND_INSTR(0x01, 0x00), ++ ILI9881C_COMMAND_INSTR(0x02, 0x00), ++ ILI9881C_COMMAND_INSTR(0x03, 0x73), ++ ILI9881C_COMMAND_INSTR(0x04, 0x73), ++ ILI9881C_COMMAND_INSTR(0x05, 0x00), ++ ILI9881C_COMMAND_INSTR(0x06, 0x06), ++ ILI9881C_COMMAND_INSTR(0x07, 0x02), ++ ILI9881C_COMMAND_INSTR(0x08, 0x00), ++ ILI9881C_COMMAND_INSTR(0x09, 0x01), ++ ILI9881C_COMMAND_INSTR(0x0a, 0x01), ++ ILI9881C_COMMAND_INSTR(0x0b, 0x01), ++ ILI9881C_COMMAND_INSTR(0x0c, 0x01), ++ ILI9881C_COMMAND_INSTR(0x0d, 0x01), ++ ILI9881C_COMMAND_INSTR(0x0e, 0x01), ++ ILI9881C_COMMAND_INSTR(0x0f, 0x01), ++ ILI9881C_COMMAND_INSTR(0x10, 0x01), ++ ILI9881C_COMMAND_INSTR(0x11, 0x00), ++ ILI9881C_COMMAND_INSTR(0x12, 0x00), ++ ILI9881C_COMMAND_INSTR(0x13, 0x01), ++ ILI9881C_COMMAND_INSTR(0x14, 0x00), ++ ILI9881C_COMMAND_INSTR(0x15, 0x00), ++ ILI9881C_COMMAND_INSTR(0x16, 0x00), ++ ILI9881C_COMMAND_INSTR(0x17, 0x00), ++ ILI9881C_COMMAND_INSTR(0x18, 0x00), ++ ILI9881C_COMMAND_INSTR(0x19, 0x00), ++ ILI9881C_COMMAND_INSTR(0x1a, 0x00), ++ ILI9881C_COMMAND_INSTR(0x1b, 0x00), ++ ILI9881C_COMMAND_INSTR(0x1c, 0x00), ++ ILI9881C_COMMAND_INSTR(0x1d, 0x00), ++ ILI9881C_COMMAND_INSTR(0x1e, 0xc0), ++ ILI9881C_COMMAND_INSTR(0x1f, 0x80), ++ ILI9881C_COMMAND_INSTR(0x20, 0x04), ++ ILI9881C_COMMAND_INSTR(0x21, 0x03), ++ ILI9881C_COMMAND_INSTR(0x22, 0x00), ++ ILI9881C_COMMAND_INSTR(0x23, 0x00), ++ ILI9881C_COMMAND_INSTR(0x24, 0x00), ++ ILI9881C_COMMAND_INSTR(0x25, 0x00), ++ ILI9881C_COMMAND_INSTR(0x26, 0x00), ++ ILI9881C_COMMAND_INSTR(0x27, 0x00), ++ ILI9881C_COMMAND_INSTR(0x28, 0x33), ++ ILI9881C_COMMAND_INSTR(0x29, 0x03), ++ ILI9881C_COMMAND_INSTR(0x2a, 0x00), ++ ILI9881C_COMMAND_INSTR(0x2b, 0x00), ++ ILI9881C_COMMAND_INSTR(0x2c, 0x00), ++ ILI9881C_COMMAND_INSTR(0x2d, 0x00), ++ ILI9881C_COMMAND_INSTR(0x2e, 0x00), ++ ILI9881C_COMMAND_INSTR(0x2f, 0x00), ++ ILI9881C_COMMAND_INSTR(0x30, 0x00), ++ ILI9881C_COMMAND_INSTR(0x31, 0x00), ++ ILI9881C_COMMAND_INSTR(0x32, 0x00), ++ ILI9881C_COMMAND_INSTR(0x33, 0x00), ++ ILI9881C_COMMAND_INSTR(0x34, 0x03), ++ ILI9881C_COMMAND_INSTR(0x35, 0x00), ++ ILI9881C_COMMAND_INSTR(0x36, 0x03), ++ ILI9881C_COMMAND_INSTR(0x37, 0x00), ++ ILI9881C_COMMAND_INSTR(0x38, 0x00), ++ ILI9881C_COMMAND_INSTR(0x39, 0x00), ++ ILI9881C_COMMAND_INSTR(0x3a, 0x00), ++ ILI9881C_COMMAND_INSTR(0x3b, 0x00), ++ ILI9881C_COMMAND_INSTR(0x3c, 0x00), ++ ILI9881C_COMMAND_INSTR(0x3d, 0x00), ++ ILI9881C_COMMAND_INSTR(0x3e, 0x00), ++ ILI9881C_COMMAND_INSTR(0x3f, 0x00), ++ ILI9881C_COMMAND_INSTR(0x40, 0x00), ++ ILI9881C_COMMAND_INSTR(0x41, 0x00), ++ ILI9881C_COMMAND_INSTR(0x42, 0x00), ++ ILI9881C_COMMAND_INSTR(0x43, 0x00), ++ ILI9881C_COMMAND_INSTR(0x44, 0x00), ++ ILI9881C_COMMAND_INSTR(0x50, 0x01), ++ ILI9881C_COMMAND_INSTR(0x51, 0x23), ++ ILI9881C_COMMAND_INSTR(0x52, 0x45), ++ ILI9881C_COMMAND_INSTR(0x53, 0x67), ++ ILI9881C_COMMAND_INSTR(0x54, 0x89), ++ ILI9881C_COMMAND_INSTR(0x55, 0xab), ++ ILI9881C_COMMAND_INSTR(0x56, 0x01), ++ ILI9881C_COMMAND_INSTR(0x57, 0x23), ++ ILI9881C_COMMAND_INSTR(0x58, 0x45), ++ ILI9881C_COMMAND_INSTR(0x59, 0x67), ++ ILI9881C_COMMAND_INSTR(0x5a, 0x89), ++ ILI9881C_COMMAND_INSTR(0x5b, 0xab), ++ ILI9881C_COMMAND_INSTR(0x5c, 0xcd), ++ ILI9881C_COMMAND_INSTR(0x5d, 0xef), ++ ILI9881C_COMMAND_INSTR(0x5e, 0x10), ++ ILI9881C_COMMAND_INSTR(0x5f, 0x09), ++ ILI9881C_COMMAND_INSTR(0x60, 0x08), ++ ILI9881C_COMMAND_INSTR(0x61, 0x0f), ++ ILI9881C_COMMAND_INSTR(0x62, 0x0e), ++ ILI9881C_COMMAND_INSTR(0x63, 0x0d), ++ ILI9881C_COMMAND_INSTR(0x64, 0x0c), ++ ILI9881C_COMMAND_INSTR(0x65, 0x02), ++ ILI9881C_COMMAND_INSTR(0x66, 0x02), ++ ILI9881C_COMMAND_INSTR(0x67, 0x02), ++ ILI9881C_COMMAND_INSTR(0x68, 0x02), ++ ILI9881C_COMMAND_INSTR(0x69, 0x02), ++ ILI9881C_COMMAND_INSTR(0x6a, 0x02), ++ ILI9881C_COMMAND_INSTR(0x6b, 0x02), ++ ILI9881C_COMMAND_INSTR(0x6c, 0x02), ++ ILI9881C_COMMAND_INSTR(0x6d, 0x02), ++ ILI9881C_COMMAND_INSTR(0x6e, 0x02), ++ ILI9881C_COMMAND_INSTR(0x6f, 0x02), ++ ILI9881C_COMMAND_INSTR(0x70, 0x02), ++ ILI9881C_COMMAND_INSTR(0x71, 0x06), ++ ILI9881C_COMMAND_INSTR(0x72, 0x07), ++ ILI9881C_COMMAND_INSTR(0x73, 0x02), ++ ILI9881C_COMMAND_INSTR(0x74, 0x02), ++ ILI9881C_COMMAND_INSTR(0x75, 0x06), ++ ILI9881C_COMMAND_INSTR(0x76, 0x07), ++ ILI9881C_COMMAND_INSTR(0x77, 0x0e), ++ ILI9881C_COMMAND_INSTR(0x78, 0x0f), ++ ILI9881C_COMMAND_INSTR(0x79, 0x0c), ++ ILI9881C_COMMAND_INSTR(0x7a, 0x0d), ++ ILI9881C_COMMAND_INSTR(0x7b, 0x02), ++ ILI9881C_COMMAND_INSTR(0x7c, 0x02), ++ ILI9881C_COMMAND_INSTR(0x7d, 0x02), ++ ILI9881C_COMMAND_INSTR(0x7e, 0x02), ++ ILI9881C_COMMAND_INSTR(0x7f, 0x02), ++ ILI9881C_COMMAND_INSTR(0x80, 0x02), ++ ILI9881C_COMMAND_INSTR(0x81, 0x02), ++ ILI9881C_COMMAND_INSTR(0x82, 0x02), ++ ILI9881C_COMMAND_INSTR(0x83, 0x02), ++ ILI9881C_COMMAND_INSTR(0x84, 0x02), ++ ILI9881C_COMMAND_INSTR(0x85, 0x02), ++ ILI9881C_COMMAND_INSTR(0x86, 0x02), ++ ILI9881C_COMMAND_INSTR(0x87, 0x09), ++ ILI9881C_COMMAND_INSTR(0x88, 0x08), ++ ILI9881C_COMMAND_INSTR(0x89, 0x02), ++ ILI9881C_COMMAND_INSTR(0x8A, 0x02), ++ ILI9881C_SWITCH_PAGE_INSTR(4), ++ ILI9881C_COMMAND_INSTR(0x6C, 0x15), ++ ILI9881C_COMMAND_INSTR(0x6E, 0x2a), ++ ILI9881C_COMMAND_INSTR(0x6F, 0x57), ++ ILI9881C_COMMAND_INSTR(0x3A, 0xa4), ++ ILI9881C_COMMAND_INSTR(0x8D, 0x1a), ++ ILI9881C_COMMAND_INSTR(0x87, 0xba), ++ ILI9881C_COMMAND_INSTR(0x26, 0x76), ++ ILI9881C_COMMAND_INSTR(0xB2, 0xd1), ++ ILI9881C_SWITCH_PAGE_INSTR(1), ++ ILI9881C_COMMAND_INSTR(0x22, 0x0A), ++ ILI9881C_COMMAND_INSTR(0x31, 0x00), ++ ILI9881C_COMMAND_INSTR(0x53, 0x35), ++ ILI9881C_COMMAND_INSTR(0x55, 0x50), ++ ILI9881C_COMMAND_INSTR(0x50, 0xaf), ++ ILI9881C_COMMAND_INSTR(0x51, 0xaf), ++ ILI9881C_COMMAND_INSTR(0x60, 0x14), ++ ILI9881C_COMMAND_INSTR(0xA0, 0x08), ++ ILI9881C_COMMAND_INSTR(0xA1, 0x1d), ++ ILI9881C_COMMAND_INSTR(0xA2, 0x2c), ++ ILI9881C_COMMAND_INSTR(0xA3, 0x14), ++ ILI9881C_COMMAND_INSTR(0xA4, 0x19), ++ ILI9881C_COMMAND_INSTR(0xA5, 0x2e), ++ ILI9881C_COMMAND_INSTR(0xA6, 0x22), ++ ILI9881C_COMMAND_INSTR(0xA7, 0x23), ++ ILI9881C_COMMAND_INSTR(0xA8, 0x97), ++ ILI9881C_COMMAND_INSTR(0xA9, 0x1e), ++ ILI9881C_COMMAND_INSTR(0xAA, 0x29), ++ ILI9881C_COMMAND_INSTR(0xAB, 0x7b), ++ ILI9881C_COMMAND_INSTR(0xAC, 0x18), ++ ILI9881C_COMMAND_INSTR(0xAD, 0x17), ++ ILI9881C_COMMAND_INSTR(0xAE, 0x4b), ++ ILI9881C_COMMAND_INSTR(0xAF, 0x1f), ++ ILI9881C_COMMAND_INSTR(0xB0, 0x27), ++ ILI9881C_COMMAND_INSTR(0xB1, 0x52), ++ ILI9881C_COMMAND_INSTR(0xB2, 0x63), ++ ILI9881C_COMMAND_INSTR(0xB3, 0x39), ++ ILI9881C_COMMAND_INSTR(0xC0, 0x08), ++ ILI9881C_COMMAND_INSTR(0xC1, 0x1d), ++ ILI9881C_COMMAND_INSTR(0xC2, 0x2c), ++ ILI9881C_COMMAND_INSTR(0xC3, 0x14), ++ ILI9881C_COMMAND_INSTR(0xC4, 0x19), ++ ILI9881C_COMMAND_INSTR(0xC5, 0x2e), ++ ILI9881C_COMMAND_INSTR(0xC6, 0x22), ++ ILI9881C_COMMAND_INSTR(0xC7, 0x23), ++ ILI9881C_COMMAND_INSTR(0xC8, 0x97), ++ ILI9881C_COMMAND_INSTR(0xC9, 0x1e), ++ ILI9881C_COMMAND_INSTR(0xCA, 0x29), ++ ILI9881C_COMMAND_INSTR(0xCB, 0x7b), ++ ILI9881C_COMMAND_INSTR(0xCC, 0x18), ++ ILI9881C_COMMAND_INSTR(0xCD, 0x17), ++ ILI9881C_COMMAND_INSTR(0xCE, 0x4b), ++ ILI9881C_COMMAND_INSTR(0xCF, 0x1f), ++ ILI9881C_COMMAND_INSTR(0xD0, 0x27), ++ ILI9881C_COMMAND_INSTR(0xD1, 0x52), ++ ILI9881C_COMMAND_INSTR(0xD2, 0x63), ++ ILI9881C_COMMAND_INSTR(0xD3, 0x39), ++}; ++ ++static const struct ili9881c_instr rpi_7inch_init = { ++ ILI9881C_SWITCH_PAGE_INSTR(3), ++ ILI9881C_COMMAND_INSTR(0x01, 0x00), ++ ILI9881C_COMMAND_INSTR(0x02, 0x00), ++ ILI9881C_COMMAND_INSTR(0x03, 0x73), ++ ILI9881C_COMMAND_INSTR(0x04, 0x00), ++ ILI9881C_COMMAND_INSTR(0x05, 0x00), ++ ILI9881C_COMMAND_INSTR(0x06, 0x0a), ++ ILI9881C_COMMAND_INSTR(0x07, 0x00), ++ ILI9881C_COMMAND_INSTR(0x08, 0x00), ++ ILI9881C_COMMAND_INSTR(0x09, 0x61), ++ ILI9881C_COMMAND_INSTR(0x0a, 0x00), ++ ILI9881C_COMMAND_INSTR(0x0b, 0x00), ++ ILI9881C_COMMAND_INSTR(0x0c, 0x01), ++ ILI9881C_COMMAND_INSTR(0x0d, 0x00), ++ ILI9881C_COMMAND_INSTR(0x0e, 0x00), ++ ILI9881C_COMMAND_INSTR(0x0f, 0x61), ++ ILI9881C_COMMAND_INSTR(0x10, 0x61), ++ ILI9881C_COMMAND_INSTR(0x11, 0x00), ++ ILI9881C_COMMAND_INSTR(0x12, 0x00), ++ ILI9881C_COMMAND_INSTR(0x13, 0x00), ++ ILI9881C_COMMAND_INSTR(0x14, 0x00), ++ ILI9881C_COMMAND_INSTR(0x15, 0x00), ++ ILI9881C_COMMAND_INSTR(0x16, 0x00), ++ ILI9881C_COMMAND_INSTR(0x17, 0x00), ++ ILI9881C_COMMAND_INSTR(0x18, 0x00), ++ ILI9881C_COMMAND_INSTR(0x19, 0x00), ++ ILI9881C_COMMAND_INSTR(0x1a, 0x00), ++ ILI9881C_COMMAND_INSTR(0x1b, 0x00), ++ ILI9881C_COMMAND_INSTR(0x1c, 0x00), ++ ILI9881C_COMMAND_INSTR(0x1d, 0x00), ++ ILI9881C_COMMAND_INSTR(0x1e, 0x40), ++ ILI9881C_COMMAND_INSTR(0x1f, 0x80), ++ ILI9881C_COMMAND_INSTR(0x20, 0x06), ++ ILI9881C_COMMAND_INSTR(0x21, 0x01), ++ ILI9881C_COMMAND_INSTR(0x22, 0x00), ++ ILI9881C_COMMAND_INSTR(0x23, 0x00), ++ ILI9881C_COMMAND_INSTR(0x24, 0x00), ++ ILI9881C_COMMAND_INSTR(0x25, 0x00), ++ ILI9881C_COMMAND_INSTR(0x26, 0x00), ++ ILI9881C_COMMAND_INSTR(0x27, 0x00), ++ ILI9881C_COMMAND_INSTR(0x28, 0x33), ++ ILI9881C_COMMAND_INSTR(0x29, 0x03), ++ ILI9881C_COMMAND_INSTR(0x2a, 0x00), ++ ILI9881C_COMMAND_INSTR(0x2b, 0x00), ++ ILI9881C_COMMAND_INSTR(0x2c, 0x00), ++ ILI9881C_COMMAND_INSTR(0x2d, 0x00), ++ ILI9881C_COMMAND_INSTR(0x2e, 0x00), ++ ILI9881C_COMMAND_INSTR(0x2f, 0x00), ++ ILI9881C_COMMAND_INSTR(0x30, 0x00), ++ ILI9881C_COMMAND_INSTR(0x31, 0x00), ++ ILI9881C_COMMAND_INSTR(0x32, 0x00), ++ ILI9881C_COMMAND_INSTR(0x33, 0x00), ++ ILI9881C_COMMAND_INSTR(0x34, 0x04), ++ ILI9881C_COMMAND_INSTR(0x35, 0x00), ++ ILI9881C_COMMAND_INSTR(0x36, 0x00), ++ ILI9881C_COMMAND_INSTR(0x37, 0x00), ++ ILI9881C_COMMAND_INSTR(0x38, 0x3c), ++ ILI9881C_COMMAND_INSTR(0x39, 0x00), ++ ILI9881C_COMMAND_INSTR(0x3a, 0x00), ++ ILI9881C_COMMAND_INSTR(0x3b, 0x00), ++ ILI9881C_COMMAND_INSTR(0x3c, 0x00), ++ ILI9881C_COMMAND_INSTR(0x3d, 0x00), ++ ILI9881C_COMMAND_INSTR(0x3e, 0x00), ++ ILI9881C_COMMAND_INSTR(0x3f, 0x00), ++ ILI9881C_COMMAND_INSTR(0x40, 0x00), ++ ILI9881C_COMMAND_INSTR(0x41, 0x00), ++ ILI9881C_COMMAND_INSTR(0x42, 0x00), ++ ILI9881C_COMMAND_INSTR(0x43, 0x00), ++ ILI9881C_COMMAND_INSTR(0x44, 0x00), ++ ILI9881C_COMMAND_INSTR(0x50, 0x10), ++ ILI9881C_COMMAND_INSTR(0x51, 0x32), ++ ILI9881C_COMMAND_INSTR(0x52, 0x54), ++ ILI9881C_COMMAND_INSTR(0x53, 0x76), ++ ILI9881C_COMMAND_INSTR(0x54, 0x98), ++ ILI9881C_COMMAND_INSTR(0x55, 0xba), ++ ILI9881C_COMMAND_INSTR(0x56, 0x10), ++ ILI9881C_COMMAND_INSTR(0x57, 0x32), ++ ILI9881C_COMMAND_INSTR(0x58, 0x54), ++ ILI9881C_COMMAND_INSTR(0x59, 0x76), ++ ILI9881C_COMMAND_INSTR(0x5a, 0x98), ++ ILI9881C_COMMAND_INSTR(0x5b, 0xba), ++ ILI9881C_COMMAND_INSTR(0x5c, 0xdc), ++ ILI9881C_COMMAND_INSTR(0x5d, 0xfe), ++ ILI9881C_COMMAND_INSTR(0x5e, 0x00), ++ ILI9881C_COMMAND_INSTR(0x5f, 0x0e), ++ ILI9881C_COMMAND_INSTR(0x60, 0x0f), ++ ILI9881C_COMMAND_INSTR(0x61, 0x0c), ++ ILI9881C_COMMAND_INSTR(0x62, 0x0d), ++ ILI9881C_COMMAND_INSTR(0x63, 0x06), ++ ILI9881C_COMMAND_INSTR(0x64, 0x07), ++ ILI9881C_COMMAND_INSTR(0x65, 0x02), ++ ILI9881C_COMMAND_INSTR(0x66, 0x02), ++ ILI9881C_COMMAND_INSTR(0x67, 0x02), ++ ILI9881C_COMMAND_INSTR(0x68, 0x02), ++ ILI9881C_COMMAND_INSTR(0x69, 0x01), ++ ILI9881C_COMMAND_INSTR(0x6a, 0x00), ++ ILI9881C_COMMAND_INSTR(0x6b, 0x02), ++ ILI9881C_COMMAND_INSTR(0x6c, 0x15), ++ ILI9881C_COMMAND_INSTR(0x6d, 0x14), ++ ILI9881C_COMMAND_INSTR(0x6e, 0x02), ++ ILI9881C_COMMAND_INSTR(0x6f, 0x02), ++ ILI9881C_COMMAND_INSTR(0x70, 0x02), ++ ILI9881C_COMMAND_INSTR(0x71, 0x02), ++ ILI9881C_COMMAND_INSTR(0x72, 0x02), ++ ILI9881C_COMMAND_INSTR(0x73, 0x02), ++ ILI9881C_COMMAND_INSTR(0x74, 0x02), ++ ILI9881C_COMMAND_INSTR(0x75, 0x0e), ++ ILI9881C_COMMAND_INSTR(0x76, 0x0f), ++ ILI9881C_COMMAND_INSTR(0x77, 0x0c), ++ ILI9881C_COMMAND_INSTR(0x78, 0x0d), ++ ILI9881C_COMMAND_INSTR(0x79, 0x06), ++ ILI9881C_COMMAND_INSTR(0x7a, 0x07), ++ ILI9881C_COMMAND_INSTR(0x7b, 0x02), ++ ILI9881C_COMMAND_INSTR(0x7c, 0x02), ++ ILI9881C_COMMAND_INSTR(0x7d, 0x02), ++ ILI9881C_COMMAND_INSTR(0x7e, 0x02), ++ ILI9881C_COMMAND_INSTR(0x7f, 0x01), ++ ILI9881C_COMMAND_INSTR(0x80, 0x00), ++ ILI9881C_COMMAND_INSTR(0x81, 0x02), ++ ILI9881C_COMMAND_INSTR(0x82, 0x14), ++ ILI9881C_COMMAND_INSTR(0x83, 0x15), ++ ILI9881C_COMMAND_INSTR(0x84, 0x02), ++ ILI9881C_COMMAND_INSTR(0x85, 0x02), ++ ILI9881C_COMMAND_INSTR(0x86, 0x02), ++ ILI9881C_COMMAND_INSTR(0x87, 0x02), ++ ILI9881C_COMMAND_INSTR(0x88, 0x02), ++ ILI9881C_COMMAND_INSTR(0x89, 0x02), ++ ILI9881C_COMMAND_INSTR(0x8A, 0x02), ++ ILI9881C_SWITCH_PAGE_INSTR(4), ++ ILI9881C_COMMAND_INSTR(0x6C, 0x15), ++ ILI9881C_COMMAND_INSTR(0x6E, 0x2A), ++ ILI9881C_COMMAND_INSTR(0x6F, 0x33), ++ ILI9881C_COMMAND_INSTR(0x3B, 0x98), ++ ILI9881C_COMMAND_INSTR(0x3a, 0x94), ++ ILI9881C_COMMAND_INSTR(0x8D, 0x14), ++ ILI9881C_COMMAND_INSTR(0x87, 0xBA), ++ ILI9881C_COMMAND_INSTR(0x26, 0x76), ++ ILI9881C_COMMAND_INSTR(0xB2, 0xD1), ++ ILI9881C_COMMAND_INSTR(0xB5, 0x06), ++ ILI9881C_COMMAND_INSTR(0x38, 0x01), ++ ILI9881C_COMMAND_INSTR(0x39, 0x00), ++ ILI9881C_SWITCH_PAGE_INSTR(1), ++ ILI9881C_COMMAND_INSTR(0x22, 0x0A), ++ ILI9881C_COMMAND_INSTR(0x31, 0x00), ++ ILI9881C_COMMAND_INSTR(0x53, 0x7d), ++ ILI9881C_COMMAND_INSTR(0x55, 0x8f), ++ ILI9881C_COMMAND_INSTR(0x40, 0x33), ++ ILI9881C_COMMAND_INSTR(0x50, 0x96), ++ ILI9881C_COMMAND_INSTR(0x51, 0x96), ++ ILI9881C_COMMAND_INSTR(0x60, 0x23), ++ ILI9881C_COMMAND_INSTR(0xA0, 0x08), ++ ILI9881C_COMMAND_INSTR(0xA1, 0x1d), ++ ILI9881C_COMMAND_INSTR(0xA2, 0x2a), ++ ILI9881C_COMMAND_INSTR(0xA3, 0x10), ++ ILI9881C_COMMAND_INSTR(0xA4, 0x15), ++ ILI9881C_COMMAND_INSTR(0xA5, 0x28), ++ ILI9881C_COMMAND_INSTR(0xA6, 0x1c), ++ ILI9881C_COMMAND_INSTR(0xA7, 0x1d), ++ ILI9881C_COMMAND_INSTR(0xA8, 0x7e), ++ ILI9881C_COMMAND_INSTR(0xA9, 0x1d), ++ ILI9881C_COMMAND_INSTR(0xAA, 0x29), ++ ILI9881C_COMMAND_INSTR(0xAB, 0x6b), ++ ILI9881C_COMMAND_INSTR(0xAC, 0x1a), ++ ILI9881C_COMMAND_INSTR(0xAD, 0x18), ++ ILI9881C_COMMAND_INSTR(0xAE, 0x4b), ++ ILI9881C_COMMAND_INSTR(0xAF, 0x20), ++ ILI9881C_COMMAND_INSTR(0xB0, 0x27), ++ ILI9881C_COMMAND_INSTR(0xB1, 0x50), ++ ILI9881C_COMMAND_INSTR(0xB2, 0x64), ++ ILI9881C_COMMAND_INSTR(0xB3, 0x39), ++ ILI9881C_COMMAND_INSTR(0xC0, 0x08), ++ ILI9881C_COMMAND_INSTR(0xC1, 0x1d), ++ ILI9881C_COMMAND_INSTR(0xC2, 0x2a), ++ ILI9881C_COMMAND_INSTR(0xC3, 0x10), ++ ILI9881C_COMMAND_INSTR(0xC4, 0x15), ++ ILI9881C_COMMAND_INSTR(0xC5, 0x28), ++ ILI9881C_COMMAND_INSTR(0xC6, 0x1c), ++ ILI9881C_COMMAND_INSTR(0xC7, 0x1d), ++ ILI9881C_COMMAND_INSTR(0xC8, 0x7e), ++ ILI9881C_COMMAND_INSTR(0xC9, 0x1d), ++ ILI9881C_COMMAND_INSTR(0xCA, 0x29), ++ ILI9881C_COMMAND_INSTR(0xCB, 0x6b), ++ ILI9881C_COMMAND_INSTR(0xCC, 0x1a), ++ ILI9881C_COMMAND_INSTR(0xCD, 0x18), ++ ILI9881C_COMMAND_INSTR(0xCE, 0x4b), ++ ILI9881C_COMMAND_INSTR(0xCF, 0x20), ++ ILI9881C_COMMAND_INSTR(0xD0, 0x27), ++ ILI9881C_COMMAND_INSTR(0xD1, 0x50), ++ ILI9881C_COMMAND_INSTR(0xD2, 0x64), ++ ILI9881C_COMMAND_INSTR(0xD3, 0x39), ++}; ++ ++static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel) ++{ ++ return container_of(panel, struct ili9881c, panel); ++} ++ ++/* ++ * The panel seems to accept some private DCS commands that map ++ * directly to registers. ++ * ++ * It is organised by page, with each page having its own set of ++ * registers, and the first page looks like it's holding the standard + * DCS commands. + * + * So before any attempt at sending a command or data, we have to be +@@ -883,10 +1696,10 @@ static int ili9881c_prepare(struct drm_panel *panel) + msleep(5); + + /* And reset it */ +- gpiod_set_value(ctx->reset, 1); ++ gpiod_set_value_cansleep(ctx->reset, 1); + msleep(20); + +- gpiod_set_value(ctx->reset, 0); ++ gpiod_set_value_cansleep(ctx->reset, 0); + msleep(20); + + for (i = 0; i < ctx->desc->init_length; i++) { +@@ -941,7 +1754,7 @@ static int ili9881c_unprepare(struct drm_panel *panel) + + mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); + regulator_disable(ctx->power); +- gpiod_set_value(ctx->reset, 1); ++ gpiod_set_value_cansleep(ctx->reset, 1); + + return 0; + } +@@ -980,6 +1793,23 @@ static const struct drm_display_mode k101_im2byl02_default_mode = { .height_mm = 217, }; +static const struct drm_display_mode nwe080_default_mode = { -+ .clock = 71750, ++ .clock = 71750, ++ ++ .hdisplay = 800, ++ .hsync_start = 800 + 52, ++ .hsync_end = 800 + 52 + 8, ++ .htotal = 800 + 52 + 8 + 48, ++ ++ .vdisplay = 1280, ++ .vsync_start = 1280 + 16, ++ .vsync_end = 1280 + 16 + 6, ++ .vtotal = 1280 + 16 + 6 + 15, + -+ .hdisplay = 800, -+ .hsync_start = 800 + 52, -+ .hsync_end = 800 + 52 + 8, -+ .htotal = 800 + 52 + 8 + 48, ++ .width_mm = 107, ++ .height_mm = 170, ++}; + + static const struct drm_display_mode tl050hdv35_default_mode = { + .clock = 59400, + +@@ -1014,6 +1844,54 @@ static const struct drm_display_mode w552946aba_default_mode = { + .height_mm = 121, + }; + ++static const struct drm_display_mode cfaf7201280a0_050tx_default_mode = { ++ .clock = 72830, ++ .hdisplay = 720, ++ .hsync_start = 720 + 87, ++ .hsync_end = 720 + 87 + 20, ++ .htotal = 720 + 87 + 20 + 87, + .vdisplay = 1280, + .vsync_start = 1280 + 16, -+ .vsync_end = 1280 + 16 + 6, -+ .vtotal = 1280 + 16 + 6 + 15, ++ .vsync_end = 1280 + 16 + 8, ++ .vtotal = 1280 + 16 + 8 + 16, ++ .width_mm = 62, ++ .height_mm = 1108 ++}; ++ ++static const struct drm_display_mode rpi_5inch_default_mode = { ++ .clock = 83333, ++ ++ .hdisplay = 720, ++ .hsync_start = 720 + 110, ++ .hsync_end = 720 + 110 + 2, ++ .htotal = 720 + 110 + 2 + 105, ++ ++ .vdisplay = 1280, ++ .vsync_start = 1280 + 100, ++ .vsync_end = 1280 + 100 + 2, ++ .vtotal = 1280 + 100 + 2 + 100, ++ ++ .width_mm = 62, ++ .height_mm = 110, ++}; ++ ++static const struct drm_display_mode rpi_7inch_default_mode = { ++ .clock = 83330, ++ ++ .hdisplay = 720, ++ .hsync_start = 720 + 239, ++ .hsync_end = 720 + 239 + 33, ++ .htotal = 720 + 239 + 33 + 50, + -+ .width_mm = 107, -+ .height_mm = 170, ++ .vdisplay = 1280, ++ .vsync_start = 1280 + 20, ++ .vsync_end = 1280 + 20 + 2, ++ .vtotal = 1280 + 20 + 2 + 30, ++ ++ .width_mm = 90, ++ .height_mm = 151, +}; + static int ili9881c_get_modes(struct drm_panel *panel, struct drm_connector *connector) { -@@ -670,7 +909,7 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) +@@ -1074,6 +1952,7 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) + ctx->dsi = dsi; + ctx->desc = of_device_get_match_data(&dsi->dev); - drm_panel_add(&ctx->panel); ++ ctx->panel.prepare_prev_first = true; + drm_panel_init(&ctx->panel, &dsi->dev, &ili9881c_funcs, + DRM_MODE_CONNECTOR_DSI); -- dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE; -+ dsi->mode_flags = ctx->desc->flags; +@@ -1102,9 +1981,13 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) + + dsi->mode_flags = ctx->desc->mode_flags; dsi->format = MIPI_DSI_FMT_RGB888; - dsi->lanes = 4; +- dsi->lanes = 4; ++ dsi->lanes = ctx->desc->lanes; ++ ++ ret = mipi_dsi_attach(dsi); ++ if (ret) ++ drm_panel_remove(&ctx->panel); + +- return mipi_dsi_attach(dsi); ++ return ret; + } -@@ -691,18 +930,28 @@ static const struct ili9881c_desc lhr050h41_desc = { - .init = lhr050h41_init, + static void ili9881c_dsi_remove(struct mipi_dsi_device *dsi) +@@ -1113,6 +1996,9 @@ static void ili9881c_dsi_remove(struct mipi_dsi_device *dsi) + + mipi_dsi_detach(dsi); + drm_panel_remove(&ctx->panel); ++ ++ gpiod_set_value_cansleep(ctx->reset, 1); ++ regulator_disable(ctx->power); + } + + static const struct ili9881c_desc lhr050h41_desc = { +@@ -1120,6 +2006,7 @@ static const struct ili9881c_desc lhr050h41_desc = { .init_length = ARRAY_SIZE(lhr050h41_init), .mode = &lhr050h41_default_mode, -+ .flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE, + .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE, ++ .lanes = 4, }; static const struct ili9881c_desc k101_im2byl02_desc = { - .init = k101_im2byl02_init, +@@ -1127,6 +2014,15 @@ static const struct ili9881c_desc k101_im2byl02_desc = { .init_length = ARRAY_SIZE(k101_im2byl02_init), .mode = &k101_im2byl02_default_mode, -+ .flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE, + .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE, ++ .lanes = 4, +}; + +static const struct ili9881c_desc nwe080_desc = { + .init = nwe080_init, + .init_length = ARRAY_SIZE(nwe080_init), + .mode = &nwe080_default_mode, -+ .flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_VIDEO, ++ .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_VIDEO, ++ .lanes = 4, + }; + + static const struct ili9881c_desc tl050hdv35_desc = { +@@ -1143,13 +2039,42 @@ static const struct ili9881c_desc w552946aba_desc = { + .mode = &w552946aba_default_mode, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, ++ .lanes = 4, ++}; ++ ++static const struct ili9881c_desc cfaf7201280a0_050tx_desc = { ++ .init = cfaf7201280a0_050tx_init, ++ .init_length = ARRAY_SIZE(cfaf7201280a0_050tx_init), ++ .mode = &cfaf7201280a0_050tx_default_mode, ++ .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_VIDEO, ++ .lanes = 4, ++}; ++ ++static const struct ili9881c_desc rpi_5inch_desc = { ++ .init = rpi_5inch_init, ++ .init_length = ARRAY_SIZE(rpi_5inch_init), ++ .mode = &rpi_5inch_default_mode, ++ .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM, ++ .lanes = 2, ++}; ++ ++static const struct ili9881c_desc rpi_7inch_desc = { ++ .init = rpi_7inch_init, ++ .init_length = ARRAY_SIZE(rpi_7inch_init), ++ .mode = &rpi_7inch_default_mode, ++ .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM, ++ .lanes = 2, }; static const struct of_device_id ili9881c_of_match = { { .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc }, { .compatible = "feixin,k101-im2byl02", .data = &k101_im2byl02_desc }, -- { } + { .compatible = "nwe,nwe080", .data = &nwe080_desc }, -+ {} + { .compatible = "tdo,tl050hdv35", .data = &tl050hdv35_desc }, + { .compatible = "wanchanglong,w552946aba", .data = &w552946aba_desc }, ++ { .compatible = "crystalfontz,cfaf7201280a0_050tx", .data = &cfaf7201280a0_050tx_desc }, ++ { .compatible = "raspberrypi,dsi-5inch", &rpi_5inch_desc }, ++ { .compatible = "raspberrypi,dsi-7inch", &rpi_7inch_desc }, + { } }; MODULE_DEVICE_TABLE(of, ili9881c_of_match); - diff --git a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c -index 733010b5e4f5..7fb4d98e166d 100644 +index 213008499caa..50c1622d8920 100644 --- a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c +++ b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c @@ -205,11 +205,11 @@ static int jdi_panel_unprepare(struct drm_panel *panel) @@ -57365,11 +75585,19 @@ return ret; } +@@ -429,6 +429,7 @@ static int jdi_panel_add(struct jdi_panel *jdi) + return dev_err_probe(dev, PTR_ERR(jdi->backlight), + "failed to register backlight %d\n", ret); + ++ jdi->base.prepare_prev_first = true; + drm_panel_init(&jdi->base, &jdi->dsi->dev, &jdi_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c -index bbdd086be7f5..3f0c11fa60a5 100644 +index 4618c892cdd6..4c418962aa9b 100644 --- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c -@@ -219,7 +219,35 @@ static struct rpi_touchscreen *panel_to_ts(struct drm_panel *panel) +@@ -218,7 +218,35 @@ static struct rpi_touchscreen *panel_to_ts(struct drm_panel *panel) static int rpi_touchscreen_i2c_read(struct rpi_touchscreen *ts, u8 reg) { @@ -57406,26 +75634,20 @@ } static void rpi_touchscreen_i2c_write(struct rpi_touchscreen *ts, -@@ -229,7 +257,7 @@ static void rpi_touchscreen_i2c_write(struct rpi_touchscreen *ts, - - ret = i2c_smbus_write_byte_data(ts->i2c, reg, val); - if (ret) -- dev_err(&ts->dsi->dev, "I2C write failed: %d\n", ret); -+ dev_err(&ts->i2c->dev, "I2C write failed: %d\n", ret); - } - - static int rpi_touchscreen_write(struct rpi_touchscreen *ts, u16 reg, u32 val) -@@ -265,15 +293,17 @@ static int rpi_touchscreen_noop(struct drm_panel *panel) - return 0; - } - --static int rpi_touchscreen_enable(struct drm_panel *panel) -+static int rpi_touchscreen_prepare(struct drm_panel *panel) +@@ -267,12 +295,21 @@ static int rpi_touchscreen_noop(struct drm_panel *panel) + static int rpi_touchscreen_prepare(struct drm_panel *panel) { struct rpi_touchscreen *ts = panel_to_ts(panel); - int i; + int i, data; ++ /* ++ * Power up the Toshiba bridge. The Atmel device can misbehave ++ * over I2C for a few ms after writes to REG_POWERON (including the ++ * write in rpi_touchscreen_disable()), so sleep before and after. ++ * Also to ensure that the bridge has been off for at least 100ms. ++ */ ++ msleep(100); rpi_touchscreen_i2c_write(ts, REG_POWERON, 1); + usleep_range(20000, 25000); /* Wait for nPWRDWN to go low to indicate poweron is done. */ @@ -57436,35 +75658,28 @@ break; } -@@ -295,6 +325,13 @@ static int rpi_touchscreen_enable(struct drm_panel *panel) - rpi_touchscreen_write(ts, DSI_STARTDSI, 0x01); - msleep(100); +@@ -398,6 +435,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c) -+ return 0; -+} -+ -+static int rpi_touchscreen_enable(struct drm_panel *panel) -+{ -+ struct rpi_touchscreen *ts = panel_to_ts(panel); -+ - /* Turn on the backlight. */ - rpi_touchscreen_i2c_write(ts, REG_PWM, 255); + /* Turn off at boot, so we can cleanly sequence powering on. */ + rpi_touchscreen_i2c_write(ts, REG_POWERON, 0); ++ usleep_range(20000, 25000); -@@ -349,7 +386,7 @@ static int rpi_touchscreen_get_modes(struct drm_panel *panel, - static const struct drm_panel_funcs rpi_touchscreen_funcs = { - .disable = rpi_touchscreen_disable, - .unprepare = rpi_touchscreen_noop, -- .prepare = rpi_touchscreen_noop, -+ .prepare = rpi_touchscreen_prepare, - .enable = rpi_touchscreen_enable, - .get_modes = rpi_touchscreen_get_modes, - }; + /* Look up the DSI host. It needs to probe before we do. */ + endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c -index 7ffd2a04ab23..08d26e81cbfb 100644 +index 51f838befb32..035ee7a2f8a0 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c -@@ -112,8 +112,6 @@ struct panel_simple { - struct gpio_desc *hpd_gpio; +@@ -40,6 +40,7 @@ + #include <drm/drm_edid.h> + #include <drm/drm_mipi_dsi.h> + #include <drm/drm_panel.h> ++#include <drm/drm_of.h> + + /** + * struct panel_desc - Describes a simple panel. +@@ -153,8 +154,6 @@ struct panel_simple { + struct edid *edid; struct drm_display_mode override_mode; - @@ -57472,17 +75687,32 @@ }; static inline struct panel_simple *to_panel_simple(struct drm_panel *panel) -@@ -373,9 +371,6 @@ static int panel_simple_get_modes(struct drm_panel *panel, +@@ -411,12 +410,6 @@ static int panel_simple_get_modes(struct drm_panel *panel, /* add hard-coded panel modes */ num += panel_simple_get_non_edid_modes(p, connector); -- /* set up connector's "panel orientation" property */ +- /* +- * TODO: Remove once all drm drivers call +- * drm_connector_set_orientation_from_panel() +- */ - drm_connector_set_panel_orientation(connector, p->orientation); - return num; } -@@ -438,6 +433,7 @@ static int panel_dpi_probe(struct device *dev, +@@ -439,9 +432,9 @@ static int panel_simple_get_timings(struct drm_panel *panel, + + static enum drm_panel_orientation panel_simple_get_orientation(struct drm_panel *panel) + { +- struct panel_simple *p = to_panel_simple(panel); ++ //struct panel_simple *p = to_panel_simple(panel); + +- return p->orientation; ++ return DRM_MODE_PANEL_ORIENTATION_UNKNOWN; + } + + static const struct drm_panel_funcs panel_simple_funcs = { +@@ -487,6 +480,7 @@ static int panel_dpi_probe(struct device *dev, of_property_read_u32(np, "width-mm", &desc->size.width); of_property_read_u32(np, "height-mm", &desc->size.height); @@ -57490,7 +75720,7 @@ /* Extract bus_flags from display_timing */ bus_flags = 0; -@@ -447,6 +443,8 @@ static int panel_dpi_probe(struct device *dev, +@@ -496,6 +490,8 @@ static int panel_dpi_probe(struct device *dev, /* We do not know the connector for the DT node, so guess it */ desc->connector_type = DRM_MODE_CONNECTOR_DPI; @@ -57499,9 +75729,9 @@ panel->desc = desc; -@@ -537,12 +535,6 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) - return err; - } +@@ -575,12 +571,6 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) + return dev_err_probe(dev, PTR_ERR(panel->enable_gpio), + "failed to request GPIO\n"); - err = of_drm_get_panel_orientation(dev->of_node, &panel->orientation); - if (err) { @@ -57512,7 +75742,7 @@ ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0); if (ddc) { panel->ddc = of_find_i2c_adapter_by_node(ddc); -@@ -1940,6 +1932,32 @@ static const struct panel_desc friendlyarm_hd702e = { +@@ -2032,6 +2022,32 @@ static const struct panel_desc friendlyarm_hd702e = { }, }; @@ -57545,7 +75775,7 @@ static const struct drm_display_mode giantplus_gpg482739qs5_mode = { .clock = 9000, .hdisplay = 480, -@@ -2094,6 +2112,38 @@ static const struct panel_desc innolux_at043tn24 = { +@@ -2212,6 +2228,38 @@ static const struct panel_desc innolux_at043tn24 = { .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, }; @@ -57584,16 +75814,16 @@ static const struct drm_display_mode innolux_at070tn92_mode = { .clock = 33333, .hdisplay = 800, -@@ -3188,6 +3238,31 @@ static const struct panel_desc qd43003c0_40 = { - .bus_format = MEDIA_BUS_FMT_RGB888_1X24, +@@ -3372,6 +3420,31 @@ static const struct panel_desc rocktech_rk043fn48h = { + .connector_type = DRM_MODE_CONNECTOR_DPI, }; +static const struct drm_display_mode raspberrypi_7inch_mode = { -+ .clock = 25979400 / 1000, ++ .clock = 27777, + .hdisplay = 800, -+ .hsync_start = 800 + 2, -+ .hsync_end = 800 + 2 + 2, -+ .htotal = 800 + 2 + 2 + 46, ++ .hsync_start = 800 + 59, ++ .hsync_end = 800 + 59 + 2, ++ .htotal = 800 + 59 + 2 + 46, + .vdisplay = 480, + .vsync_start = 480 + 7, + .vsync_end = 480 + 7 + 2, @@ -57616,7 +75846,7 @@ static const struct display_timing rocktech_rk070er9427_timing = { .pixelclock = { 26400000, 33300000, 46800000 }, .hactive = { 800, 800, 800 }, -@@ -4058,6 +4133,9 @@ static const struct of_device_id platform_of_match = { +@@ -4269,6 +4342,9 @@ static const struct of_device_id platform_of_match = { }, { .compatible = "friendlyarm,hd702e", .data = &friendlyarm_hd702e, @@ -57626,7 +75856,7 @@ }, { .compatible = "giantplus,gpg482739qs5", .data = &giantplus_gpg482739qs5 -@@ -4076,6 +4154,9 @@ static const struct of_device_id platform_of_match = { +@@ -4290,6 +4366,9 @@ static const struct of_device_id platform_of_match = { }, { .compatible = "innolux,at043tn24", .data = &innolux_at043tn24, @@ -57636,1645 +75866,12034 @@ }, { .compatible = "innolux,at070tn92", .data = &innolux_at070tn92, -@@ -4205,6 +4286,9 @@ static const struct of_device_id platform_of_match = { +@@ -4422,6 +4501,9 @@ static const struct of_device_id platform_of_match = { }, { - .compatible = "qiaodian,qd43003c0-40", - .data = &qd43003c0_40, + .compatible = "rocktech,rk043fn48h", + .data = &rocktech_rk043fn48h, + }, { + .compatible = "raspberrypi,7inch-dsi", + .data = &raspberrypi_7inch, }, { .compatible = "rocktech,rk070er9427", .data = &rocktech_rk070er9427, -diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c -index f22a1b776f4b..5c9e28fdb6ad 100644 ---- a/drivers/gpu/drm/qxl/qxl_display.c -+++ b/drivers/gpu/drm/qxl/qxl_display.c -@@ -373,7 +373,7 @@ static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc, - } - - 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"); - } -@@ -445,13 +445,13 @@ static const struct drm_framebuffer_funcs qxl_fb_funcs = { +@@ -4776,6 +4858,9 @@ static const struct panel_desc_dsi osd101t2045_53ts = { + .lanes = 4, }; - 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 --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c -index 065604c5837d..41a2f8d3e992 100644 ---- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c -+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c -@@ -688,20 +688,23 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) - */ - - 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. */ -@@ -716,7 +719,7 @@ static int rcar_du_crtc_atomic_check(struct drm_crtc *crtc, - } - - 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); -@@ -751,8 +754,10 @@ static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc, - } - - 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; -@@ -780,7 +785,7 @@ static void rcar_du_crtc_atomic_disable(struct drm_crtc *crtc, - } - - 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); - -@@ -809,7 +814,7 @@ static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc, - } - - 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; -@@ -1145,7 +1150,6 @@ static const struct drm_crtc_funcs crtc_funcs_gen3 = { - .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, ++// for panels using generic panel-dsi binding ++static struct panel_desc_dsi panel_dsi; ++ + static const struct of_device_id dsi_of_match = { + { + .compatible = "auo,b080uan01", +@@ -4798,21 +4883,138 @@ static const struct of_device_id dsi_of_match = { + }, { + .compatible = "osddisplays,osd101t2045-53ts", + .data = &osd101t2045_53ts ++ }, { ++ /* Must be the last entry */ ++ .compatible = "panel-dsi", ++ .data = &panel_dsi, + }, { + /* sentinel */ + } }; + MODULE_DEVICE_TABLE(of, dsi_of_match); - /* ----------------------------------------------------------------------------- -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -index 0f23144491e4..5a108247ace4 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -@@ -693,7 +693,7 @@ static void rockchip_drm_set_win_enabled(struct drm_crtc *crtc, bool enabled) - } - - 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); - -@@ -1247,8 +1247,10 @@ static void vop_crtc_gamma_set(struct vop *vop, struct drm_crtc *crtc, - } - - static void vop_crtc_atomic_begin(struct drm_crtc *crtc, -- struct drm_crtc_state *old_crtc_state) -+ struct drm_atomic_state *state) ++ ++/* Checks for DSI panel definition in device-tree, analog to panel_dpi */ ++static int panel_dsi_dt_probe(struct device *dev, ++ struct panel_desc_dsi *desc_dsi) ++{ ++ struct panel_desc *desc; ++ struct display_timing *timing; ++ const struct device_node *np; ++ const char *dsi_color_format; ++ const char *dsi_mode_flags; ++ struct property *prop; ++ int dsi_lanes, ret; ++ ++ np = dev->of_node; ++ ++ desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); ++ if (!desc) ++ return -ENOMEM; ++ ++ timing = devm_kzalloc(dev, sizeof(*timing), GFP_KERNEL); ++ if (!timing) ++ return -ENOMEM; ++ ++ ret = of_get_display_timing(np, "panel-timing", timing); ++ if (ret < 0) { ++ dev_err(dev, "%pOF: no panel-timing node found for \"panel-dsi\" binding\n", ++ np); ++ return ret; ++ } ++ ++ desc->timings = timing; ++ desc->num_timings = 1; ++ ++ of_property_read_u32(np, "width-mm", &desc->size.width); ++ of_property_read_u32(np, "height-mm", &desc->size.height); ++ ++ dsi_lanes = drm_of_get_data_lanes_count_ep(np, 0, 0, 1, 4); ++ ++ if (dsi_lanes < 0) { ++ dev_err(dev, "%pOF: no or too many data-lanes defined", np); ++ return dsi_lanes; ++ } ++ ++ desc_dsi->lanes = dsi_lanes; ++ ++ of_property_read_string(np, "dsi-color-format", &dsi_color_format); ++ if (!strcmp(dsi_color_format, "RGB888")) { ++ desc_dsi->format = MIPI_DSI_FMT_RGB888; ++ desc->bpc = 8; ++ } else if (!strcmp(dsi_color_format, "RGB565")) { ++ desc_dsi->format = MIPI_DSI_FMT_RGB565; ++ desc->bpc = 6; ++ } else if (!strcmp(dsi_color_format, "RGB666")) { ++ desc_dsi->format = MIPI_DSI_FMT_RGB666; ++ desc->bpc = 6; ++ } else if (!strcmp(dsi_color_format, "RGB666_PACKED")) { ++ desc_dsi->format = MIPI_DSI_FMT_RGB666_PACKED; ++ desc->bpc = 6; ++ } else { ++ dev_err(dev, "%pOF: no valid dsi-color-format defined", np); ++ return -EINVAL; ++ } ++ ++ ++ of_property_for_each_string(np, "mode", prop, dsi_mode_flags) { ++ if (!strcmp(dsi_mode_flags, "MODE_VIDEO")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VIDEO; ++ else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_BURST")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_BURST; ++ else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_SYNC_PULSE")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_SYNC_PULSE; ++ else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_AUTO_VERT")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_AUTO_VERT; ++ else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_HSE")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_HSE; ++ else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_NO_HFP")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_NO_HFP; ++ else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_NO_HBP")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_NO_HBP; ++ else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_NO_HSA")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_NO_HSA; ++ else if (!strcmp(dsi_mode_flags, "MODE_VSYNC_FLUSH")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VSYNC_FLUSH; ++ else if (!strcmp(dsi_mode_flags, "MODE_NO_EOT_PACKET")) ++ desc_dsi->flags |= MIPI_DSI_MODE_NO_EOT_PACKET; ++ else if (!strcmp(dsi_mode_flags, "CLOCK_NON_CONTINUOUS")) ++ desc_dsi->flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS; ++ else if (!strcmp(dsi_mode_flags, "MODE_LPM")) ++ desc_dsi->flags |= MIPI_DSI_MODE_LPM; ++ else if (!strcmp(dsi_mode_flags, "HS_PKT_END_ALIGNED")) ++ desc_dsi->flags |= MIPI_DSI_HS_PKT_END_ALIGNED; ++ } ++ ++ desc->connector_type = DRM_MODE_CONNECTOR_DSI; ++ desc_dsi->desc = *desc; ++ ++ return 0; ++} ++ + static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi) { -+ struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, -+ crtc); - struct vop *vop = to_vop(crtc); + const struct panel_desc_dsi *desc; ++ struct panel_desc_dsi *dt_desc; + int err; - /* -@@ -1261,8 +1263,10 @@ static void vop_crtc_atomic_begin(struct drm_crtc *crtc, - } + desc = of_device_get_match_data(&dsi->dev); + if (!desc) + return -ENODEV; - 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); -@@ -1414,8 +1418,10 @@ static void vop_wait_for_irq_handler(struct vop *vop) - } ++ if (desc == &panel_dsi) { ++ /* Handle the generic panel-dsi binding */ ++ dt_desc = devm_kzalloc(&dsi->dev, sizeof(*dt_desc), GFP_KERNEL); ++ if (!dt_desc) ++ return -ENOMEM; ++ ++ err = panel_dsi_dt_probe(&dsi->dev, dt_desc); ++ if (err < 0) ++ return err; ++ ++ desc = dt_desc; ++ } ++ + err = panel_simple_probe(&dsi->dev, &desc->desc); + if (err < 0) + return err; +diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7701.c b/drivers/gpu/drm/panel/panel-sitronix-st7701.c +index 036ac403ed21..b226d8a885ba 100644 +--- a/drivers/gpu/drm/panel/panel-sitronix-st7701.c ++++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c +@@ -7,16 +7,21 @@ + #include <drm/drm_mipi_dsi.h> + #include <drm/drm_modes.h> + #include <drm/drm_panel.h> ++#include <drm/drm_print.h> - 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; -@@ -1459,8 +1465,10 @@ static int vop_crtc_atomic_check(struct drm_crtc *crtc, - } + #include <linux/bitfield.h> + #include <linux/gpio/consumer.h> + #include <linux/delay.h> ++#include <linux/media-bus-format.h> + #include <linux/module.h> + #include <linux/of.h> + #include <linux/regulator/consumer.h> ++#include <linux/spi/spi.h> - 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); -@@ -1634,7 +1642,6 @@ static const struct drm_crtc_funcs vop_crtc_funcs = { - .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, - }; + #include <video/mipi_display.h> - static void vop_fb_unref_worker(struct drm_flip_work *work, void *val) -diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c -index 6f37c104c46f..409795786f03 100644 ---- a/drivers/gpu/drm/sti/sti_crtc.c -+++ b/drivers/gpu/drm/sti/sti_crtc.c -@@ -23,7 +23,7 @@ - #include "sti_vtg.h" ++#define SPI_DATA_FLAG 0x100 ++ + /* Command2 BKx selection command */ + #define DSI_CMD2BKX_SEL 0xFF + #define DSI_CMD1 0 +@@ -42,6 +47,25 @@ + #define DSI_CMD2_BK1_SPD2 0xC2 /* Source EQ2 Setting */ + #define DSI_CMD2_BK1_MIPISET1 0xD0 /* MIPI Setting 1 */ - 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); ++/* ++ * Command2 with BK function selection. ++ * ++ * BIT4.....CN2 ++ * BIT1:0...BKXSEL ++ * 1:00 = CMD2BK0, Command2 BK0 ++ * 1:01 = CMD2BK1, Command2 BK1 ++ * 1:11 = CMD2BK3, Command2 BK3 ++ * 0:00 = Command2 disable ++ */ ++#define DSI_CMD2BK0_SEL 0x10 ++#define DSI_CMD2BK1_SEL 0x11 ++#define DSI_CMD2BK3_SEL 0x13 ++#define DSI_CMD2BKX_SEL_NONE 0x00 ++#define SPI_CMD2BK3_SEL (SPI_DATA_FLAG | DSI_CMD2BK3_SEL) ++#define SPI_CMD2BK1_SEL (SPI_DATA_FLAG | DSI_CMD2BK1_SEL) ++#define SPI_CMD2BK0_SEL (SPI_DATA_FLAG | DSI_CMD2BK0_SEL) ++#define SPI_CMD2BKX_SEL_NONE (SPI_DATA_FLAG | DSI_CMD2BKX_SEL_NONE) ++ + /* Command2, BK0 bytes */ + #define DSI_CMD2_BK0_GAMCTRL_AJ_MASK GENMASK(7, 6) + #define DSI_CMD2_BK0_GAMCTRL_VC0_MASK GENMASK(3, 0) +@@ -100,11 +124,23 @@ enum op_bias { -@@ -35,7 +35,7 @@ static void sti_crtc_atomic_enable(struct drm_crtc *crtc, - } + struct st7701; - 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); ++struct st7701; ++ ++enum st7701_ctrl_if { ++ ST7701_CTRL_DSI, ++ ST7701_CTRL_SPI, ++}; ++ + struct st7701_panel_desc { + const struct drm_display_mode *mode; + unsigned int lanes; + enum mipi_dsi_pixel_format format; ++ u32 mediabus_format; + unsigned int panel_sleep_delay; ++ void (*init_sequence)(struct st7701 *st7701); ++ unsigned int conn_type; ++ enum st7701_ctrl_if interface; ++ u32 bus_flags; + + /* TFT matrix driver configuration, panel specific. */ + const u8 pv_gamma16; /* Positive voltage gamma control */ +@@ -130,6 +166,9 @@ struct st7701_panel_desc { + struct st7701 { + struct drm_panel panel; + struct mipi_dsi_device *dsi; ++ struct spi_device *spi; ++ const struct device *dev; ++ + const struct st7701_panel_desc *desc; -@@ -133,7 +133,7 @@ sti_crtc_mode_set_nofb(struct drm_crtc *crtc) + struct regulator_bulk_data supplies2; +@@ -192,7 +231,23 @@ static void st7701_switch_cmd_bkx(struct st7701 *st7701, bool cmd2, u8 bkx) + ST7701_DSI(st7701, DSI_CMD2BKX_SEL, 0x77, 0x01, 0x00, 0x00, val); } - static void sti_crtc_atomic_flush(struct drm_crtc *crtc, -- struct drm_crtc_state *old_crtc_state) -+ struct drm_atomic_state *state) +-static void st7701_init_sequence(struct st7701 *st7701) ++#define ST7701_SPI(st7701, seq...) \ ++ { \ ++ const u16 d = { seq }; \ ++ struct spi_transfer xfer = { }; \ ++ struct spi_message spi; \ ++ \ ++ spi_message_init(&spi); \ ++ \ ++ xfer.tx_buf = d; \ ++ xfer.bits_per_word = 9; \ ++ xfer.len = sizeof(u16) * ARRAY_SIZE(d); \ ++ \ ++ spi_message_add_tail(&xfer, &spi); \ ++ spi_sync((st7701)->spi, &spi); \ ++ } ++ ++static void ts8550b_init_sequence(struct st7701 *st7701) { - struct drm_device *drm_dev = crtc->dev; - struct sti_mixer *mixer = to_sti_mixer(crtc); -diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c -index 62488ac14923..6f3b523e16e8 100644 ---- a/drivers/gpu/drm/stm/ltdc.c -+++ b/drivers/gpu/drm/stm/ltdc.c -@@ -420,7 +420,7 @@ static void ltdc_crtc_update_clut(struct drm_crtc *crtc) - } - - 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; -@@ -442,7 +442,7 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, + const struct st7701_panel_desc *desc = st7701->desc; + const struct drm_display_mode *mode = desc->mode; +@@ -423,6 +478,111 @@ static void kd50t048a_gip_sequence(struct st7701 *st7701) + 0xFF, 0xFF, 0xFF, 0xFF, 0x10, 0x45, 0x67, 0x98, 0xBA); } - static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc, -- struct drm_crtc_state *old_state) -+ struct drm_atomic_state *state) ++static void txw210001b0_init_sequence(struct st7701 *st7701) ++{ ++ ST7701_SPI(st7701, MIPI_DCS_SOFT_RESET); ++ ++ usleep_range(5000, 7000); ++ ++ ST7701_SPI(st7701, DSI_CMD2BKX_SEL, ++ 0x177, 0x101, 0x100, 0x100, SPI_CMD2BK0_SEL); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK0_LNESET, 0x13B, 0x100); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK0_PORCTRL, 0x10B, 0x102); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK0_INVSEL, 0x100, 0x102); ++ ++ ST7701_SPI(st7701, 0xCC, 0x110); ++ ++ /* ++ * Gamma option B: ++ * Positive Voltage Gamma Control ++ */ ++ ST7701_SPI(st7701, DSI_CMD2_BK0_PVGAMCTRL, ++ 0x102, 0x113, 0x11B, 0x10D, 0x110, 0x105, 0x108, 0x107, ++ 0x107, 0x124, 0x104, 0x111, 0x10E, 0x12C, 0x133, 0x11D); ++ ++ /* Negative Voltage Gamma Control */ ++ ST7701_SPI(st7701, DSI_CMD2_BK0_NVGAMCTRL, ++ 0x105, 0x113, 0x11B, 0x10D, 0x111, 0x105, 0x108, 0x107, ++ 0x107, 0x124, 0x104, 0x111, 0x10E, 0x12C, 0x133, 0x11D); ++ ++ ST7701_SPI(st7701, DSI_CMD2BKX_SEL, ++ 0x177, 0x101, 0x100, 0x100, SPI_CMD2BK1_SEL); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_VRHS, 0x15D); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_VCOM, 0x143); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_VGHSS, 0x181); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_TESTCMD, 0x180); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_VGLS, 0x143); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_PWCTLR1, 0x185); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_PWCTLR2, 0x120); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_SPD1, 0x178); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_SPD2, 0x178); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_MIPISET1, 0x188); ++ ++ ST7701_SPI(st7701, 0xE0, 0x100, 0x100, 0x102); ++ ++ ST7701_SPI(st7701, 0xE1, ++ 0x103, 0x1A0, 0x100, 0x100, 0x104, 0x1A0, 0x100, 0x100, ++ 0x100, 0x120, 0x120); ++ ++ ST7701_SPI(st7701, 0xE2, ++ 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, ++ 0x100, 0x100, 0x100, 0x100, 0x100); ++ ++ ST7701_SPI(st7701, 0xE3, 0x100, 0x100, 0x111, 0x100); ++ ++ ST7701_SPI(st7701, 0xE4, 0x122, 0x100); ++ ++ ST7701_SPI(st7701, 0xE5, ++ 0x105, 0x1EC, 0x1A0, 0x1A0, 0x107, 0x1EE, 0x1A0, 0x1A0, ++ 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100); ++ ++ ST7701_SPI(st7701, 0xE6, 0x100, 0x100, 0x111, 0x100); ++ ++ ST7701_SPI(st7701, 0xE7, 0x122, 0x100); ++ ++ ST7701_SPI(st7701, 0xE8, ++ 0x106, 0x1ED, 0x1A0, 0x1A0, 0x108, 0x1EF, 0x1A0, 0x1A0, ++ 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100); ++ ++ ST7701_SPI(st7701, 0xEB, ++ 0x100, 0x100, 0x140, 0x140, 0x100, 0x100, 0x100); ++ ++ ST7701_SPI(st7701, 0xED, ++ 0x1FF, 0x1FF, 0x1FF, 0x1BA, 0x10A, 0x1BF, 0x145, 0x1FF, ++ 0x1FF, 0x154, 0x1FB, 0x1A0, 0x1AB, 0x1FF, 0x1FF, 0x1FF); ++ ++ ST7701_SPI(st7701, 0xEF, 0x110, 0x10D, 0x104, 0x108, 0x13F, 0x11F); ++ ++ ST7701_SPI(st7701, DSI_CMD2BKX_SEL, ++ 0x177, 0x101, 0x100, 0x100, SPI_CMD2BK3_SEL); ++ ++ ST7701_SPI(st7701, 0xEF, 0x108); ++ ++ ST7701_SPI(st7701, DSI_CMD2BKX_SEL, ++ 0x177, 0x101, 0x100, 0x100, SPI_CMD2BKX_SEL_NONE); ++ ++ ST7701_SPI(st7701, 0xCD, 0x108); /* RGB format COLCTRL */ ++ ++ ST7701_SPI(st7701, 0x36, 0x108); /* MadCtl */ ++ ++ ST7701_SPI(st7701, 0x3A, 0x166); /* Colmod */ ++ ++ ST7701_SPI(st7701, MIPI_DCS_EXIT_SLEEP_MODE); ++} ++ + static int st7701_prepare(struct drm_panel *panel) { - struct ltdc_device *ldev = crtc_to_ltdc(crtc); - struct drm_device *ddev = crtc->dev; -@@ -625,7 +625,7 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) - } - - 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; -@@ -742,7 +742,6 @@ static const struct drm_crtc_funcs ltdc_crtc_funcs = { - .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 --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c -index 3a153648b369..45d9eb552d86 100644 ---- a/drivers/gpu/drm/sun4i/sun4i_crtc.c -+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c -@@ -15,6 +15,7 @@ - - #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> -@@ -45,21 +46,25 @@ static struct drm_encoder *sun4i_crtc_get_encoder(struct drm_crtc *crtc) - } + struct st7701 *st7701 = panel_to_st7701(panel); +@@ -439,13 +599,21 @@ static int st7701_prepare(struct drm_panel *panel) + gpiod_set_value(st7701->reset, 1); + msleep(150); - 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; +- st7701_init_sequence(st7701); ++ st7701->desc->init_sequence(st7701); - if (engine && engine->ops && engine->ops->atomic_check) -- ret = engine->ops->atomic_check(engine, state); -+ ret = engine->ops->atomic_check(engine, crtc_state); + if (st7701->desc->gip_sequence) + st7701->desc->gip_sequence(st7701); - return ret; - } + /* Disable Command2 */ +- st7701_switch_cmd_bkx(st7701, false, 0); ++ switch (st7701->desc->interface) { ++ case ST7701_CTRL_DSI: ++ st7701_switch_cmd_bkx(st7701, false, 0); ++ break; ++ case ST7701_CTRL_SPI: ++ ST7701_SPI(st7701, DSI_CMD2BKX_SEL, ++ 0x177, 0x101, 0x100, 0x100, SPI_CMD2BKX_SEL_NONE); ++ break; ++ } - 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; -@@ -79,7 +84,7 @@ static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc, + return 0; } - - static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc, -- struct drm_crtc_state *old_state) -+ struct drm_atomic_state *state) +@@ -454,7 +622,15 @@ static int st7701_enable(struct drm_panel *panel) { - struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); - struct drm_pending_vblank_event *event = crtc->state->event; -@@ -101,7 +106,7 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc, - } + struct st7701 *st7701 = panel_to_st7701(panel); - 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); -@@ -122,7 +127,7 @@ static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc, - } +- ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_ON, 0x00); ++ switch (st7701->desc->interface) { ++ case ST7701_CTRL_DSI: ++ ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_ON, 0x00); ++ break; ++ case ST7701_CTRL_SPI: ++ ST7701_SPI(st7701, MIPI_DCS_SET_DISPLAY_ON); ++ msleep(30); ++ break; ++ } - 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 --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c -index ceb86338c003..1e486da92ac3 100644 ---- a/drivers/gpu/drm/tegra/dc.c -+++ b/drivers/gpu/drm/tegra/dc.c -@@ -1748,7 +1748,7 @@ static int tegra_dc_wait_idle(struct tegra_dc *dc, unsigned long timeout) - } - - 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; -@@ -1805,10 +1805,10 @@ static void tegra_crtc_atomic_disable(struct drm_crtc *crtc, + return 0; } - - static void tegra_crtc_atomic_enable(struct drm_crtc *crtc, -- struct drm_crtc_state *old_state) -+ struct drm_atomic_state *state) +@@ -463,7 +639,14 @@ static int st7701_disable(struct drm_panel *panel) { - 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; -@@ -1888,7 +1888,7 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc, - 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); -@@ -1924,7 +1924,7 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc, - } + struct st7701 *st7701 = panel_to_st7701(panel); - 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; +- ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_OFF, 0x00); ++ switch (st7701->desc->interface) { ++ case ST7701_CTRL_DSI: ++ ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_OFF, 0x00); ++ break; ++ case ST7701_CTRL_SPI: ++ ST7701_SPI(st7701, MIPI_DCS_SET_DISPLAY_OFF); ++ break; ++ } -@@ -1943,17 +1943,17 @@ static void tegra_crtc_atomic_begin(struct drm_crtc *crtc, + return 0; } - - 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 --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c -index 3c5744a91d4a..2218da3b3ca3 100644 ---- a/drivers/gpu/drm/tidss/tidss_crtc.c -+++ b/drivers/gpu/drm/tidss/tidss_crtc.c -@@ -85,8 +85,10 @@ void tidss_crtc_error_irq(struct drm_crtc *crtc, u64 irqstatus) - /* drm_crtc_helper_funcs */ - - static int tidss_crtc_atomic_check(struct drm_crtc *crtc, -- struct drm_crtc_state *state) -+ struct drm_atomic_state *state) +@@ -472,7 +655,14 @@ static int st7701_unprepare(struct drm_panel *panel) { -+ 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; -@@ -97,10 +99,10 @@ static int tidss_crtc_atomic_check(struct drm_crtc *crtc, - - dev_dbg(ddev->dev, "%s\n", __func__); - -- if (!state->enable) -+ if (!crtc_state->enable) - return 0; + struct st7701 *st7701 = panel_to_st7701(panel); -- mode = &state->adjusted_mode; -+ mode = &crtc_state->adjusted_mode; - - ok = dispc_vp_mode_valid(dispc, hw_videoport, mode); - if (ok != MODE_OK) { -@@ -109,7 +111,7 @@ static int tidss_crtc_atomic_check(struct drm_crtc *crtc, - return -EINVAL; - } +- ST7701_DSI(st7701, MIPI_DCS_ENTER_SLEEP_MODE, 0x00); ++ switch (st7701->desc->interface) { ++ case ST7701_CTRL_DSI: ++ ST7701_DSI(st7701, MIPI_DCS_ENTER_SLEEP_MODE, 0x00); ++ break; ++ case ST7701_CTRL_SPI: ++ ST7701_SPI(st7701, MIPI_DCS_ENTER_SLEEP_MODE); ++ break; ++ } -- return dispc_vp_bus_check(dispc, hw_videoport, state); -+ return dispc_vp_bus_check(dispc, hw_videoport, crtc_state); - } + msleep(st7701->sleep_delay); - /* -@@ -161,8 +163,10 @@ static void tidss_crtc_position_planes(struct tidss_device *tidss, - } +@@ -503,7 +693,7 @@ static int st7701_get_modes(struct drm_panel *panel, - 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); -@@ -212,8 +216,10 @@ static void tidss_crtc_atomic_flush(struct drm_crtc *crtc, - } + mode = drm_mode_duplicate(connector->dev, desc_mode); + if (!mode) { +- dev_err(&st7701->dsi->dev, "failed to add mode %ux%u@%u\n", ++ dev_err(st7701->dev, "failed to add mode %ux%u@%u\n", + desc_mode->hdisplay, desc_mode->vdisplay, + drm_mode_vrefresh(desc_mode)); + return -ENOMEM; +@@ -512,6 +702,12 @@ static int st7701_get_modes(struct drm_panel *panel, + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + ++ if (st7701->desc->mediabus_format) ++ drm_display_info_set_bus_formats(&connector->display_info, ++ &st7701->desc->mediabus_format, ++ 1); ++ connector->display_info.bus_flags = 0; ++ + connector->display_info.width_mm = desc_mode->width_mm; + connector->display_info.height_mm = desc_mode->height_mm; - 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); -@@ -255,7 +261,7 @@ static void tidss_crtc_atomic_enable(struct drm_crtc *crtc, - } +@@ -521,6 +717,9 @@ static int st7701_get_modes(struct drm_panel *panel, + */ + drm_connector_set_panel_orientation(connector, st7701->orientation); - 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 --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c -index 0aaa4a26b5db..c7c1fcc03b32 100644 ---- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c -+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c -@@ -484,7 +484,7 @@ static void tilcdc_crtc_enable(struct drm_crtc *crtc) ++ if (st7701->desc->bus_flags) ++ connector->display_info.bus_flags = st7701->desc->bus_flags; ++ + return 1; } - static void tilcdc_crtc_atomic_enable(struct drm_crtc *crtc, -- struct drm_crtc_state *old_state) -+ struct drm_atomic_state *state) +@@ -564,6 +763,9 @@ static const struct st7701_panel_desc ts8550b_desc = { + .lanes = 2, + .format = MIPI_DSI_FMT_RGB888, + .panel_sleep_delay = 80, /* panel need extra 80ms for sleep out cmd */ ++ .init_sequence = ts8550b_init_sequence, ++ .conn_type = DRM_MODE_CONNECTOR_DSI, ++ .interface = ST7701_CTRL_DSI, + + .pv_gamma = { + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | +@@ -759,6 +961,26 @@ static const struct drm_display_mode kd50t048a_mode = { + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, + }; + ++static const struct drm_display_mode txw210001b0_mode = { ++ .clock = 19200, ++ ++ .hdisplay = 480, ++ .hsync_start = 480 + 10, ++ .hsync_end = 480 + 10 + 16, ++ .htotal = 480 + 10 + 16 + 56, ++ ++ .vdisplay = 480, ++ .vsync_start = 480 + 15, ++ .vsync_end = 480 + 15 + 60, ++ .vtotal = 480 + 15 + 60 + 15, ++ ++ .width_mm = 53, ++ .height_mm = 53, ++ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, ++ ++ .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, ++}; ++ + static const struct st7701_panel_desc kd50t048a_desc = { + .mode = &kd50t048a_mode, + .lanes = 2, +@@ -839,42 +1061,54 @@ static const struct st7701_panel_desc kd50t048a_desc = { + .gip_sequence = kd50t048a_gip_sequence, + }; + +-static int st7701_dsi_probe(struct mipi_dsi_device *dsi) ++static const struct st7701_panel_desc txw210001b0_desc = { ++ .mode = &txw210001b0_mode, ++ .mediabus_format = MEDIA_BUS_FMT_RGB888_1X24, ++ .init_sequence = txw210001b0_init_sequence, ++ .conn_type = DRM_MODE_CONNECTOR_DPI, ++ .interface = ST7701_CTRL_SPI, ++ .bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, ++}; ++ ++static const struct st7701_panel_desc hyperpixel2r_desc = { ++ .mode = &txw210001b0_mode, ++ .mediabus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI, ++ .init_sequence = txw210001b0_init_sequence, ++ .conn_type = DRM_MODE_CONNECTOR_DPI, ++ .interface = ST7701_CTRL_SPI, ++ .bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, ++}; ++ ++static int st7701_probe(struct device *dev, struct st7701 **ret_st7701) { - tilcdc_crtc_enable(crtc); - } -@@ -541,13 +541,13 @@ static void tilcdc_crtc_disable(struct drm_crtc *crtc) - } + const struct st7701_panel_desc *desc; + struct st7701 *st7701; + int ret; - 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); - } +- st7701 = devm_kzalloc(&dsi->dev, sizeof(*st7701), GFP_KERNEL); ++ st7701 = devm_kzalloc(dev, sizeof(*st7701), GFP_KERNEL); + if (!st7701) + return -ENOMEM; - 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; -@@ -669,15 +669,17 @@ static bool tilcdc_crtc_mode_fixup(struct drm_crtc *crtc, - } +- desc = of_device_get_match_data(&dsi->dev); +- dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | +- MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS; +- dsi->format = desc->format; +- dsi->lanes = desc->lanes; ++ desc = of_device_get_match_data(dev); ++ if (!desc) ++ return -EINVAL; - 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; + st7701->supplies0.supply = "VCC"; + st7701->supplies1.supply = "IOVCC"; + +- ret = devm_regulator_bulk_get(&dsi->dev, ARRAY_SIZE(st7701->supplies), ++ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(st7701->supplies), + st7701->supplies); + if (ret < 0) + return ret; -- if (state->state->planes0.ptr != crtc->primary || -- state->state->planes0.state == NULL || -- state->state->planes0.state->crtc != crtc) { -+ if (state->planes0.ptr != crtc->primary || -+ state->planes0.state == NULL || -+ state->planes0.state->crtc != crtc) { - dev_dbg(crtc->dev->dev, "CRTC primary plane must be present"); - return -EINVAL; +- st7701->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); ++ st7701->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(st7701->reset)) { +- dev_err(&dsi->dev, "Couldn't get our reset GPIO\n"); ++ dev_err(dev, "Couldn't get our reset GPIO\n"); + return PTR_ERR(st7701->reset); } -diff --git a/drivers/gpu/drm/v3d/Kconfig b/drivers/gpu/drm/v3d/Kconfig -index 9a5c44606337..b0e048697964 100644 ---- a/drivers/gpu/drm/v3d/Kconfig -+++ b/drivers/gpu/drm/v3d/Kconfig -@@ -1,7 +1,7 @@ - # 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 --git a/drivers/gpu/drm/v3d/v3d_debugfs.c b/drivers/gpu/drm/v3d/v3d_debugfs.c -index e76b24bb8828..b7b296bb87d0 100644 ---- a/drivers/gpu/drm/v3d/v3d_debugfs.c -+++ b/drivers/gpu/drm/v3d/v3d_debugfs.c -@@ -4,7 +4,6 @@ - #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> -@@ -130,11 +129,8 @@ static int v3d_v3d_debugfs_ident(struct seq_file *m, void *unused) - 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); +- ret = of_drm_get_panel_orientation(dsi->dev.of_node, &st7701->orientation); - if (ret < 0) -- return ret; - - ident0 = V3D_READ(V3D_HUB_IDENT0); - ident1 = V3D_READ(V3D_HUB_IDENT1); -@@ -187,9 +183,6 @@ static int v3d_v3d_debugfs_ident(struct seq_file *m, void *unused) - (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0); - } - -- pm_runtime_mark_last_busy(v3d->drm.dev); -- pm_runtime_put_autosuspend(v3d->drm.dev); -- - return 0; - } - -@@ -217,11 +210,6 @@ static int v3d_measure_clock(struct seq_file *m, void *unused) - uint32_t cycles; - int core = 0; - int measure_ms = 1000; -- int ret; +- return dev_err_probe(&dsi->dev, ret, "Failed to get orientation\n"); - -- 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, -@@ -245,8 +233,6 @@ static int v3d_measure_clock(struct seq_file *m, void *unused) - 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 --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c -index 9f7c26193831..3237f47a4792 100644 ---- a/drivers/gpu/drm/v3d/v3d_drv.c -+++ b/drivers/gpu/drm/v3d/v3d_drv.c -@@ -70,7 +70,7 @@ static int v3d_runtime_resume(struct device *dev) - } - #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) - }; - -@@ -79,7 +79,6 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data, - { - 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, -@@ -105,17 +104,12 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data, - 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; - } - -@@ -227,6 +221,7 @@ static struct drm_driver v3d_drm_driver = { - 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); -@@ -268,8 +263,8 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) - return ret; +- drm_panel_init(&st7701->panel, &dsi->dev, &st7701_funcs, +- DRM_MODE_CONNECTOR_DSI); ++ drm_panel_init(&st7701->panel, dev, &st7701_funcs, ++ desc->conn_type); - 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); + /** + * Once sleep out has been issued, ST7701 IC required to wait 120ms +@@ -893,14 +1127,39 @@ static int st7701_dsi_probe(struct mipi_dsi_device *dsi) - ident1 = V3D_READ(V3D_HUB_IDENT1); -@@ -294,6 +289,21 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) - } - } + drm_panel_add(&st7701->panel); -+ 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; ++ st7701->desc = desc; ++ st7701->dev = dev; + - if (v3d->ver < 41) { - ret = map_regs(v3d, &v3d->gca_regs, "gca"); - if (ret) -@@ -307,9 +317,6 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) - return -ENOMEM; - } - -- pm_runtime_use_autosuspend(dev); -- pm_runtime_set_autosuspend_delay(dev, 50); -- pm_runtime_enable(dev); ++ *ret_st7701 = st7701; ++ ++ return 0; ++} ++ ++static int st7701_dsi_probe(struct mipi_dsi_device *dsi) ++{ ++ struct st7701 *st7701; ++ int ret; ++ ++ ret = st7701_probe(&dsi->dev, &st7701); ++ ++ if (ret) ++ return ret; ++ ++ dsi->mode_flags = MIPI_DSI_MODE_VIDEO; ++ dsi->format = st7701->desc->format; ++ dsi->lanes = st7701->desc->lanes; ++ + mipi_dsi_set_drvdata(dsi, st7701); + st7701->dsi = dsi; +- st7701->desc = desc; - ret = v3d_gem_init(drm); + ret = mipi_dsi_attach(dsi); if (ret) -@@ -323,6 +330,9 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) - if (ret) - goto irq_disable; + goto err_attach; -+ ret = clk_set_rate(v3d->clk, v3d->clk_down_rate); -+ WARN_ON_ONCE(ret != 0); ++ ret = of_drm_get_panel_orientation(dsi->dev.of_node, &st7701->orientation); ++ if (ret < 0) ++ return dev_err_probe(&dsi->dev, ret, "Failed to get orientation\n"); + return 0; - irq_disable: -@@ -355,6 +365,7 @@ static struct platform_driver v3d_platform_driver = { - .driver = { - .name = "v3d", - .of_match_table = v3d_of_match, -+ .pm = &v3d_pm_ops, + err_attach: +@@ -916,23 +1175,115 @@ static void st7701_dsi_remove(struct mipi_dsi_device *dsi) + drm_panel_remove(&st7701->panel); + } + +-static const struct of_device_id st7701_of_match = { ++static const struct of_device_id st7701_dsi_of_match = { + { .compatible = "densitron,dmt028vghmcmi-1a", .data = &dmt028vghmcmi_1a_desc }, + { .compatible = "elida,kd50t048a", .data = &kd50t048a_desc }, + { .compatible = "techstar,ts8550b", .data = &ts8550b_desc }, + { } + }; +-MODULE_DEVICE_TABLE(of, st7701_of_match); ++MODULE_DEVICE_TABLE(of, st7701_dsi_of_match); + + static struct mipi_dsi_driver st7701_dsi_driver = { + .probe = st7701_dsi_probe, + .remove = st7701_dsi_remove, + .driver = { + .name = "st7701", +- .of_match_table = st7701_of_match, ++ .of_match_table = st7701_dsi_of_match, }, }; - -diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h -index 8a390738d65b..1372e913e765 100644 ---- a/drivers/gpu/drm/v3d/v3d_drv.h -+++ b/drivers/gpu/drm/v3d/v3d_drv.h -@@ -51,6 +51,12 @@ struct v3d_dev { - 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; +-module_mipi_dsi_driver(st7701_dsi_driver); + - struct reset_control *reset; - - /* Virtual and DMA addresses of the single shared page table. */ -diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c -index 64fe63c1938f..59a5e0f8fa3b 100644 ---- a/drivers/gpu/drm/v3d/v3d_gem.c -+++ b/drivers/gpu/drm/v3d/v3d_gem.c -@@ -4,6 +4,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> -@@ -18,6 +19,47 @@ - #include "v3d_regs.h" - #include "v3d_trace.h" - -+static void -+v3d_clock_down_work(struct work_struct *work) ++/* SPI display probe */ ++static const struct of_device_id st7701_spi_of_match = { ++ { .compatible = "txw,txw210001b0", ++ .data = &txw210001b0_desc, ++ }, { ++ .compatible = "pimoroni,hyperpixel2round", ++ .data = &hyperpixel2r_desc, ++ }, { ++ /* sentinel */ ++ } ++}; ++MODULE_DEVICE_TABLE(of, st7701_spi_of_match); ++ ++static int st7701_spi_probe(struct spi_device *spi) +{ -+ struct v3d_dev *v3d = -+ container_of(work, struct v3d_dev, clk_down_work.work); ++ struct st7701 *st7701; + int ret; + -+ ret = clk_set_rate(v3d->clk, v3d->clk_down_rate); -+ v3d->clk_up = false; -+ WARN_ON_ONCE(ret != 0); ++ spi->mode = SPI_MODE_3; ++ spi->bits_per_word = 9; ++ ret = spi_setup(spi); ++ if (ret < 0) { ++ dev_err(&spi->dev, "failed to setup SPI: %d\n", ret); ++ return ret; ++ } ++ ++ ret = st7701_probe(&spi->dev, &st7701); ++ ++ if (ret) ++ return ret; ++ ++ spi_set_drvdata(spi, st7701); ++ st7701->spi = spi; ++ ++ return 0; +} + -+static void -+v3d_clock_up_get(struct v3d_dev *v3d) ++static void st7701_spi_remove(struct spi_device *spi) +{ -+ mutex_lock(&v3d->clk_lock); -+ if (v3d->clk_refcount++ == 0) { -+ cancel_delayed_work_sync(&v3d->clk_down_work); -+ if (!v3d->clk_up) { -+ int ret; ++ struct st7701 *ctx = spi_get_drvdata(spi); + -+ ret = clk_set_rate(v3d->clk, v3d->clk_up_rate); -+ WARN_ON_ONCE(ret != 0); -+ v3d->clk_up = true; -+ } -+ } -+ mutex_unlock(&v3d->clk_lock); ++ drm_panel_remove(&ctx->panel); +} + -+static void -+v3d_clock_up_put(struct v3d_dev *v3d) ++static const struct spi_device_id st7701_spi_ids = { ++ { "txw210001b0", 0 }, ++ { "hyperpixel2round", 0 }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(spi, st7701_spi_ids); ++ ++static struct spi_driver st7701_spi_driver = { ++ .probe = st7701_spi_probe, ++ .remove = st7701_spi_remove, ++ .driver = { ++ .name = "st7701", ++ .of_match_table = st7701_spi_of_match, ++ }, ++ .id_table = st7701_spi_ids, ++}; ++ ++static int __init panel_st7701_init(void) +{ -+ mutex_lock(&v3d->clk_lock); -+ if (--v3d->clk_refcount == 0) { -+ schedule_delayed_work(&v3d->clk_down_work, -+ msecs_to_jiffies(100)); ++ int err; ++ ++ err = spi_register_driver(&st7701_spi_driver); ++ if (err < 0) ++ return err; ++ ++ if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) { ++ err = mipi_dsi_driver_register(&st7701_dsi_driver); ++ if (err < 0) ++ goto err_did_spi_register; + } -+ mutex_unlock(&v3d->clk_lock); -+} + ++ return 0; + - static void - v3d_init_core(struct v3d_dev *v3d, int core) - { -@@ -354,6 +396,7 @@ v3d_job_free(struct kref *ref) - 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++) { -@@ -370,8 +413,7 @@ v3d_job_free(struct kref *ref) - 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); - } -@@ -439,10 +481,6 @@ v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, - 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); -@@ -453,12 +491,12 @@ v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, - 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; - } - -@@ -879,6 +917,13 @@ v3d_gem_init(struct drm_device *dev) - 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); ++err_did_spi_register: ++ spi_unregister_driver(&st7701_spi_driver); + -+ /* kick the clock so firmware knows we are using firmware clock interface */ -+ v3d_clock_up_get(v3d); -+ v3d_clock_up_put(v3d); ++ return err; ++} ++module_init(panel_st7701_init); + - /* 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 --git a/drivers/gpu/drm/v3d/v3d_irq.c b/drivers/gpu/drm/v3d/v3d_irq.c -index c88686489b88..0f7a23f051df 100644 ---- a/drivers/gpu/drm/v3d/v3d_irq.c -+++ b/drivers/gpu/drm/v3d/v3d_irq.c -@@ -177,11 +177,9 @@ v3d_hub_irq(int irq, void *arg) - "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; -@@ -189,6 +187,7 @@ v3d_hub_irq(int irq, void *arg) - client = v3d41_axi_idsaxi_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) ? -@@ -197,6 +196,7 @@ v3d_hub_irq(int irq, void *arg) - ", pte invalid" : ""), - ((intsts & V3D_HUB_INT_MMU_CAP) ? - ", cap exceeded" : "")); -+ logged_error = 1; - status = IRQ_HANDLED; - } - -@@ -217,7 +217,7 @@ v3d_irq_init(struct v3d_dev *v3d) - 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 --git a/drivers/gpu/drm/v3d/v3d_mmu.c b/drivers/gpu/drm/v3d/v3d_mmu.c -index 5a453532901f..618503f2f2f1 100644 ---- a/drivers/gpu/drm/v3d/v3d_mmu.c -+++ b/drivers/gpu/drm/v3d/v3d_mmu.c -@@ -18,6 +18,8 @@ - * each client. This is not yet implemented. - */ - -+#include <linux/pm_runtime.h> ++static void __exit panel_st7701_exit(void) ++{ ++ if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) ++ mipi_dsi_driver_unregister(&st7701_dsi_driver); + - #include "v3d_drv.h" - #include "v3d_regs.h" - -diff --git a/drivers/gpu/drm/vboxvideo/vbox_mode.c b/drivers/gpu/drm/vboxvideo/vbox_mode.c -index 4fcc0a542b8a..322bf7133ba1 100644 ---- a/drivers/gpu/drm/vboxvideo/vbox_mode.c -+++ b/drivers/gpu/drm/vboxvideo/vbox_mode.c -@@ -213,17 +213,17 @@ static void vbox_crtc_set_base_and_mode(struct drm_crtc *crtc, - } - - 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) - { - } ++ spi_unregister_driver(&st7701_spi_driver); ++} ++module_exit(panel_st7701_exit); -diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig -index 118e8a426b1a..345a5570a3da 100644 ---- a/drivers/gpu/drm/vc4/Kconfig -+++ b/drivers/gpu/drm/vc4/Kconfig -@@ -12,6 +12,7 @@ config DRM_VC4 - 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 --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile -index d0163e18e9ca..8281a044834f 100644 ---- a/drivers/gpu/drm/vc4/Makefile -+++ b/drivers/gpu/drm/vc4/Makefile -@@ -9,6 +9,7 @@ vc4-y := \ - vc4_dpi.o \ - vc4_dsi.o \ - vc4_fence.o \ -+ vc4_firmware_kms.o \ - vc4_kms.o \ - vc4_gem.o \ - vc4_hdmi.o \ -diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c -index f4ccca922e44..f73d73425f08 100644 ---- a/drivers/gpu/drm/vc4/vc4_crtc.c -+++ b/drivers/gpu/drm/vc4/vc4_crtc.c -@@ -279,19 +279,32 @@ static u32 vc4_crtc_get_fifo_full_level_bits(struct vc4_crtc *vc4_crtc, - * 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_encoder *encoder; + MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>"); + MODULE_DESCRIPTION("Sitronix ST7701 LCD Panel Driver"); +diff --git a/drivers/gpu/drm/panel/panel-tdo-y17p.c b/drivers/gpu/drm/panel/panel-tdo-y17p.c +new file mode 100644 +index 000000000000..28c2a33691fd +--- /dev/null ++++ b/drivers/gpu/drm/panel/panel-tdo-y17p.c +@@ -0,0 +1,277 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * TDO Y17P TFT LCD drm_panel driver. ++ * ++ * SPI configured DPI display controller ++ * Copyright (C) 2022 Raspberry Pi Ltd ++ * ++ * Derived from drivers/drm/gpu/panel/panel-sitronix-st7789v.c ++ * Copyright (C) 2017 Free Electrons ++ */ + -+ WARN_ON(hweight32(state->encoder_mask) > 1); ++#include <drm/drm_modes.h> ++#include <drm/drm_panel.h> + -+ drm_for_each_encoder_mask(encoder, crtc->dev, state->encoder_mask) -+ return encoder; ++#include <linux/bitops.h> ++#include <linux/gpio/consumer.h> ++#include <linux/media-bus-format.h> ++#include <linux/module.h> ++#include <linux/of_device.h> ++#include <linux/regmap.h> ++#include <linux/regulator/consumer.h> ++#include <linux/spi/spi.h> + -+ return NULL; -+} ++#include <video/mipi_display.h> ++#include <video/of_videomode.h> ++#include <video/videomode.h> + -+#define drm_for_each_connector_mask(connector, dev, connector_mask) \ -+ list_for_each_entry((connector), &(dev)->mode_config.connector_list, head) \ -+ for_each_if ((connector_mask) & drm_connector_mask(connector)) ++struct tdo_y17p { ++ struct drm_panel panel; ++ struct spi_device *spi; ++ struct gpio_desc *reset; ++ struct regulator *power; ++ u32 bus_format; ++}; + -+struct drm_connector *vc4_get_crtc_connector(struct drm_crtc *crtc, -+ struct drm_crtc_state *state) - { - struct drm_connector *connector; -- struct drm_connector_list_iter conn_iter; - -- 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->connector_mask) > 1); ++static const u16 panel_init = { ++ 0x0ff, 0x1ff, 0x198, 0x106, 0x104, 0x101, 0x008, 0x110, ++ 0x021, 0x109, 0x030, 0x102, 0x031, 0x100, 0x040, 0x110, ++ 0x041, 0x155, 0x042, 0x102, 0x043, 0x109, 0x044, 0x107, ++ 0x050, 0x178, 0x051, 0x178, 0x052, 0x100, 0x053, 0x16d, ++ 0x060, 0x107, 0x061, 0x100, 0x062, 0x108, 0x063, 0x100, ++ 0x0a0, 0x100, 0x0a1, 0x107, 0x0a2, 0x10c, 0x0a3, 0x10b, ++ 0x0a4, 0x103, 0x0a5, 0x107, 0x0a6, 0x106, 0x0a7, 0x104, ++ 0x0a8, 0x108, 0x0a9, 0x10c, 0x0aa, 0x113, 0x0ab, 0x106, ++ 0x0ac, 0x10d, 0x0ad, 0x119, 0x0ae, 0x110, 0x0af, 0x100, ++ 0x0c0, 0x100, 0x0c1, 0x107, 0x0c2, 0x10c, 0x0c3, 0x10b, ++ 0x0c4, 0x103, 0x0c5, 0x107, 0x0c6, 0x107, 0x0c7, 0x104, ++ 0x0c8, 0x108, 0x0c9, 0x10c, 0x0ca, 0x113, 0x0cb, 0x106, ++ 0x0cc, 0x10d, 0x0cd, 0x118, 0x0ce, 0x110, 0x0cf, 0x100, ++ 0x0ff, 0x1ff, 0x198, 0x106, 0x104, 0x106, 0x000, 0x120, ++ 0x001, 0x10a, 0x002, 0x100, 0x003, 0x100, 0x004, 0x101, ++ 0x005, 0x101, 0x006, 0x198, 0x007, 0x106, 0x008, 0x101, ++ 0x009, 0x180, 0x00a, 0x100, 0x00b, 0x100, 0x00c, 0x101, ++ 0x00d, 0x101, 0x00e, 0x100, 0x00f, 0x100, 0x010, 0x1f0, ++ 0x011, 0x1f4, 0x012, 0x101, 0x013, 0x100, 0x014, 0x100, ++ 0x015, 0x1c0, 0x016, 0x108, 0x017, 0x100, 0x018, 0x100, ++ 0x019, 0x100, 0x01a, 0x100, 0x01b, 0x100, 0x01c, 0x100, ++ 0x01d, 0x100, 0x020, 0x101, 0x021, 0x123, 0x022, 0x145, ++ 0x023, 0x167, 0x024, 0x101, 0x025, 0x123, 0x026, 0x145, ++ 0x027, 0x167, 0x030, 0x111, 0x031, 0x111, 0x032, 0x100, ++ 0x033, 0x1ee, 0x034, 0x1ff, 0x035, 0x1bb, 0x036, 0x1aa, ++ 0x037, 0x1dd, 0x038, 0x1cc, 0x039, 0x166, 0x03a, 0x177, ++ 0x03b, 0x122, 0x03c, 0x122, 0x03d, 0x122, 0x03e, 0x122, ++ 0x03f, 0x122, 0x040, 0x122, 0x052, 0x110, 0x053, 0x110, ++ 0x0ff, 0x1ff, 0x198, 0x106, 0x104, 0x107, 0x018, 0x11d, ++ 0x017, 0x122, 0x002, 0x177, 0x026, 0x1b2, 0x0e1, 0x179, ++ 0x0ff, 0x1ff, 0x198, 0x106, 0x104, 0x100, 0x03a, 0x160, ++ 0x035, 0x100, 0x011, 0x100, ++}; ++ ++#define NUM_INIT_REGS ARRAY_SIZE(panel_init) ++ ++static inline struct tdo_y17p *panel_to_tdo_y17p(struct drm_panel *panel) ++{ ++ return container_of(panel, struct tdo_y17p, panel); ++} ++ ++static int tdo_y17p_write_msg(struct tdo_y17p *ctx, const u16 *msg, unsigned int len) ++{ ++ struct spi_transfer xfer = { }; ++ struct spi_message spi; ++ ++ spi_message_init(&spi); ++ ++ xfer.tx_buf = msg; ++ xfer.bits_per_word = 9; ++ xfer.len = sizeof(u16) * len; ++ ++ spi_message_add_tail(&xfer, &spi); ++ return spi_sync(ctx->spi, &spi); ++} ++ ++static const struct drm_display_mode tdo_y17pe_720x720_mode = { ++ .clock = 36720, ++ .hdisplay = 720, ++ .hsync_start = 720 + 20, ++ .hsync_end = 720 + 20 + 20, ++ .htotal = 720 + 20 + 20 + 40, ++ .vdisplay = 720, ++ .vsync_start = 720 + 15, ++ .vsync_end = 720 + 15 + 15, ++ .vtotal = 720 + 15 + 15 + 15, ++ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC, ++}; + -+ drm_for_each_connector_mask(connector, crtc->dev, state->connector_mask) -+ return connector; - - return NULL; - } -@@ -305,22 +318,29 @@ static void vc4_crtc_pixelvalve_reset(struct drm_crtc *crtc) - 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; ++static int tdo_y17p_get_modes(struct drm_panel *panel, ++ struct drm_connector *connector) ++{ ++ struct tdo_y17p *ctx = panel_to_tdo_y17p(panel); ++ struct drm_display_mode *mode; + - bool debug_dump_regs = false; - - if (debug_dump_regs) { -@@ -344,48 +364,60 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc) - 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; -+ } -+ } ++ mode = drm_mode_duplicate(connector->dev, &tdo_y17pe_720x720_mode); ++ if (!mode) { ++ dev_err(panel->dev, "failed to add mode %ux%ux@%u\n", ++ tdo_y17pe_720x720_mode.hdisplay, ++ tdo_y17pe_720x720_mode.vdisplay, ++ drm_mode_vrefresh(&tdo_y17pe_720x720_mode)); ++ return -ENOMEM; ++ } + -+ if (odd_field_first) -+ ++vert_fp_even; -+ else -+ ++vert_bp; ++ drm_mode_set_name(mode); + - 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_VSYNCD_EVEN, 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)); ++ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; ++ drm_mode_probed_add(connector, mode); + - if (is_dsi) - CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep); - -@@ -420,9 +452,11 @@ static void require_hvs_enabled(struct drm_device *dev) - 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; -@@ -452,21 +486,40 @@ static int vc4_crtc_disable(struct drm_crtc *crtc, unsigned int channel) - 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) ++ connector->display_info.width_mm = 72; ++ connector->display_info.height_mm = 72; ++ drm_display_info_set_bus_formats(&connector->display_info, ++ &ctx->bus_format, 1); ++ connector->display_info.bus_flags = 0; ++ ++ return 1; ++} ++ ++static int tdo_y17p_prepare(struct drm_panel *panel) +{ -+ struct drm_encoder *encoder; ++ struct tdo_y17p *ctx = panel_to_tdo_y17p(panel); ++ int ret; + -+ drm_for_each_encoder(encoder, crtc->dev) { -+ struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder); ++ ret = regulator_enable(ctx->power); ++ if (ret) ++ return ret; + -+ if (vc4_encoder->type == type) -+ return encoder; -+ } ++ ret = tdo_y17p_write_msg(ctx, panel_init, NUM_INIT_REGS); + -+ return NULL; ++ msleep(120); ++ ++ return ret; +} + - 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, -@@ -485,21 +538,37 @@ int vc4_crtc_disable_at_boot(struct drm_crtc *crtc) - 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; ++static int tdo_y17p_enable(struct drm_panel *panel) ++{ ++ struct tdo_y17p *ctx = panel_to_tdo_y17p(panel); ++ const u16 msg = { MIPI_DCS_SET_DISPLAY_ON }; ++ int ret; + -+ pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc); -+ encoder_type = pv_data->encoder_typesencoder_sel; -+ encoder = vc4_crtc_get_encoder_by_type(crtc, encoder_type); -+ if (WARN_ON(!encoder)) -+ return 0; ++ ret = tdo_y17p_write_msg(ctx, msg, ARRAY_SIZE(msg)); + -+ 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); ++ return ret; ++} + - 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 -@@ -516,13 +585,18 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc, - } - - 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); ++static int tdo_y17p_disable(struct drm_panel *panel) ++{ ++ struct tdo_y17p *ctx = panel_to_tdo_y17p(panel); ++ const u16 msg = { MIPI_DCS_SET_DISPLAY_OFF }; ++ int ret; + - require_hvs_enabled(dev); - - /* Enable vblank irq handling before crtc is started otherwise -@@ -530,17 +604,17 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc, - */ - 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. -@@ -549,7 +623,7 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc, - 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, -@@ -597,18 +671,36 @@ void vc4_crtc_get_margins(struct drm_crtc_state *state, - } - - 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); ++ ret = tdo_y17p_write_msg(ctx, msg, ARRAY_SIZE(msg)); + -+ 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; -+ } -+ } ++ return ret; ++} + -+ for_each_new_connector_in_state(state, conn, conn_state, -+ i) { - if (conn_state->crtc != crtc) - continue; - -@@ -643,14 +735,14 @@ 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; - struct vc4_dev *vc4 = to_vc4_dev(dev); -- struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); -- u32 chan = vc4_state->assigned_channel; -+ u32 chan = vc4_crtc->current_hvs_channel; - unsigned long flags; - - spin_lock_irqsave(&dev->event_lock, flags); -+ spin_lock(&vc4_crtc->irq_lock); - if (vc4_crtc->event && -- (vc4_state->mm.start == HVS_READ(SCALER_DISPLACTX(chan)) || -- vc4_state->feed_txp)) { -+ (vc4_crtc->current_dlist == HVS_READ(SCALER_DISPLACTX(chan)) || -+ vc4_crtc->feeds_txp)) { - drm_crtc_send_vblank_event(crtc, vc4_crtc->event); - vc4_crtc->event = NULL; - drm_crtc_vblank_put(crtc); -@@ -663,6 +755,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) - */ - vc4_hvs_unmask_underrun(dev, chan); - } -+ spin_unlock(&vc4_crtc->irq_lock); - spin_unlock_irqrestore(&dev->event_lock, flags); - } - -@@ -695,6 +788,7 @@ struct vc4_async_flip_state { - struct drm_pending_vblank_event *event; - - struct vc4_seqno_cb cb; -+ struct dma_fence_cb fence_cb; - }; - - /* Called when the V3D execution for the BO being flipped to is done, so that -@@ -743,6 +837,39 @@ vc4_async_page_flip_complete(struct vc4_seqno_cb *cb) - up(&vc4->async_modeset); - } - -+static void vc4_async_page_flip_fence_complete(struct dma_fence *fence, -+ struct dma_fence_cb *cb) ++static int tdo_y17p_unprepare(struct drm_panel *panel) +{ -+ struct vc4_async_flip_state *flip_state = -+ container_of(cb, struct vc4_async_flip_state, fence_cb); ++ struct tdo_y17p *ctx = panel_to_tdo_y17p(panel); ++ const u16 msg = { MIPI_DCS_ENTER_SLEEP_MODE }; ++ int ret; + -+ vc4_async_page_flip_complete(&flip_state->cb); -+ dma_fence_put(fence); ++ ret = tdo_y17p_write_msg(ctx, msg, ARRAY_SIZE(msg)); ++ ++ return ret; +} + -+static int vc4_async_set_fence_cb(struct drm_device *dev, -+ struct vc4_async_flip_state *flip_state) ++static const struct drm_panel_funcs tdo_y17p_drm_funcs = { ++ .disable = tdo_y17p_disable, ++ .enable = tdo_y17p_enable, ++ .get_modes = tdo_y17p_get_modes, ++ .prepare = tdo_y17p_prepare, ++ .unprepare = tdo_y17p_unprepare, ++}; ++ ++static const struct of_device_id tdo_y17p_of_match = { ++ { .compatible = "tdo,tl040hds20ct", ++ .data = (void *)MEDIA_BUS_FMT_BGR888_1X24, ++ }, { ++ .compatible = "pimoroni,hyperpixel4square", ++ .data = (void *)MEDIA_BUS_FMT_BGR666_1X24_CPADHI, ++ }, { ++ .compatible = "tdo,y17p", ++ .data = (void *)MEDIA_BUS_FMT_BGR888_1X24, ++ }, { ++ /* sentinel */ ++ } ++}; ++MODULE_DEVICE_TABLE(of, tdo_y17p_of_match); ++ ++static int tdo_y17p_probe(struct spi_device *spi) +{ -+ struct drm_framebuffer *fb = flip_state->fb; -+ struct drm_gem_cma_object *cma_bo = drm_fb_cma_get_gem_obj(fb, 0); -+ struct vc4_dev *vc4 = to_vc4_dev(dev); -+ struct dma_fence *fence; ++ const struct of_device_id *id; ++ struct tdo_y17p *ctx; ++ int ret; ++ ++ ctx = devm_kzalloc(&spi->dev, sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ ++ id = of_match_node(tdo_y17p_of_match, spi->dev.of_node); ++ if (!id) ++ return -ENODEV; ++ ++ ctx->bus_format = (u32)(uintptr_t)id->data; ++ ++ spi_set_drvdata(spi, ctx); ++ ctx->spi = spi; ++ ++ drm_panel_init(&ctx->panel, &spi->dev, &tdo_y17p_drm_funcs, ++ DRM_MODE_CONNECTOR_DPI); + -+ if (!vc4->hvs->hvs5) { -+ struct vc4_bo *bo = to_vc4_bo(&cma_bo->base); ++ ctx->power = devm_regulator_get(&spi->dev, "power"); ++ if (IS_ERR(ctx->power)) ++ return PTR_ERR(ctx->power); + -+ return vc4_queue_seqno_cb(dev, &flip_state->cb, bo->seqno, -+ vc4_async_page_flip_complete); ++ ctx->reset = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW); ++ if (IS_ERR(ctx->reset)) { ++ dev_err(&spi->dev, "Couldn't get our reset line\n"); ++ return PTR_ERR(ctx->reset); + } + -+ fence = dma_fence_get(dma_resv_get_excl(cma_bo->base.resv)); -+ if (dma_fence_add_callback(fence, &flip_state->fence_cb, -+ vc4_async_page_flip_fence_complete)) -+ vc4_async_page_flip_fence_complete(fence, &flip_state->fence_cb); ++ ret = drm_panel_of_backlight(&ctx->panel); ++ if (ret) ++ return ret; ++ ++ drm_panel_add(&ctx->panel); + + return 0; +} + - /* Implements async (non-vblank-synced) page flips. - * - * The page flip ioctl needs to return immediately, so we grab the -@@ -813,8 +940,7 @@ static int vc4_async_page_flip(struct drm_crtc *crtc, - */ - drm_atomic_set_fb_for_plane(plane->state, fb); - -- vc4_queue_seqno_cb(dev, &flip_state->cb, bo->seqno, -- vc4_async_page_flip_complete); -+ vc4_async_set_fence_cb(dev, flip_state); - - /* Driver takes ownership of state on successful async commit. */ - return 0; -@@ -841,7 +967,6 @@ struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc) - return NULL; - - old_vc4_state = to_vc4_crtc_state(crtc->state); -- vc4_state->feed_txp = old_vc4_state->feed_txp; - vc4_state->margins = old_vc4_state->margins; - vc4_state->assigned_channel = old_vc4_state->assigned_channel; - -@@ -894,7 +1019,6 @@ static const struct drm_crtc_funcs vc4_crtc_funcs = { - .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, -@@ -903,6 +1027,7 @@ static const struct drm_crtc_funcs vc4_crtc_funcs = { - static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = { - .mode_valid = vc4_crtc_mode_valid, - .atomic_check = vc4_crtc_atomic_check, -+ .atomic_begin = vc4_hvs_atomic_begin, - .atomic_flush = vc4_hvs_atomic_flush, - .atomic_enable = vc4_crtc_atomic_enable, - .atomic_disable = vc4_crtc_atomic_disable, -@@ -1077,25 +1202,43 @@ int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc, - return PTR_ERR(primary_plane); - } - -+ spin_lock_init(&vc4_crtc->irq_lock); - drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL, - crtc_funcs, NULL); - drm_crtc_helper_add(crtc, crtc_helper_funcs); - - if (!vc4->hvs->hvs5) { - drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r)); -- - drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size); -+ } ++static void tdo_y17p_remove(struct spi_device *spi) ++{ ++ struct tdo_y17p *ctx = spi_get_drvdata(spi); + - -+ if (!vc4->hvs->hvs5) { - /* We support CTM, but only for one CRTC at a time. It's therefore - * implemented as private driver state in vc4_kms, not here. - */ -- drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size); -- } -+ drm_crtc_enable_color_mgmt(crtc, 0, true, 0); - -- for (i = 0; i < crtc->gamma_size; i++) { -- vc4_crtc->lut_ri = i; -- vc4_crtc->lut_gi = i; -- vc4_crtc->lut_bi = i; -+ /* Initialize the VC4 gamma LUTs */ -+ for (i = 0; i < crtc->gamma_size; i++) { -+ vc4_crtc->lut_ri = i; -+ vc4_crtc->lut_gi = i; -+ vc4_crtc->lut_bi = i; -+ } -+ } else { -+ /* Initialize the VC5 gamma PWL entries. Assume 12-bit pipeline, -+ * evenly spread over full range. -+ */ -+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++) { -+ vc4_crtc->pwl_ri = -+ VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8); -+ vc4_crtc->pwl_gi = -+ VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8); -+ vc4_crtc->pwl_bi = -+ VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8); -+ vc4_crtc->pwl_ai = -+ VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8); ++ drm_panel_remove(&ctx->panel); ++} ++ ++static const struct spi_device_id tdo_y17p_ids = { ++ { "tl040hds20ct", 0 }, ++ { "hyperpixel4square", 0 }, ++ { "y17p", 0 }, ++ { /* sentinel */ } ++}; ++ ++MODULE_DEVICE_TABLE(spi, tdo_y17p_ids); ++ ++static struct spi_driver tdo_y17p_driver = { ++ .probe = tdo_y17p_probe, ++ .remove = tdo_y17p_remove, ++ .driver = { ++ .name = "tdo_y17p", ++ .of_match_table = tdo_y17p_of_match, ++ }, ++ .id_table = tdo_y17p_ids, ++}; ++module_spi_driver(tdo_y17p_driver); ++ ++MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com>"); ++MODULE_DESCRIPTION("TDO Y17P LCD panel driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/gpu/drm/panel/panel-waveshare-dsi.c b/drivers/gpu/drm/panel/panel-waveshare-dsi.c +new file mode 100644 +index 000000000000..835b80a6a0ae +--- /dev/null ++++ b/drivers/gpu/drm/panel/panel-waveshare-dsi.c +@@ -0,0 +1,434 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright © 2023 Raspberry Pi Ltd ++ * ++ * Based on panel-raspberrypi-touchscreen by Broadcom ++ */ ++ ++#include <linux/backlight.h> ++#include <linux/delay.h> ++#include <linux/err.h> ++#include <linux/fb.h> ++#include <linux/i2c.h> ++#include <linux/media-bus-format.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/of_graph.h> ++#include <linux/pm.h> ++ ++#include <drm/drm_crtc.h> ++#include <drm/drm_device.h> ++#include <drm/drm_mipi_dsi.h> ++#include <drm/drm_panel.h> ++ ++#define WS_DSI_DRIVER_NAME "ws-ts-dsi" ++ ++struct ws_panel { ++ struct drm_panel base; ++ struct mipi_dsi_device *dsi; ++ struct i2c_client *i2c; ++ const struct drm_display_mode *mode; ++ enum drm_panel_orientation orientation; ++}; ++ ++/* 2.8inch 480x640 ++ * https://www.waveshare.com/product/raspberry-pi/displays/2.8inch-dsi-lcd.htm ++ */ ++static const struct drm_display_mode ws_panel_2_8_mode = { ++ .clock = 50000, ++ .hdisplay = 480, ++ .hsync_start = 480 + 150, ++ .hsync_end = 480 + 150 + 50, ++ .htotal = 480 + 150 + 50 + 150, ++ .vdisplay = 640, ++ .vsync_start = 640 + 150, ++ .vsync_end = 640 + 150 + 50, ++ .vtotal = 640 + 150 + 50 + 150, ++}; ++ ++/* 3.4inch 800x800 Round ++ * https://www.waveshare.com/product/displays/lcd-oled/3.4inch-dsi-lcd-c.htm ++ */ ++static const struct drm_display_mode ws_panel_3_4_mode = { ++ .clock = 50000, ++ .hdisplay = 800, ++ .hsync_start = 800 + 32, ++ .hsync_end = 800 + 32 + 6, ++ .htotal = 800 + 32 + 6 + 120, ++ .vdisplay = 800, ++ .vsync_start = 800 + 8, ++ .vsync_end = 800 + 8 + 4, ++ .vtotal = 800 + 8 + 4 + 16, ++}; ++ ++/* 4.0inch 480x800 ++ * https://www.waveshare.com/product/raspberry-pi/displays/4inch-dsi-lcd.htm ++ */ ++static const struct drm_display_mode ws_panel_4_0_mode = { ++ .clock = 50000, ++ .hdisplay = 480, ++ .hsync_start = 480 + 150, ++ .hsync_end = 480 + 150 + 100, ++ .htotal = 480 + 150 + 100 + 150, ++ .vdisplay = 800, ++ .vsync_start = 800 + 20, ++ .vsync_end = 800 + 20 + 100, ++ .vtotal = 800 + 20 + 100 + 20, ++}; ++ ++/* 7.0inch C 1024x600 ++ * https://www.waveshare.com/product/raspberry-pi/displays/lcd-oled/7inch-dsi-lcd-c-with-case-a.htm ++ */ ++static const struct drm_display_mode ws_panel_7_0_c_mode = { ++ .clock = 50000, ++ .hdisplay = 1024, ++ .hsync_start = 1024 + 100, ++ .hsync_end = 1024 + 100 + 100, ++ .htotal = 1024 + 100 + 100 + 100, ++ .vdisplay = 600, ++ .vsync_start = 600 + 10, ++ .vsync_end = 600 + 10 + 10, ++ .vtotal = 600 + 10 + 10 + 10, ++}; ++ ++/* 7.9inch 400x1280 ++ * https://www.waveshare.com/product/raspberry-pi/displays/7.9inch-dsi-lcd.htm ++ */ ++static const struct drm_display_mode ws_panel_7_9_mode = { ++ .clock = 50000, ++ .hdisplay = 400, ++ .hsync_start = 400 + 40, ++ .hsync_end = 400 + 40 + 30, ++ .htotal = 400 + 40 + 30 + 40, ++ .vdisplay = 1280, ++ .vsync_start = 1280 + 20, ++ .vsync_end = 1280 + 20 + 10, ++ .vtotal = 1280 + 20 + 10 + 20, ++}; ++ ++/* 8.0inch or 10.1inch 1280x800 ++ * https://www.waveshare.com/product/raspberry-pi/displays/8inch-dsi-lcd-c.htm ++ * https://www.waveshare.com/product/raspberry-pi/displays/10.1inch-dsi-lcd-c.htm ++ */ ++static const struct drm_display_mode ws_panel_10_1_mode = { ++ .clock = 83333, ++ .hdisplay = 1280, ++ .hsync_start = 1280 + 156, ++ .hsync_end = 1280 + 156 + 20, ++ .htotal = 1280 + 156 + 20 + 40, ++ .vdisplay = 800, ++ .vsync_start = 800 + 40, ++ .vsync_end = 800 + 40 + 48, ++ .vtotal = 800 + 40 + 48 + 40, ++}; ++ ++/* 11.9inch 320x1480 ++ * https://www.waveshare.com/product/raspberry-pi/displays/11.9inch-dsi-lcd.htm ++ */ ++static const struct drm_display_mode ws_panel_11_9_mode = { ++ .clock = 50000, ++ .hdisplay = 320, ++ .hsync_start = 320 + 60, ++ .hsync_end = 320 + 60 + 60, ++ .htotal = 320 + 60 + 60 + 60, ++ .vdisplay = 1480, ++ .vsync_start = 1480 + 60, ++ .vsync_end = 1480 + 60 + 60, ++ .vtotal = 1480 + 60 + 60 + 60, ++}; ++ ++static const struct drm_display_mode ws_panel_4_mode = { ++ .clock = 50000, ++ .hdisplay = 720, ++ .hsync_start = 720 + 32, ++ .hsync_end = 720 + 32 + 200, ++ .htotal = 720 + 32 + 200 + 120, ++ .vdisplay = 720, ++ .vsync_start = 720 + 8, ++ .vsync_end = 720 + 8 + 4, ++ .vtotal = 720 + 8 + 4 + 16, ++}; ++ ++static struct ws_panel *panel_to_ts(struct drm_panel *panel) ++{ ++ return container_of(panel, struct ws_panel, base); ++} ++ ++static void ws_panel_i2c_write(struct ws_panel *ts, u8 reg, u8 val) ++{ ++ int ret; ++ ++ ret = i2c_smbus_write_byte_data(ts->i2c, reg, val); ++ if (ret) ++ dev_err(&ts->i2c->dev, "I2C write failed: %d\n", ret); ++} ++ ++static int ws_panel_disable(struct drm_panel *panel) ++{ ++ struct ws_panel *ts = panel_to_ts(panel); ++ ++ ws_panel_i2c_write(ts, 0xad, 0x00); ++ ++ return 0; ++} ++ ++static int ws_panel_unprepare(struct drm_panel *panel) ++{ ++ return 0; ++} ++ ++static int ws_panel_prepare(struct drm_panel *panel) ++{ ++ return 0; ++} ++ ++static int ws_panel_enable(struct drm_panel *panel) ++{ ++ struct ws_panel *ts = panel_to_ts(panel); ++ ++ ws_panel_i2c_write(ts, 0xad, 0x01); ++ ++ return 0; ++} ++ ++static int ws_panel_get_modes(struct drm_panel *panel, ++ struct drm_connector *connector) ++{ ++ static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; ++ struct ws_panel *ts = panel_to_ts(panel); ++ struct drm_display_mode *mode; ++ ++ mode = drm_mode_duplicate(connector->dev, ts->mode); ++ if (!mode) { ++ dev_err(panel->dev, "failed to add mode %ux%u@%u\n", ++ ts->mode->hdisplay, ++ ts->mode->vdisplay, ++ drm_mode_vrefresh(ts->mode)); ++ } ++ ++ mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; ++ ++ drm_mode_set_name(mode); ++ ++ drm_mode_probed_add(connector, mode); ++ ++ connector->display_info.bpc = 8; ++ connector->display_info.width_mm = 154; ++ connector->display_info.height_mm = 86; ++ drm_display_info_set_bus_formats(&connector->display_info, ++ &bus_format, 1); ++ ++ /* ++ * TODO: Remove once all drm drivers call ++ * drm_connector_set_orientation_from_panel() ++ */ ++ drm_connector_set_panel_orientation(connector, ts->orientation); ++ ++ return 1; ++} ++ ++static enum drm_panel_orientation ws_panel_get_orientation(struct drm_panel *panel) ++{ ++ struct ws_panel *ts = panel_to_ts(panel); ++ ++ return ts->orientation; ++} ++ ++static const struct drm_panel_funcs ws_panel_funcs = { ++ .disable = ws_panel_disable, ++ .unprepare = ws_panel_unprepare, ++ .prepare = ws_panel_prepare, ++ .enable = ws_panel_enable, ++ .get_modes = ws_panel_get_modes, ++ .get_orientation = ws_panel_get_orientation, ++}; ++ ++static int ws_panel_bl_update_status(struct backlight_device *bl) ++{ ++ struct ws_panel *ts = bl_get_data(bl); ++ ++ ws_panel_i2c_write(ts, 0xab, 0xff - backlight_get_brightness(bl)); ++ ws_panel_i2c_write(ts, 0xaa, 0x01); ++ ++ return 0; ++} ++ ++static const struct backlight_ops ws_panel_bl_ops = { ++ .update_status = ws_panel_bl_update_status, ++}; ++ ++static struct backlight_device * ++ws_panel_create_backlight(struct ws_panel *ts) ++{ ++ struct device *dev = ts->base.dev; ++ const struct backlight_properties props = { ++ .type = BACKLIGHT_RAW, ++ .brightness = 255, ++ .max_brightness = 255, ++ }; ++ ++ return devm_backlight_device_register(dev, dev_name(dev), dev, ts, ++ &ws_panel_bl_ops, &props); ++} ++ ++static int ws_panel_probe(struct i2c_client *i2c) ++{ ++ struct device *dev = &i2c->dev; ++ struct ws_panel *ts; ++ struct device_node *endpoint, *dsi_host_node; ++ struct mipi_dsi_host *host; ++ struct mipi_dsi_device_info info = { ++ .type = WS_DSI_DRIVER_NAME, ++ .channel = 0, ++ .node = NULL, ++ }; ++ int ret; ++ ++ ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); ++ if (!ts) ++ return -ENOMEM; ++ ++ ts->mode = of_device_get_match_data(dev); ++ if (!ts->mode) ++ return -EINVAL; ++ ++ i2c_set_clientdata(i2c, ts); ++ ++ ts->i2c = i2c; ++ ++ ws_panel_i2c_write(ts, 0xc0, 0x01); ++ ws_panel_i2c_write(ts, 0xc2, 0x01); ++ ws_panel_i2c_write(ts, 0xac, 0x01); ++ ++ ret = of_drm_get_panel_orientation(dev->of_node, &ts->orientation); ++ if (ret) { ++ dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret); ++ return ret; ++ } ++ ++ /* Look up the DSI host. It needs to probe before we do. */ ++ endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); ++ if (!endpoint) ++ return -ENODEV; ++ ++ dsi_host_node = of_graph_get_remote_port_parent(endpoint); ++ if (!dsi_host_node) ++ goto error; ++ ++ host = of_find_mipi_dsi_host_by_node(dsi_host_node); ++ of_node_put(dsi_host_node); ++ if (!host) { ++ of_node_put(endpoint); ++ return -EPROBE_DEFER; ++ } ++ ++ info.node = of_graph_get_remote_port(endpoint); ++ if (!info.node) ++ goto error; ++ ++ of_node_put(endpoint); ++ ++ ts->dsi = devm_mipi_dsi_device_register_full(dev, host, &info); ++ if (IS_ERR(ts->dsi)) { ++ dev_err(dev, "DSI device registration failed: %ld\n", ++ PTR_ERR(ts->dsi)); ++ return PTR_ERR(ts->dsi); ++ } ++ ++ drm_panel_init(&ts->base, dev, &ws_panel_funcs, ++ DRM_MODE_CONNECTOR_DSI); ++ ++ ts->base.backlight = ws_panel_create_backlight(ts); ++ if (IS_ERR(ts->base.backlight)) { ++ ret = PTR_ERR(ts->base.backlight); ++ dev_err(dev, "Failed to create backlight: %d\n", ret); ++ return ret; ++ } ++ ++ /* This appears last, as it's what will unblock the DSI host ++ * driver's component bind function. ++ */ ++ drm_panel_add(&ts->base); ++ ++ ts->dsi->mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | ++ MIPI_DSI_CLOCK_NON_CONTINUOUS; ++ ts->dsi->format = MIPI_DSI_FMT_RGB888; ++ ts->dsi->lanes = 2; ++ ++ ret = devm_mipi_dsi_attach(dev, ts->dsi); ++ ++ if (ret) ++ dev_err(dev, "failed to attach dsi to host: %d\n", ret); ++ ++ return 0; ++ ++error: ++ of_node_put(endpoint); ++ return -ENODEV; ++} ++ ++static void ws_panel_remove(struct i2c_client *i2c) ++{ ++ struct ws_panel *ts = i2c_get_clientdata(i2c); ++ ++ ws_panel_disable(&ts->base); ++ ++ drm_panel_remove(&ts->base); ++} ++ ++static void ws_panel_shutdown(struct i2c_client *i2c) ++{ ++ struct ws_panel *ts = i2c_get_clientdata(i2c); ++ ++ ws_panel_disable(&ts->base); ++} ++ ++static const struct of_device_id ws_panel_of_ids = { ++ { ++ .compatible = "waveshare,2.8inch-panel", ++ .data = &ws_panel_2_8_mode, ++ }, { ++ .compatible = "waveshare,3.4inch-panel", ++ .data = &ws_panel_3_4_mode, ++ }, { ++ .compatible = "waveshare,4.0inch-panel", ++ .data = &ws_panel_4_0_mode, ++ }, { ++ .compatible = "waveshare,7.0inch-c-panel", ++ .data = &ws_panel_7_0_c_mode, ++ }, { ++ .compatible = "waveshare,7.9inch-panel", ++ .data = &ws_panel_7_9_mode, ++ }, { ++ .compatible = "waveshare,8.0inch-panel", ++ .data = &ws_panel_10_1_mode, ++ }, { ++ .compatible = "waveshare,10.1inch-panel", ++ .data = &ws_panel_10_1_mode, ++ }, { ++ .compatible = "waveshare,11.9inch-panel", ++ .data = &ws_panel_11_9_mode, ++ }, { ++ .compatible = "waveshare,4inch-panel", ++ .data = &ws_panel_4_mode, ++ }, { ++ /* sentinel */ ++ } ++}; ++MODULE_DEVICE_TABLE(of, ws_panel_of_ids); ++ ++static struct i2c_driver ws_panel_driver = { ++ .driver = { ++ .name = "ws_touchscreen", ++ .of_match_table = ws_panel_of_ids, ++ }, ++ .probe = ws_panel_probe, ++ .remove = ws_panel_remove, ++ .shutdown = ws_panel_shutdown, ++}; ++module_i2c_driver(ws_panel_driver); ++ ++MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com>"); ++MODULE_DESCRIPTION("Waveshare DSI panel driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/gpu/drm/rp1/Kconfig b/drivers/gpu/drm/rp1/Kconfig +new file mode 100644 +index 000000000000..d73c62e0ab64 +--- /dev/null ++++ b/drivers/gpu/drm/rp1/Kconfig +@@ -0,0 +1,5 @@ ++source "drivers/gpu/drm/rp1/rp1-dsi/Kconfig" ++ ++source "drivers/gpu/drm/rp1/rp1-dpi/Kconfig" ++ ++source "drivers/gpu/drm/rp1/rp1-vec/Kconfig" +diff --git a/drivers/gpu/drm/rp1/Makefile b/drivers/gpu/drm/rp1/Makefile +new file mode 100644 +index 000000000000..0f915b158e96 +--- /dev/null ++++ b/drivers/gpu/drm/rp1/Makefile +@@ -0,0 +1,4 @@ ++obj-$(CONFIG_DRM_RP1_DSI) += rp1-dsi/ ++obj-$(CONFIG_DRM_RP1_DPI) += rp1-dpi/ ++obj-$(CONFIG_DRM_RP1_VEC) += rp1-vec/ ++ +diff --git a/drivers/gpu/drm/rp1/rp1-dpi/Kconfig b/drivers/gpu/drm/rp1/rp1-dpi/Kconfig +new file mode 100644 +index 000000000000..72c72709a5ce +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dpi/Kconfig +@@ -0,0 +1,11 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config DRM_RP1_DPI ++ tristate "DRM Support for RP1 DPI" ++ depends on DRM && MFD_RP1 ++ select DRM_GEM_DMA_HELPER ++ select DRM_KMS_HELPER ++ select DRM_VRAM_HELPER ++ select DRM_TTM ++ select DRM_TTM_HELPER ++ help ++ Choose this option to enable Video Out on RP1 +diff --git a/drivers/gpu/drm/rp1/rp1-dpi/Makefile b/drivers/gpu/drm/rp1/rp1-dpi/Makefile +new file mode 100644 +index 000000000000..79fdc7903167 +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dpi/Makefile +@@ -0,0 +1,5 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++ ++drm-rp1-dpi-y := rp1_dpi.o rp1_dpi_hw.o rp1_dpi_cfg.o ++ ++obj-$(CONFIG_DRM_RP1_DPI) += drm-rp1-dpi.o +diff --git a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c +new file mode 100644 +index 000000000000..a5a6300770cf +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c +@@ -0,0 +1,415 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for DPI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/slab.h> ++#include <linux/mm.h> ++#include <linux/fb.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/ioport.h> ++#include <linux/list.h> ++#include <linux/platform_device.h> ++#include <linux/clk.h> ++#include <linux/printk.h> ++#include <linux/console.h> ++#include <linux/debugfs.h> ++#include <linux/uaccess.h> ++#include <linux/io.h> ++#include <linux/dma-mapping.h> ++#include <linux/cred.h> ++#include <linux/media-bus-format.h> ++#include <linux/pinctrl/consumer.h> ++#include <drm/drm_drv.h> ++#include <drm/drm_mm.h> ++#include <drm/drm_fourcc.h> ++#include <drm/drm_gem_atomic_helper.h> ++#include <drm/drm_gem_dma_helper.h> ++#include <drm/drm_atomic_helper.h> ++#include <drm/drm_managed.h> ++#include <drm/drm_crtc.h> ++#include <drm/drm_crtc_helper.h> ++#include <drm/drm_encoder.h> ++#include <drm/drm_fb_helper.h> ++#include <drm/drm_fbdev_generic.h> ++#include <drm/drm_framebuffer.h> ++#include <drm/drm_gem.h> ++#include <drm/drm_gem_framebuffer_helper.h> ++#include <drm/drm_simple_kms_helper.h> ++#include <drm/drm_probe_helper.h> ++#include <drm/drm_modeset_helper_vtables.h> ++#include <drm/drm_vblank.h> ++#include <drm/drm_of.h> ++ ++#include "rp1_dpi.h" ++ ++/* ++ * Default bus format, where not specified by a connector/bridge ++ * and not overridden by the OF property "default_bus_fmt". ++ * This value is for compatibility with vc4 and VGA666-style boards, ++ * even though RP1 hardware cannot achieve the full 18-bit depth ++ * with that pinout (MEDIA_BUS_FMT_RGB666_1X24_CPADHI is preferred). ++ */ ++static unsigned int default_bus_fmt = MEDIA_BUS_FMT_RGB666_1X18; ++module_param(default_bus_fmt, uint, 0644); ++ ++/* -------------------------------------------------------------- */ ++ ++static void rp1dpi_pipe_update(struct drm_simple_display_pipe *pipe, ++ struct drm_plane_state *old_state) ++{ ++ struct drm_pending_vblank_event *event; ++ unsigned long flags; ++ struct drm_framebuffer *fb = pipe->plane.state->fb; ++ struct rp1_dpi *dpi = pipe->crtc.dev->dev_private; ++ struct drm_gem_object *gem = fb ? drm_gem_fb_get_obj(fb, 0) : NULL; ++ struct drm_gem_dma_object *dma_obj = gem ? to_drm_gem_dma_obj(gem) : NULL; ++ bool can_update = fb && dma_obj && dpi && dpi->pipe_enabled; ++ ++ /* (Re-)start DPI-DMA where required; and update FB address */ ++ if (can_update) { ++ if (!dpi->dpi_running || fb->format->format != dpi->cur_fmt) { ++ if (dpi->dpi_running && ++ fb->format->format != dpi->cur_fmt) { ++ rp1dpi_hw_stop(dpi); ++ dpi->dpi_running = false; ++ } ++ if (!dpi->dpi_running) { ++ rp1dpi_hw_setup(dpi, ++ fb->format->format, ++ dpi->bus_fmt, ++ dpi->de_inv, ++ &pipe->crtc.state->mode); ++ dpi->dpi_running = true; ++ } ++ dpi->cur_fmt = fb->format->format; ++ drm_crtc_vblank_on(&pipe->crtc); ++ } ++ rp1dpi_hw_update(dpi, dma_obj->dma_addr, fb->offsets0, fb->pitches0); ++ } ++ ++ /* Arm VBLANK event (or call it immediately in some error cases) */ ++ spin_lock_irqsave(&pipe->crtc.dev->event_lock, flags); ++ event = pipe->crtc.state->event; ++ if (event) { ++ pipe->crtc.state->event = NULL; ++ if (can_update && drm_crtc_vblank_get(&pipe->crtc) == 0) ++ drm_crtc_arm_vblank_event(&pipe->crtc, event); ++ else ++ drm_crtc_send_vblank_event(&pipe->crtc, event); ++ } ++ spin_unlock_irqrestore(&pipe->crtc.dev->event_lock, flags); ++} ++ ++static void rp1dpi_pipe_enable(struct drm_simple_display_pipe *pipe, ++ struct drm_crtc_state *crtc_state, ++ struct drm_plane_state *plane_state) ++{ ++ static const unsigned int M = 1000000; ++ struct rp1_dpi *dpi = pipe->crtc.dev->dev_private; ++ struct drm_connector *conn; ++ struct drm_connector_list_iter conn_iter; ++ unsigned int fpix, fdiv, fvco; ++ int ret; ++ ++ /* Look up the connector attached to DPI so we can get the ++ * bus_format. Ideally the bridge would tell us the ++ * bus_format we want, but it doesn't yet, so assume that it's ++ * uniform throughout the bridge chain. ++ */ ++ dev_info(&dpi->pdev->dev, __func__); ++ drm_connector_list_iter_begin(pipe->encoder.dev, &conn_iter); ++ drm_for_each_connector_iter(conn, &conn_iter) { ++ if (conn->encoder == &pipe->encoder) { ++ dpi->de_inv = !!(conn->display_info.bus_flags & ++ DRM_BUS_FLAG_DE_LOW); ++ dpi->clk_inv = !!(conn->display_info.bus_flags & ++ DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE); ++ if (conn->display_info.num_bus_formats) ++ dpi->bus_fmt = conn->display_info.bus_formats0; ++ break; ++ } ++ } ++ drm_connector_list_iter_end(&conn_iter); ++ ++ /* Set DPI clock to desired frequency. Currently (experimentally) ++ * we take control of the VideoPLL, to ensure we can generate it ++ * accurately. NB: this prevents concurrent use of DPI and VEC! ++ * Magic numbers ensure the parent clock is within 100MHz, 200MHz ++ * with VCO in 1GHz, 1.33GHz. The initial divide is by 6, 8 or 10. ++ */ ++ fpix = 1000 * pipe->crtc.state->mode.clock; ++ fpix = clamp(fpix, 1 * M, 200 * M); ++ fdiv = fpix; ++ while (fdiv < 100 * M) ++ fdiv *= 2; ++ fvco = fdiv * 2 * DIV_ROUND_UP(500 * M, fdiv); ++ ret = clk_set_rate(dpi->clocksRP1DPI_CLK_PLLCORE, fvco); ++ if (ret) ++ dev_err(&dpi->pdev->dev, "Failed to set PLL VCO to %u (%d)", fvco, ret); ++ ret = clk_set_rate(dpi->clocksRP1DPI_CLK_PLLDIV, fdiv); ++ if (ret) ++ dev_err(&dpi->pdev->dev, "Failed to set PLL output to %u (%d)", fdiv, ret); ++ ret = clk_set_rate(dpi->clocksRP1DPI_CLK_DPI, fpix); ++ if (ret) ++ dev_err(&dpi->pdev->dev, "Failed to set DPI clock to %u (%d)", fpix, ret); ++ ++ rp1dpi_vidout_setup(dpi, dpi->clk_inv); ++ clk_prepare_enable(dpi->clocksRP1DPI_CLK_PLLCORE); ++ clk_prepare_enable(dpi->clocksRP1DPI_CLK_PLLDIV); ++ pinctrl_pm_select_default_state(&dpi->pdev->dev); ++ clk_prepare_enable(dpi->clocksRP1DPI_CLK_DPI); ++ dev_info(&dpi->pdev->dev, "Want %u /%u %u /%u %u; got VCO=%lu DIV=%lu DPI=%lu", ++ fvco, fvco / fdiv, fdiv, fdiv / fpix, fpix, ++ clk_get_rate(dpi->clocksRP1DPI_CLK_PLLCORE), ++ clk_get_rate(dpi->clocksRP1DPI_CLK_PLLDIV), ++ clk_get_rate(dpi->clocksRP1DPI_CLK_DPI)); ++ ++ /* Start DPI-DMA. pipe already has the new crtc and plane state. */ ++ dpi->pipe_enabled = true; ++ dpi->cur_fmt = 0xdeadbeef; ++ rp1dpi_pipe_update(pipe, 0); ++} ++ ++static void rp1dpi_pipe_disable(struct drm_simple_display_pipe *pipe) ++{ ++ struct rp1_dpi *dpi = pipe->crtc.dev->dev_private; ++ ++ dev_info(&dpi->pdev->dev, __func__); ++ drm_crtc_vblank_off(&pipe->crtc); ++ if (dpi->dpi_running) { ++ rp1dpi_hw_stop(dpi); ++ dpi->dpi_running = false; ++ } ++ clk_disable_unprepare(dpi->clocksRP1DPI_CLK_DPI); ++ pinctrl_pm_select_sleep_state(&dpi->pdev->dev); ++ clk_disable_unprepare(dpi->clocksRP1DPI_CLK_PLLDIV); ++ clk_disable_unprepare(dpi->clocksRP1DPI_CLK_PLLCORE); ++ dpi->pipe_enabled = false; ++} ++ ++static int rp1dpi_pipe_enable_vblank(struct drm_simple_display_pipe *pipe) ++{ ++ struct rp1_dpi *dpi = pipe->crtc.dev->dev_private; ++ ++ if (dpi) ++ rp1dpi_hw_vblank_ctrl(dpi, 1); ++ ++ return 0; ++} ++ ++static void rp1dpi_pipe_disable_vblank(struct drm_simple_display_pipe *pipe) ++{ ++ struct rp1_dpi *dpi = pipe->crtc.dev->dev_private; ++ ++ if (dpi) ++ rp1dpi_hw_vblank_ctrl(dpi, 0); ++} ++ ++static const struct drm_simple_display_pipe_funcs rp1dpi_pipe_funcs = { ++ .enable = rp1dpi_pipe_enable, ++ .update = rp1dpi_pipe_update, ++ .disable = rp1dpi_pipe_disable, ++ .enable_vblank = rp1dpi_pipe_enable_vblank, ++ .disable_vblank = rp1dpi_pipe_disable_vblank, ++}; ++ ++static const struct drm_mode_config_funcs rp1dpi_mode_funcs = { ++ .fb_create = drm_gem_fb_create, ++ .atomic_check = drm_atomic_helper_check, ++ .atomic_commit = drm_atomic_helper_commit, ++}; ++ ++static void rp1dpi_stopall(struct drm_device *drm) ++{ ++ if (drm->dev_private) { ++ struct rp1_dpi *dpi = drm->dev_private; ++ ++ if (dpi->dpi_running || rp1dpi_hw_busy(dpi)) { ++ rp1dpi_hw_stop(dpi); ++ clk_disable_unprepare(dpi->clocksRP1DPI_CLK_DPI); ++ dpi->dpi_running = false; ++ } ++ rp1dpi_vidout_poweroff(dpi); ++ pinctrl_pm_select_sleep_state(&dpi->pdev->dev); ++ } ++} ++ ++DEFINE_DRM_GEM_DMA_FOPS(rp1dpi_fops); ++ ++static struct drm_driver rp1dpi_driver = { ++ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, ++ .fops = &rp1dpi_fops, ++ .name = "drm-rp1-dpi", ++ .desc = "drm-rp1-dpi", ++ .date = "0", ++ .major = 1, ++ .minor = 0, ++ DRM_GEM_DMA_DRIVER_OPS, ++ .release = rp1dpi_stopall, ++}; ++ ++static const u32 rp1dpi_formats = { ++ DRM_FORMAT_XRGB8888, ++ DRM_FORMAT_XBGR8888, ++ DRM_FORMAT_RGB888, ++ DRM_FORMAT_BGR888, ++ DRM_FORMAT_RGB565 ++}; ++ ++static int rp1dpi_platform_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct rp1_dpi *dpi; ++ struct drm_bridge *bridge = NULL; ++ struct drm_panel *panel; ++ int i, ret; ++ ++ dev_info(dev, __func__); ++ ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, 0, 0, ++ &panel, &bridge); ++ if (ret) { ++ dev_info(dev, "%s: bridge not found\n", __func__); ++ return -EPROBE_DEFER; ++ } ++ if (panel) { ++ bridge = devm_drm_panel_bridge_add(dev, panel); ++ if (IS_ERR(bridge)) ++ return PTR_ERR(bridge); ++ } ++ ++ dpi = devm_drm_dev_alloc(dev, &rp1dpi_driver, struct rp1_dpi, drm); ++ if (IS_ERR(dpi)) { ++ ret = PTR_ERR(dpi); ++ dev_err(dev, "%s devm_drm_dev_alloc %d", __func__, ret); ++ return ret; ++ } ++ dpi->pdev = pdev; ++ ++ dpi->bus_fmt = default_bus_fmt; ++ ret = of_property_read_u32(dev->of_node, "default_bus_fmt", &dpi->bus_fmt); ++ ++ for (i = 0; i < RP1DPI_NUM_HW_BLOCKS; i++) { ++ dpi->hw_basei = ++ devm_ioremap_resource(dev, ++ platform_get_resource(dpi->pdev, IORESOURCE_MEM, i)); ++ if (IS_ERR(dpi->hw_basei)) { ++ dev_err(dev, "Error memory mapping regs%d\n", i); ++ return PTR_ERR(dpi->hw_basei); ++ } ++ } ++ ret = platform_get_irq(dpi->pdev, 0); ++ if (ret > 0) ++ ret = devm_request_irq(dev, ret, rp1dpi_hw_isr, ++ IRQF_SHARED, "rp1-dpi", dpi); ++ if (ret) { ++ dev_err(dev, "Unable to request interrupt\n"); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < RP1DPI_NUM_CLOCKS; i++) { ++ static const char * const myclocknamesRP1DPI_NUM_CLOCKS = { ++ "dpiclk", "plldiv", "pllcore" ++ }; ++ dpi->clocksi = devm_clk_get(dev, myclocknamesi); ++ if (IS_ERR(dpi->clocksi)) { ++ dev_err(dev, "Unable to request clock %s\n", myclocknamesi); ++ return PTR_ERR(dpi->clocksi); ++ } ++ } ++ ++ ret = drmm_mode_config_init(&dpi->drm); ++ if (ret) ++ goto done_err; ++ ++ /* Now we have all our resources, finish driver initialization */ ++ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); ++ init_completion(&dpi->finished); ++ dpi->drm.dev_private = dpi; ++ platform_set_drvdata(pdev, &dpi->drm); ++ ++ dpi->drm.mode_config.max_width = 4096; ++ dpi->drm.mode_config.max_height = 4096; ++ dpi->drm.mode_config.preferred_depth = 32; ++ dpi->drm.mode_config.prefer_shadow = 0; ++ dpi->drm.mode_config.quirk_addfb_prefer_host_byte_order = true; ++ dpi->drm.mode_config.funcs = &rp1dpi_mode_funcs; ++ drm_vblank_init(&dpi->drm, 1); ++ ++ ret = drm_simple_display_pipe_init(&dpi->drm, ++ &dpi->pipe, ++ &rp1dpi_pipe_funcs, ++ rp1dpi_formats, ++ ARRAY_SIZE(rp1dpi_formats), ++ NULL, NULL); ++ if (!ret) ++ ret = drm_simple_display_pipe_attach_bridge(&dpi->pipe, bridge); ++ if (ret) ++ goto done_err; ++ ++ drm_mode_config_reset(&dpi->drm); ++ ++ ret = drm_dev_register(&dpi->drm, 0); ++ if (ret) ++ return ret; ++ ++ drm_fbdev_generic_setup(&dpi->drm, 32); ++ return ret; ++ ++done_err: ++ dev_err(dev, "%s fail %d\n", __func__, ret); ++ return ret; ++} ++ ++static int rp1dpi_platform_remove(struct platform_device *pdev) ++{ ++ struct drm_device *drm = platform_get_drvdata(pdev); ++ ++ rp1dpi_stopall(drm); ++ drm_dev_unregister(drm); ++ drm_atomic_helper_shutdown(drm); ++ drm_dev_put(drm); ++ ++ return 0; ++} ++ ++static void rp1dpi_platform_shutdown(struct platform_device *pdev) ++{ ++ struct drm_device *drm = platform_get_drvdata(pdev); ++ ++ rp1dpi_stopall(drm); ++} ++ ++static const struct of_device_id rp1dpi_of_match = { ++ { ++ .compatible = "raspberrypi,rp1dpi", ++ }, ++ { /* sentinel */ }, ++}; ++ ++MODULE_DEVICE_TABLE(of, rp1dpi_of_match); ++ ++static struct platform_driver rp1dpi_platform_driver = { ++ .probe = rp1dpi_platform_probe, ++ .remove = rp1dpi_platform_remove, ++ .shutdown = rp1dpi_platform_shutdown, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = rp1dpi_of_match, ++ }, ++}; ++ ++module_platform_driver(rp1dpi_platform_driver); ++ ++MODULE_AUTHOR("Nick Hollinghurst"); ++MODULE_DESCRIPTION("DRM driver for DPI output on Raspberry Pi RP1"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h +new file mode 100644 +index 000000000000..1d32216bcca6 +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h +@@ -0,0 +1,69 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * DRM Driver for DSI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include <linux/types.h> ++#include <linux/io.h> ++#include <linux/clk.h> ++#include <drm/drm_device.h> ++#include <drm/drm_simple_kms_helper.h> ++ ++#define MODULE_NAME "drm-rp1-dpi" ++#define DRIVER_NAME "drm-rp1-dpi" ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define RP1DPI_HW_BLOCK_DPI 0 ++#define RP1DPI_HW_BLOCK_CFG 1 ++#define RP1DPI_NUM_HW_BLOCKS 2 ++ ++#define RP1DPI_CLK_DPI 0 ++#define RP1DPI_CLK_PLLDIV 1 ++#define RP1DPI_CLK_PLLCORE 2 ++#define RP1DPI_NUM_CLOCKS 3 ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct rp1_dpi { ++ /* DRM base and platform device pointer */ ++ struct drm_device drm; ++ struct platform_device *pdev; ++ ++ /* Framework and helper objects */ ++ struct drm_simple_display_pipe pipe; ++ struct drm_connector connector; ++ ++ /* Clocks: Video PLL, its primary divider, and DPI clock. */ ++ struct clk *clocksRP1DPI_NUM_CLOCKS; ++ ++ /* Block (DPI, VOCFG) base addresses, and current state */ ++ void __iomem *hw_baseRP1DPI_NUM_HW_BLOCKS; ++ u32 cur_fmt; ++ u32 bus_fmt; ++ bool de_inv, clk_inv; ++ bool dpi_running, pipe_enabled; ++ struct completion finished; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++/* Functions to control the DPI/DMA block */ ++ ++void rp1dpi_hw_setup(struct rp1_dpi *dpi, ++ u32 in_format, ++ u32 bus_format, ++ bool de_inv, ++ struct drm_display_mode const *mode); ++void rp1dpi_hw_update(struct rp1_dpi *dpi, dma_addr_t addr, u32 offset, u32 stride); ++void rp1dpi_hw_stop(struct rp1_dpi *dpi); ++int rp1dpi_hw_busy(struct rp1_dpi *dpi); ++irqreturn_t rp1dpi_hw_isr(int irq, void *dev); ++void rp1dpi_hw_vblank_ctrl(struct rp1_dpi *dpi, int enable); ++ ++/* ---------------------------------------------------------------------- */ ++/* Functions to control the VIDEO OUT CFG block and check RP1 platform */ ++ ++void rp1dpi_vidout_setup(struct rp1_dpi *dpi, bool drive_negedge); ++void rp1dpi_vidout_poweroff(struct rp1_dpi *dpi); +diff --git a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_cfg.c b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_cfg.c +new file mode 100644 +index 000000000000..cd328b98d4da +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_cfg.c +@@ -0,0 +1,510 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for DPI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/mm.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/platform_device.h> ++#include <linux/printk.h> ++#include <linux/rp1_platform.h> ++ ++#include "rp1_dpi.h" ++ ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_SEL ++// JTAG access : synchronous ++// Description : Selects source: VEC or DPI ++#define VIDEO_OUT_CFG_SEL_OFFSET 0x00000000 ++#define VIDEO_OUT_CFG_SEL_BITS 0x00000013 ++#define VIDEO_OUT_CFG_SEL_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_SEL_PCLK_INV ++// Description : Select dpi_pclk output port polarity inversion. ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_RESET 0x0 ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_BITS 0x00000010 ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_MSB 4 ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_LSB 4 ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_SEL_PAD_MUX ++// Description : VEC 1 DPI 0 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_RESET 0x0 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_BITS 0x00000002 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_MSB 1 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_LSB 1 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_SEL_VDAC_MUX ++// Description : VEC 1 DPI 0 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_RESET 0x0 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_BITS 0x00000001 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_MSB 0 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_LSB 0 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_VDAC_CFG ++// JTAG access : synchronous ++// Description : Configure SNPS VDAC ++#define VIDEO_OUT_CFG_VDAC_CFG_OFFSET 0x00000004 ++#define VIDEO_OUT_CFG_VDAC_CFG_BITS 0x1fffffff ++#define VIDEO_OUT_CFG_VDAC_CFG_RESET 0x0003ffff ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENCTR ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_BITS 0x1c000000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_MSB 28 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_LSB 26 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENSC ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_BITS 0x03800000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_MSB 25 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_LSB 23 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENDAC ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_BITS 0x00700000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_MSB 22 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_LSB 20 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENVBG ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_BITS 0x00080000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_MSB 19 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_LSB 19 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_BITS 0x00040000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_MSB 18 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_LSB 18 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_DAC2GC ++// Description : dac2 gain control ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_RESET 0x3f ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_BITS 0x0003f000 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_MSB 17 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_LSB 12 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_DAC1GC ++// Description : dac1 gain control ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_RESET 0x3f ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_BITS 0x00000fc0 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_MSB 11 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_LSB 6 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_DAC0GC ++// Description : dac0 gain control ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_RESET 0x3f ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_BITS 0x0000003f ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_MSB 5 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_LSB 0 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_VDAC_STATUS ++// JTAG access : synchronous ++// Description : Read VDAC status ++#define VIDEO_OUT_CFG_VDAC_STATUS_OFFSET 0x00000008 ++#define VIDEO_OUT_CFG_VDAC_STATUS_BITS 0x00000017 ++#define VIDEO_OUT_CFG_VDAC_STATUS_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3 ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_BITS 0x00000010 ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_MSB 4 ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_LSB 4 ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_RESET "-" ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_BITS 0x00000007 ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_MSB 2 ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_LSB 0 ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_MEM_PD ++// JTAG access : synchronous ++// Description : Control memory power down ++#define VIDEO_OUT_CFG_MEM_PD_OFFSET 0x0000000c ++#define VIDEO_OUT_CFG_MEM_PD_BITS 0x00000003 ++#define VIDEO_OUT_CFG_MEM_PD_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_MEM_PD_VEC ++// Description : None ++#define VIDEO_OUT_CFG_MEM_PD_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_MEM_PD_VEC_BITS 0x00000002 ++#define VIDEO_OUT_CFG_MEM_PD_VEC_MSB 1 ++#define VIDEO_OUT_CFG_MEM_PD_VEC_LSB 1 ++#define VIDEO_OUT_CFG_MEM_PD_VEC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_MEM_PD_DPI ++// Description : None ++#define VIDEO_OUT_CFG_MEM_PD_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_MEM_PD_DPI_BITS 0x00000001 ++#define VIDEO_OUT_CFG_MEM_PD_DPI_MSB 0 ++#define VIDEO_OUT_CFG_MEM_PD_DPI_LSB 0 ++#define VIDEO_OUT_CFG_MEM_PD_DPI_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_TEST_OVERRIDE ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_OFFSET 0x00000010 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_BITS 0xffffffff ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_TEST_OVERRIDE_PAD ++// Description : None ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_RESET 0x0 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_BITS 0x80000000 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_MSB 31 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_LSB 31 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC ++// Description : None ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_RESET 0x0 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_BITS 0x40000000 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_MSB 30 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_LSB 30 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL ++// Description : None ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_RESET 0x00000000 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_BITS 0x3fffffff ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_MSB 29 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_LSB 0 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INTR ++// JTAG access : synchronous ++// Description : Raw Interrupts ++#define VIDEO_OUT_CFG_INTR_OFFSET 0x00000014 ++#define VIDEO_OUT_CFG_INTR_BITS 0x00000003 ++#define VIDEO_OUT_CFG_INTR_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTR_DPI ++// Description : None ++#define VIDEO_OUT_CFG_INTR_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_INTR_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_INTR_DPI_MSB 1 ++#define VIDEO_OUT_CFG_INTR_DPI_LSB 1 ++#define VIDEO_OUT_CFG_INTR_DPI_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTR_VEC ++// Description : None ++#define VIDEO_OUT_CFG_INTR_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_INTR_VEC_BITS 0x00000001 ++#define VIDEO_OUT_CFG_INTR_VEC_MSB 0 ++#define VIDEO_OUT_CFG_INTR_VEC_LSB 0 ++#define VIDEO_OUT_CFG_INTR_VEC_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INTE ++// JTAG access : synchronous ++// Description : Interrupt Enable ++#define VIDEO_OUT_CFG_INTE_OFFSET 0x00000018 ++#define VIDEO_OUT_CFG_INTE_BITS 0x00000003 ++#define VIDEO_OUT_CFG_INTE_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTE_DPI ++// Description : None ++#define VIDEO_OUT_CFG_INTE_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_INTE_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_INTE_DPI_MSB 1 ++#define VIDEO_OUT_CFG_INTE_DPI_LSB 1 ++#define VIDEO_OUT_CFG_INTE_DPI_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTE_VEC ++// Description : None ++#define VIDEO_OUT_CFG_INTE_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_INTE_VEC_BITS 0x00000001 ++#define VIDEO_OUT_CFG_INTE_VEC_MSB 0 ++#define VIDEO_OUT_CFG_INTE_VEC_LSB 0 ++#define VIDEO_OUT_CFG_INTE_VEC_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INTF ++// JTAG access : synchronous ++// Description : Interrupt Force ++#define VIDEO_OUT_CFG_INTF_OFFSET 0x0000001c ++#define VIDEO_OUT_CFG_INTF_BITS 0x00000003 ++#define VIDEO_OUT_CFG_INTF_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTF_DPI ++// Description : None ++#define VIDEO_OUT_CFG_INTF_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_INTF_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_INTF_DPI_MSB 1 ++#define VIDEO_OUT_CFG_INTF_DPI_LSB 1 ++#define VIDEO_OUT_CFG_INTF_DPI_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTF_VEC ++// Description : None ++#define VIDEO_OUT_CFG_INTF_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_INTF_VEC_BITS 0x00000001 ++#define VIDEO_OUT_CFG_INTF_VEC_MSB 0 ++#define VIDEO_OUT_CFG_INTF_VEC_LSB 0 ++#define VIDEO_OUT_CFG_INTF_VEC_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INTS ++// JTAG access : synchronous ++// Description : Interrupt status after masking & forcing ++#define VIDEO_OUT_CFG_INTS_OFFSET 0x00000020 ++#define VIDEO_OUT_CFG_INTS_BITS 0x00000003 ++#define VIDEO_OUT_CFG_INTS_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTS_DPI ++// Description : None ++#define VIDEO_OUT_CFG_INTS_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_INTS_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_INTS_DPI_MSB 1 ++#define VIDEO_OUT_CFG_INTS_DPI_LSB 1 ++#define VIDEO_OUT_CFG_INTS_DPI_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTS_VEC ++// Description : None ++#define VIDEO_OUT_CFG_INTS_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_INTS_VEC_BITS 0x00000001 ++#define VIDEO_OUT_CFG_INTS_VEC_MSB 0 ++#define VIDEO_OUT_CFG_INTS_VEC_LSB 0 ++#define VIDEO_OUT_CFG_INTS_VEC_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_BLOCK_ID ++// JTAG access : synchronous ++// Description : Block Identifier ++// Hexadecimal representation of "VOCF" ++#define VIDEO_OUT_CFG_BLOCK_ID_OFFSET 0x00000024 ++#define VIDEO_OUT_CFG_BLOCK_ID_BITS 0xffffffff ++#define VIDEO_OUT_CFG_BLOCK_ID_RESET 0x564f4346 ++#define VIDEO_OUT_CFG_BLOCK_ID_MSB 31 ++#define VIDEO_OUT_CFG_BLOCK_ID_LSB 0 ++#define VIDEO_OUT_CFG_BLOCK_ID_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INSTANCE_ID ++// JTAG access : synchronous ++// Description : Block Instance Identifier ++#define VIDEO_OUT_CFG_INSTANCE_ID_OFFSET 0x00000028 ++#define VIDEO_OUT_CFG_INSTANCE_ID_BITS 0x0000000f ++#define VIDEO_OUT_CFG_INSTANCE_ID_RESET 0x00000000 ++#define VIDEO_OUT_CFG_INSTANCE_ID_MSB 3 ++#define VIDEO_OUT_CFG_INSTANCE_ID_LSB 0 ++#define VIDEO_OUT_CFG_INSTANCE_ID_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_AUTO ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_OFFSET 0x0000002c ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_RESET 0x00000007 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_PARALLEL ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_OFFSET 0x00000030 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_RESET 0x00000006 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_CTRL ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_OFFSET 0x00000034 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_TRIG ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_OFFSET 0x00000038 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC ++// Description : Pulses the reset output ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_ACCESS "SC" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI ++// Description : Pulses the reset output ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_ACCESS "SC" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER ++// Description : Pulses the reset output ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_ACCESS "SC" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_DONE ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_OFFSET 0x0000003c ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_DONE_VEC ++// Description : Indicates the current state of the reset ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_DONE_DPI ++// Description : Indicates the current state of the reset ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER ++// Description : Indicates the current state of the reset ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_ACCESS "RO" ++// ============================================================================= ++ ++#define CFG_WRITE(reg, val) writel((val), dpi->hw_baseRP1DPI_HW_BLOCK_CFG + (reg ## _OFFSET)) ++#define CFG_READ(reg) readl(dpi->hw_baseRP1DPI_HW_BLOCK_CFG + (reg ## _OFFSET)) ++ ++void rp1dpi_vidout_setup(struct rp1_dpi *dpi, bool drive_negedge) ++{ ++ /* ++ * We assume DPI and VEC can't be used at the same time (due to ++ * clashing requirements for PLL_VIDEO, and potentially for VDAC). ++ * We therefore leave VEC memories powered down. ++ */ ++ CFG_WRITE(VIDEO_OUT_CFG_MEM_PD, VIDEO_OUT_CFG_MEM_PD_VEC_BITS); ++ CFG_WRITE(VIDEO_OUT_CFG_TEST_OVERRIDE, ++ VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_BITS); ++ ++ /* DPI->Pads; DPI->VDAC; optionally flip PCLK polarity */ ++ CFG_WRITE(VIDEO_OUT_CFG_SEL, ++ drive_negedge ? VIDEO_OUT_CFG_SEL_PCLK_INV_BITS : 0); ++ ++ /* configure VDAC for 3 channels, bandgap on, 710mV swing */ ++ CFG_WRITE(VIDEO_OUT_CFG_VDAC_CFG, 0); ++ ++ /* enable DPI interrupt */ ++ CFG_WRITE(VIDEO_OUT_CFG_INTE, VIDEO_OUT_CFG_INTE_DPI_BITS); ++} ++ ++void rp1dpi_vidout_poweroff(struct rp1_dpi *dpi) ++{ ++ /* disable DPI interrupt */ ++ CFG_WRITE(VIDEO_OUT_CFG_INTE, 0); ++ ++ /* Ensure VDAC is turned off; power down DPI,VEC memories */ ++ CFG_WRITE(VIDEO_OUT_CFG_VDAC_CFG, 0); ++ CFG_WRITE(VIDEO_OUT_CFG_MEM_PD, VIDEO_OUT_CFG_MEM_PD_BITS); ++} +diff --git a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c +new file mode 100644 +index 000000000000..c4aaa57f07dd +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for DPI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/mm.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/media-bus-format.h> ++#include <linux/platform_device.h> ++#include <linux/printk.h> ++#include <drm/drm_fourcc.h> ++#include <drm/drm_print.h> ++#include <drm/drm_vblank.h> ++ ++#include "rp1_dpi.h" ++ ++// --- DPI DMA REGISTERS --- ++ ++// Control ++#define DPI_DMA_CONTROL 0x0 ++#define DPI_DMA_CONTROL_ARM_SHIFT 0 ++#define DPI_DMA_CONTROL_ARM_MASK BIT(DPI_DMA_CONTROL_ARM_SHIFT) ++#define DPI_DMA_CONTROL_ALIGN16_SHIFT 2 ++#define DPI_DMA_CONTROL_ALIGN16_MASK BIT(DPI_DMA_CONTROL_ALIGN16_SHIFT) ++#define DPI_DMA_CONTROL_AUTO_REPEAT_SHIFT 1 ++#define DPI_DMA_CONTROL_AUTO_REPEAT_MASK BIT(DPI_DMA_CONTROL_AUTO_REPEAT_SHIFT) ++#define DPI_DMA_CONTROL_HIGH_WATER_SHIFT 3 ++#define DPI_DMA_CONTROL_HIGH_WATER_MASK (0x1FF << DPI_DMA_CONTROL_HIGH_WATER_SHIFT) ++#define DPI_DMA_CONTROL_DEN_POL_SHIFT 12 ++#define DPI_DMA_CONTROL_DEN_POL_MASK BIT(DPI_DMA_CONTROL_DEN_POL_SHIFT) ++#define DPI_DMA_CONTROL_HSYNC_POL_SHIFT 13 ++#define DPI_DMA_CONTROL_HSYNC_POL_MASK BIT(DPI_DMA_CONTROL_HSYNC_POL_SHIFT) ++#define DPI_DMA_CONTROL_VSYNC_POL_SHIFT 14 ++#define DPI_DMA_CONTROL_VSYNC_POL_MASK BIT(DPI_DMA_CONTROL_VSYNC_POL_SHIFT) ++#define DPI_DMA_CONTROL_COLORM_SHIFT 15 ++#define DPI_DMA_CONTROL_COLORM_MASK BIT(DPI_DMA_CONTROL_COLORM_SHIFT) ++#define DPI_DMA_CONTROL_SHUTDN_SHIFT 16 ++#define DPI_DMA_CONTROL_SHUTDN_MASK BIT(DPI_DMA_CONTROL_SHUTDN_SHIFT) ++#define DPI_DMA_CONTROL_HBP_EN_SHIFT 17 ++#define DPI_DMA_CONTROL_HBP_EN_MASK BIT(DPI_DMA_CONTROL_HBP_EN_SHIFT) ++#define DPI_DMA_CONTROL_HFP_EN_SHIFT 18 ++#define DPI_DMA_CONTROL_HFP_EN_MASK BIT(DPI_DMA_CONTROL_HFP_EN_SHIFT) ++#define DPI_DMA_CONTROL_VBP_EN_SHIFT 19 ++#define DPI_DMA_CONTROL_VBP_EN_MASK BIT(DPI_DMA_CONTROL_VBP_EN_SHIFT) ++#define DPI_DMA_CONTROL_VFP_EN_SHIFT 20 ++#define DPI_DMA_CONTROL_VFP_EN_MASK BIT(DPI_DMA_CONTROL_VFP_EN_SHIFT) ++#define DPI_DMA_CONTROL_HSYNC_EN_SHIFT 21 ++#define DPI_DMA_CONTROL_HSYNC_EN_MASK BIT(DPI_DMA_CONTROL_HSYNC_EN_SHIFT) ++#define DPI_DMA_CONTROL_VSYNC_EN_SHIFT 22 ++#define DPI_DMA_CONTROL_VSYNC_EN_MASK BIT(DPI_DMA_CONTROL_VSYNC_EN_SHIFT) ++#define DPI_DMA_CONTROL_FORCE_IMMED_SHIFT 23 ++#define DPI_DMA_CONTROL_FORCE_IMMED_MASK BIT(DPI_DMA_CONTROL_FORCE_IMMED_SHIFT) ++#define DPI_DMA_CONTROL_FORCE_DRAIN_SHIFT 24 ++#define DPI_DMA_CONTROL_FORCE_DRAIN_MASK BIT(DPI_DMA_CONTROL_FORCE_DRAIN_SHIFT) ++#define DPI_DMA_CONTROL_FORCE_EMPTY_SHIFT 25 ++#define DPI_DMA_CONTROL_FORCE_EMPTY_MASK BIT(DPI_DMA_CONTROL_FORCE_EMPTY_SHIFT) ++ ++// IRQ_ENABLES ++#define DPI_DMA_IRQ_EN 0x04 ++#define DPI_DMA_IRQ_EN_DMA_READY_SHIFT 0 ++#define DPI_DMA_IRQ_EN_DMA_READY_MASK BIT(DPI_DMA_IRQ_EN_DMA_READY_SHIFT) ++#define DPI_DMA_IRQ_EN_UNDERFLOW_SHIFT 1 ++#define DPI_DMA_IRQ_EN_UNDERFLOW_MASK BIT(DPI_DMA_IRQ_EN_UNDERFLOW_SHIFT) ++#define DPI_DMA_IRQ_EN_FRAME_START_SHIFT 2 ++#define DPI_DMA_IRQ_EN_FRAME_START_MASK BIT(DPI_DMA_IRQ_EN_FRAME_START_SHIFT) ++#define DPI_DMA_IRQ_EN_AFIFO_EMPTY_SHIFT 3 ++#define DPI_DMA_IRQ_EN_AFIFO_EMPTY_MASK BIT(DPI_DMA_IRQ_EN_AFIFO_EMPTY_SHIFT) ++#define DPI_DMA_IRQ_EN_TE_SHIFT 4 ++#define DPI_DMA_IRQ_EN_TE_MASK BIT(DPI_DMA_IRQ_EN_TE_SHIFT) ++#define DPI_DMA_IRQ_EN_ERROR_SHIFT 5 ++#define DPI_DMA_IRQ_EN_ERROR_MASK BIT(DPI_DMA_IRQ_EN_ERROR_SHIFT) ++#define DPI_DMA_IRQ_EN_MATCH_SHIFT 6 ++#define DPI_DMA_IRQ_EN_MATCH_MASK BIT(DPI_DMA_IRQ_EN_MATCH_SHIFT) ++#define DPI_DMA_IRQ_EN_MATCH_LINE_SHIFT 16 ++#define DPI_DMA_IRQ_EN_MATCH_LINE_MASK (0xFFF << DPI_DMA_IRQ_EN_MATCH_LINE_SHIFT) ++ ++// IRQ_FLAGS ++#define DPI_DMA_IRQ_FLAGS 0x08 ++#define DPI_DMA_IRQ_FLAGS_DMA_READY_SHIFT 0 ++#define DPI_DMA_IRQ_FLAGS_DMA_READY_MASK BIT(DPI_DMA_IRQ_FLAGS_DMA_READY_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_UNDERFLOW_SHIFT 1 ++#define DPI_DMA_IRQ_FLAGS_UNDERFLOW_MASK BIT(DPI_DMA_IRQ_FLAGS_UNDERFLOW_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_FRAME_START_SHIFT 2 ++#define DPI_DMA_IRQ_FLAGS_FRAME_START_MASK BIT(DPI_DMA_IRQ_FLAGS_FRAME_START_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_SHIFT 3 ++#define DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_MASK BIT(DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_TE_SHIFT 4 ++#define DPI_DMA_IRQ_FLAGS_TE_MASK BIT(DPI_DMA_IRQ_FLAGS_TE_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_ERROR_SHIFT 5 ++#define DPI_DMA_IRQ_FLAGS_ERROR_MASK BIT(DPI_DMA_IRQ_FLAGS_ERROR_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_MATCH_SHIFT 6 ++#define DPI_DMA_IRQ_FLAGS_MATCH_MASK BIT(DPI_DMA_IRQ_FLAGS_MATCH_SHIFT) ++ ++// QOS ++#define DPI_DMA_QOS 0xC ++#define DPI_DMA_QOS_DQOS_SHIFT 0 ++#define DPI_DMA_QOS_DQOS_MASK (0xF << DPI_DMA_QOS_DQOS_SHIFT) ++#define DPI_DMA_QOS_ULEV_SHIFT 4 ++#define DPI_DMA_QOS_ULEV_MASK (0xF << DPI_DMA_QOS_ULEV_SHIFT) ++#define DPI_DMA_QOS_UQOS_SHIFT 8 ++#define DPI_DMA_QOS_UQOS_MASK (0xF << DPI_DMA_QOS_UQOS_SHIFT) ++#define DPI_DMA_QOS_LLEV_SHIFT 12 ++#define DPI_DMA_QOS_LLEV_MASK (0xF << DPI_DMA_QOS_LLEV_SHIFT) ++#define DPI_DMA_QOS_LQOS_SHIFT 16 ++#define DPI_DMA_QOS_LQOS_MASK (0xF << DPI_DMA_QOS_LQOS_SHIFT) ++ ++// Panics ++#define DPI_DMA_PANICS 0x38 ++#define DPI_DMA_PANICS_UPPER_COUNT_SHIFT 0 ++#define DPI_DMA_PANICS_UPPER_COUNT_MASK \ ++ (0x0000FFFF << DPI_DMA_PANICS_UPPER_COUNT_SHIFT) ++#define DPI_DMA_PANICS_LOWER_COUNT_SHIFT 16 ++#define DPI_DMA_PANICS_LOWER_COUNT_MASK \ ++ (0x0000FFFF << DPI_DMA_PANICS_LOWER_COUNT_SHIFT) ++ ++// DMA Address Lower: ++#define DPI_DMA_DMA_ADDR_L 0x10 ++ ++// DMA Address Upper: ++#define DPI_DMA_DMA_ADDR_H 0x40 ++ ++// DMA stride ++#define DPI_DMA_DMA_STRIDE 0x14 ++ ++// Visible Area ++#define DPI_DMA_VISIBLE_AREA 0x18 ++#define DPI_DMA_VISIBLE_AREA_ROWSM1_SHIFT 0 ++#define DPI_DMA_VISIBLE_AREA_ROWSM1_MASK (0x0FFF << DPI_DMA_VISIBLE_AREA_ROWSM1_SHIFT) ++#define DPI_DMA_VISIBLE_AREA_COLSM1_SHIFT 16 ++#define DPI_DMA_VISIBLE_AREA_COLSM1_MASK (0x0FFF << DPI_DMA_VISIBLE_AREA_COLSM1_SHIFT) ++ ++// Sync width ++#define DPI_DMA_SYNC_WIDTH 0x1C ++#define DPI_DMA_SYNC_WIDTH_ROWSM1_SHIFT 0 ++#define DPI_DMA_SYNC_WIDTH_ROWSM1_MASK (0x0FFF << DPI_DMA_SYNC_WIDTH_ROWSM1_SHIFT) ++#define DPI_DMA_SYNC_WIDTH_COLSM1_SHIFT 16 ++#define DPI_DMA_SYNC_WIDTH_COLSM1_MASK (0x0FFF << DPI_DMA_SYNC_WIDTH_COLSM1_SHIFT) ++ ++// Back porch ++#define DPI_DMA_BACK_PORCH 0x20 ++#define DPI_DMA_BACK_PORCH_ROWSM1_SHIFT 0 ++#define DPI_DMA_BACK_PORCH_ROWSM1_MASK (0x0FFF << DPI_DMA_BACK_PORCH_ROWSM1_SHIFT) ++#define DPI_DMA_BACK_PORCH_COLSM1_SHIFT 16 ++#define DPI_DMA_BACK_PORCH_COLSM1_MASK (0x0FFF << DPI_DMA_BACK_PORCH_COLSM1_SHIFT) ++ ++// Front porch ++#define DPI_DMA_FRONT_PORCH 0x24 ++#define DPI_DMA_FRONT_PORCH_ROWSM1_SHIFT 0 ++#define DPI_DMA_FRONT_PORCH_ROWSM1_MASK (0x0FFF << DPI_DMA_FRONT_PORCH_ROWSM1_SHIFT) ++#define DPI_DMA_FRONT_PORCH_COLSM1_SHIFT 16 ++#define DPI_DMA_FRONT_PORCH_COLSM1_MASK (0x0FFF << DPI_DMA_FRONT_PORCH_COLSM1_SHIFT) ++ ++// Input masks ++#define DPI_DMA_IMASK 0x2C ++#define DPI_DMA_IMASK_R_SHIFT 0 ++#define DPI_DMA_IMASK_R_MASK (0x3FF << DPI_DMA_IMASK_R_SHIFT) ++#define DPI_DMA_IMASK_G_SHIFT 10 ++#define DPI_DMA_IMASK_G_MASK (0x3FF << DPI_DMA_IMASK_G_SHIFT) ++#define DPI_DMA_IMASK_B_SHIFT 20 ++#define DPI_DMA_IMASK_B_MASK (0x3FF << DPI_DMA_IMASK_B_SHIFT) ++ ++// Output Masks ++#define DPI_DMA_OMASK 0x30 ++#define DPI_DMA_OMASK_R_SHIFT 0 ++#define DPI_DMA_OMASK_R_MASK (0x3FF << DPI_DMA_OMASK_R_SHIFT) ++#define DPI_DMA_OMASK_G_SHIFT 10 ++#define DPI_DMA_OMASK_G_MASK (0x3FF << DPI_DMA_OMASK_G_SHIFT) ++#define DPI_DMA_OMASK_B_SHIFT 20 ++#define DPI_DMA_OMASK_B_MASK (0x3FF << DPI_DMA_OMASK_B_SHIFT) ++ ++// Shifts ++#define DPI_DMA_SHIFT 0x28 ++#define DPI_DMA_SHIFT_IR_SHIFT 0 ++#define DPI_DMA_SHIFT_IR_MASK (0x1F << DPI_DMA_SHIFT_IR_SHIFT) ++#define DPI_DMA_SHIFT_IG_SHIFT 5 ++#define DPI_DMA_SHIFT_IG_MASK (0x1F << DPI_DMA_SHIFT_IG_SHIFT) ++#define DPI_DMA_SHIFT_IB_SHIFT 10 ++#define DPI_DMA_SHIFT_IB_MASK (0x1F << DPI_DMA_SHIFT_IB_SHIFT) ++#define DPI_DMA_SHIFT_OR_SHIFT 15 ++#define DPI_DMA_SHIFT_OR_MASK (0x1F << DPI_DMA_SHIFT_OR_SHIFT) ++#define DPI_DMA_SHIFT_OG_SHIFT 20 ++#define DPI_DMA_SHIFT_OG_MASK (0x1F << DPI_DMA_SHIFT_OG_SHIFT) ++#define DPI_DMA_SHIFT_OB_SHIFT 25 ++#define DPI_DMA_SHIFT_OB_MASK (0x1F << DPI_DMA_SHIFT_OB_SHIFT) ++ ++// Scaling ++#define DPI_DMA_RGBSZ 0x34 ++#define DPI_DMA_RGBSZ_BPP_SHIFT 16 ++#define DPI_DMA_RGBSZ_BPP_MASK (0x3 << DPI_DMA_RGBSZ_BPP_SHIFT) ++#define DPI_DMA_RGBSZ_R_SHIFT 0 ++#define DPI_DMA_RGBSZ_R_MASK (0xF << DPI_DMA_RGBSZ_R_SHIFT) ++#define DPI_DMA_RGBSZ_G_SHIFT 4 ++#define DPI_DMA_RGBSZ_G_MASK (0xF << DPI_DMA_RGBSZ_G_SHIFT) ++#define DPI_DMA_RGBSZ_B_SHIFT 8 ++#define DPI_DMA_RGBSZ_B_MASK (0xF << DPI_DMA_RGBSZ_B_SHIFT) ++ ++// Status ++#define DPI_DMA_STATUS 0x3c ++ ++#define BITS(field, val) (((val) << (field ## _SHIFT)) & (field ## _MASK)) ++ ++static unsigned int rp1dpi_hw_read(struct rp1_dpi *dpi, unsigned int reg) ++{ ++ void __iomem *addr = dpi->hw_baseRP1DPI_HW_BLOCK_DPI + reg; ++ ++ return readl(addr); ++} ++ ++static void rp1dpi_hw_write(struct rp1_dpi *dpi, unsigned int reg, unsigned int val) ++{ ++ void __iomem *addr = dpi->hw_baseRP1DPI_HW_BLOCK_DPI + reg; ++ ++ writel(val, addr); ++} ++ ++int rp1dpi_hw_busy(struct rp1_dpi *dpi) ++{ ++ return (rp1dpi_hw_read(dpi, DPI_DMA_STATUS) & 0xF8F) ? 1 : 0; ++} ++ ++/* Table of supported input (in-memory/DMA) pixel formats. */ ++struct rp1dpi_ipixfmt { ++ u32 format; /* DRM format code */ ++ u32 mask; /* RGB masks (10 bits each, left justified) */ ++ u32 shift; /* RGB MSB positions in the memory word */ ++ u32 rgbsz; /* Shifts used for scaling; also (BPP/8-1) */ ++}; ++ ++#define IMASK_RGB(r, g, b) (BITS(DPI_DMA_IMASK_R, r) | \ ++ BITS(DPI_DMA_IMASK_G, g) | \ ++ BITS(DPI_DMA_IMASK_B, b)) ++#define OMASK_RGB(r, g, b) (BITS(DPI_DMA_OMASK_R, r) | \ ++ BITS(DPI_DMA_OMASK_G, g) | \ ++ BITS(DPI_DMA_OMASK_B, b)) ++#define ISHIFT_RGB(r, g, b) (BITS(DPI_DMA_SHIFT_IR, r) | \ ++ BITS(DPI_DMA_SHIFT_IG, g) | \ ++ BITS(DPI_DMA_SHIFT_IB, b)) ++#define OSHIFT_RGB(r, g, b) (BITS(DPI_DMA_SHIFT_OR, r) | \ ++ BITS(DPI_DMA_SHIFT_OG, g) | \ ++ BITS(DPI_DMA_SHIFT_OB, b)) ++ ++static const struct rp1dpi_ipixfmt my_formats = { ++ { ++ .format = DRM_FORMAT_XRGB8888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), ++ }, ++ { ++ .format = DRM_FORMAT_XBGR8888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), ++ }, ++ { ++ .format = DRM_FORMAT_RGB888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 2), ++ }, ++ { ++ .format = DRM_FORMAT_BGR888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 2), ++ }, ++ { ++ .format = DRM_FORMAT_RGB565, ++ .mask = IMASK_RGB(0x3e0, 0x3f0, 0x3e0), ++ .shift = ISHIFT_RGB(15, 10, 4), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_R, 5) | BITS(DPI_DMA_RGBSZ_G, 6) | ++ BITS(DPI_DMA_RGBSZ_B, 5) | BITS(DPI_DMA_RGBSZ_BPP, 1), ++ }, ++ { ++ .format = DRM_FORMAT_BGR565, ++ .mask = IMASK_RGB(0x3e0, 0x3f0, 0x3e0), ++ .shift = ISHIFT_RGB(4, 10, 15), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_R, 5) | BITS(DPI_DMA_RGBSZ_G, 6) | ++ BITS(DPI_DMA_RGBSZ_B, 5) | BITS(DPI_DMA_RGBSZ_BPP, 1), ++ } ++}; ++ ++static u32 set_output_format(u32 bus_format, u32 *shift, u32 *imask, u32 *rgbsz) ++{ ++ switch (bus_format) { ++ case MEDIA_BUS_FMT_RGB565_1X16: ++ if (*shift == ISHIFT_RGB(15, 10, 4)) { ++ /* When framebuffer is RGB565, we can output RGB565 */ ++ *shift = ISHIFT_RGB(15, 7, 0) | OSHIFT_RGB(19, 9, 0); ++ *rgbsz &= DPI_DMA_RGBSZ_BPP_MASK; ++ return OMASK_RGB(0x3fc, 0x3fc, 0); ++ } ++ ++ /* due to a HW limitation, bit-depth is effectively RGB535 */ ++ *shift |= OSHIFT_RGB(19, 14, 6); ++ *imask &= IMASK_RGB(0x3e0, 0x380, 0x3e0); ++ *rgbsz = BITS(DPI_DMA_RGBSZ_G, 5) | (*rgbsz & DPI_DMA_RGBSZ_BPP_MASK); ++ return OMASK_RGB(0x3e0, 0x39c, 0x3e0); ++ ++ case MEDIA_BUS_FMT_RGB666_1X18: ++ case MEDIA_BUS_FMT_BGR666_1X18: ++ /* due to a HW limitation, bit-depth is effectively RGB444 */ ++ *shift |= OSHIFT_RGB(23, 15, 7); ++ *imask &= IMASK_RGB(0x3c0, 0x3c0, 0x3c0); ++ *rgbsz = BITS(DPI_DMA_RGBSZ_R, 2) | (*rgbsz & DPI_DMA_RGBSZ_BPP_MASK); ++ return OMASK_RGB(0x330, 0x3c0, 0x3c0); ++ ++ case MEDIA_BUS_FMT_RGB888_1X24: ++ case MEDIA_BUS_FMT_BGR888_1X24: ++ case MEDIA_BUS_FMT_RGB101010_1X30: ++ /* The full 24 bits can be output. Note that RP1's internal wiring means ++ * that 8.8.8 to GPIO pads can share with 10.10.10 to the onboard VDAC. ++ */ ++ *shift |= OSHIFT_RGB(29, 19, 9); ++ return OMASK_RGB(0x3fc, 0x3fc, 0x3fc); ++ ++ default: ++ /* RGB666_1x24_CPADHI, BGR666_1X24_CPADHI and "RGB565_666" formats */ ++ *shift |= OSHIFT_RGB(27, 17, 7); ++ *rgbsz &= DPI_DMA_RGBSZ_BPP_MASK; ++ return OMASK_RGB(0x3f0, 0x3f0, 0x3f0); ++ } ++} ++ ++#define BUS_FMT_IS_BGR(fmt) ( \ ++ ((fmt) == MEDIA_BUS_FMT_BGR666_1X18) || \ ++ ((fmt) == MEDIA_BUS_FMT_BGR666_1X24_CPADHI) || \ ++ ((fmt) == MEDIA_BUS_FMT_BGR888_1X24)) ++ ++void rp1dpi_hw_setup(struct rp1_dpi *dpi, ++ u32 in_format, u32 bus_format, bool de_inv, ++ struct drm_display_mode const *mode) ++{ ++ u32 shift, imask, omask, rgbsz; ++ int i; ++ ++ pr_info("%s: in_fmt=\'%c%c%c%c\' bus_fmt=0x%x mode=%dx%d total=%dx%d %dkHz %cH%cV%cD%cC", ++ __func__, in_format, in_format >> 8, in_format >> 16, in_format >> 24, bus_format, ++ mode->hdisplay, mode->vdisplay, ++ mode->htotal, mode->vtotal, ++ mode->clock, ++ (mode->flags & DRM_MODE_FLAG_NHSYNC) ? '-' : '+', ++ (mode->flags & DRM_MODE_FLAG_NVSYNC) ? '-' : '+', ++ de_inv ? '-' : '+', ++ dpi->clk_inv ? '-' : '+'); ++ ++ /* ++ * Configure all DPI/DMA block registers, except base address. ++ * DMA will not actually start until a FB base address is specified ++ * using rp1dpi_hw_update(). ++ */ ++ rp1dpi_hw_write(dpi, DPI_DMA_VISIBLE_AREA, ++ BITS(DPI_DMA_VISIBLE_AREA_ROWSM1, mode->vdisplay - 1) | ++ BITS(DPI_DMA_VISIBLE_AREA_COLSM1, mode->hdisplay - 1)); ++ ++ rp1dpi_hw_write(dpi, DPI_DMA_SYNC_WIDTH, ++ BITS(DPI_DMA_SYNC_WIDTH_ROWSM1, mode->vsync_end - mode->vsync_start - 1) | ++ BITS(DPI_DMA_SYNC_WIDTH_COLSM1, mode->hsync_end - mode->hsync_start - 1)); ++ ++ /* In these registers, "back porch" time includes sync width */ ++ rp1dpi_hw_write(dpi, DPI_DMA_BACK_PORCH, ++ BITS(DPI_DMA_BACK_PORCH_ROWSM1, mode->vtotal - mode->vsync_start - 1) | ++ BITS(DPI_DMA_BACK_PORCH_COLSM1, mode->htotal - mode->hsync_start - 1)); ++ ++ rp1dpi_hw_write(dpi, DPI_DMA_FRONT_PORCH, ++ BITS(DPI_DMA_FRONT_PORCH_ROWSM1, mode->vsync_start - mode->vdisplay - 1) | ++ BITS(DPI_DMA_FRONT_PORCH_COLSM1, mode->hsync_start - mode->hdisplay - 1)); ++ ++ /* Input to output pixel format conversion */ ++ for (i = 0; i < ARRAY_SIZE(my_formats); ++i) { ++ if (my_formatsi.format == in_format) ++ break; ++ } ++ if (i >= ARRAY_SIZE(my_formats)) { ++ pr_err("%s: bad input format\n", __func__); ++ i = 4; ++ } ++ if (BUS_FMT_IS_BGR(bus_format)) ++ i ^= 1; ++ shift = my_formatsi.shift; ++ imask = my_formatsi.mask; ++ rgbsz = my_formatsi.rgbsz; ++ omask = set_output_format(bus_format, &shift, &imask, &rgbsz); ++ ++ rp1dpi_hw_write(dpi, DPI_DMA_IMASK, imask); ++ rp1dpi_hw_write(dpi, DPI_DMA_OMASK, omask); ++ rp1dpi_hw_write(dpi, DPI_DMA_SHIFT, shift); ++ rp1dpi_hw_write(dpi, DPI_DMA_RGBSZ, rgbsz); ++ ++ rp1dpi_hw_write(dpi, DPI_DMA_QOS, ++ BITS(DPI_DMA_QOS_DQOS, 0x0) | ++ BITS(DPI_DMA_QOS_ULEV, 0xb) | ++ BITS(DPI_DMA_QOS_UQOS, 0x2) | ++ BITS(DPI_DMA_QOS_LLEV, 0x8) | ++ BITS(DPI_DMA_QOS_LQOS, 0x7)); ++ ++ rp1dpi_hw_write(dpi, DPI_DMA_IRQ_FLAGS, -1); ++ rp1dpi_hw_vblank_ctrl(dpi, 1); ++ ++ i = rp1dpi_hw_busy(dpi); ++ if (i) ++ pr_warn("%s: Unexpectedly busy at start!", __func__); ++ ++ rp1dpi_hw_write(dpi, DPI_DMA_CONTROL, ++ BITS(DPI_DMA_CONTROL_ARM, !i) | ++ BITS(DPI_DMA_CONTROL_AUTO_REPEAT, 1) | ++ BITS(DPI_DMA_CONTROL_HIGH_WATER, 448) | ++ BITS(DPI_DMA_CONTROL_DEN_POL, de_inv) | ++ BITS(DPI_DMA_CONTROL_HSYNC_POL, !!(mode->flags & DRM_MODE_FLAG_NHSYNC)) | ++ BITS(DPI_DMA_CONTROL_VSYNC_POL, !!(mode->flags & DRM_MODE_FLAG_NVSYNC)) | ++ BITS(DPI_DMA_CONTROL_COLORM, 0) | ++ BITS(DPI_DMA_CONTROL_SHUTDN, 0) | ++ BITS(DPI_DMA_CONTROL_HBP_EN, (mode->htotal != mode->hsync_end)) | ++ BITS(DPI_DMA_CONTROL_HFP_EN, (mode->hsync_start != mode->hdisplay)) | ++ BITS(DPI_DMA_CONTROL_VBP_EN, (mode->vtotal != mode->vsync_end)) | ++ BITS(DPI_DMA_CONTROL_VFP_EN, (mode->vsync_start != mode->vdisplay)) | ++ BITS(DPI_DMA_CONTROL_HSYNC_EN, (mode->hsync_end != mode->hsync_start)) | ++ BITS(DPI_DMA_CONTROL_VSYNC_EN, (mode->vsync_end != mode->vsync_start))); ++} ++ ++void rp1dpi_hw_update(struct rp1_dpi *dpi, dma_addr_t addr, u32 offset, u32 stride) ++{ ++ u64 a = addr + offset; ++ ++ /* ++ * Update STRIDE, DMAH and DMAL only. When called after rp1dpi_hw_setup(), ++ * DMA starts immediately; if already running, the buffer will flip at ++ * the next vertical sync event. ++ */ ++ rp1dpi_hw_write(dpi, DPI_DMA_DMA_STRIDE, stride); ++ rp1dpi_hw_write(dpi, DPI_DMA_DMA_ADDR_H, a >> 32); ++ rp1dpi_hw_write(dpi, DPI_DMA_DMA_ADDR_L, a & 0xFFFFFFFFu); ++} ++ ++void rp1dpi_hw_stop(struct rp1_dpi *dpi) ++{ ++ u32 ctrl; ++ ++ /* ++ * Stop DMA by turning off the Auto-Repeat flag, and wait up to 100ms for ++ * the current and any queued frame to end. "Force drain" flags are not used, ++ * as they seem to prevent DMA from re-starting properly; it's safer to wait. ++ */ ++ reinit_completion(&dpi->finished); ++ ctrl = rp1dpi_hw_read(dpi, DPI_DMA_CONTROL); ++ ctrl &= ~(DPI_DMA_CONTROL_ARM_MASK | DPI_DMA_CONTROL_AUTO_REPEAT_MASK); ++ rp1dpi_hw_write(dpi, DPI_DMA_CONTROL, ctrl); ++ if (!wait_for_completion_timeout(&dpi->finished, HZ / 10)) ++ drm_err(&dpi->drm, "%s: timed out waiting for idle\n", __func__); ++ rp1dpi_hw_write(dpi, DPI_DMA_IRQ_EN, 0); ++} ++ ++void rp1dpi_hw_vblank_ctrl(struct rp1_dpi *dpi, int enable) ++{ ++ rp1dpi_hw_write(dpi, DPI_DMA_IRQ_EN, ++ BITS(DPI_DMA_IRQ_EN_AFIFO_EMPTY, 1) | ++ BITS(DPI_DMA_IRQ_EN_UNDERFLOW, 1) | ++ BITS(DPI_DMA_IRQ_EN_DMA_READY, !!enable) | ++ BITS(DPI_DMA_IRQ_EN_MATCH_LINE, 4095)); ++} ++ ++irqreturn_t rp1dpi_hw_isr(int irq, void *dev) ++{ ++ struct rp1_dpi *dpi = dev; ++ u32 u = rp1dpi_hw_read(dpi, DPI_DMA_IRQ_FLAGS); ++ ++ if (u) { ++ rp1dpi_hw_write(dpi, DPI_DMA_IRQ_FLAGS, u); ++ if (dpi) { ++ if (u & DPI_DMA_IRQ_FLAGS_UNDERFLOW_MASK) ++ drm_err_ratelimited(&dpi->drm, ++ "Underflow! (panics=0x%08x)\n", ++ rp1dpi_hw_read(dpi, DPI_DMA_PANICS)); ++ if (u & DPI_DMA_IRQ_FLAGS_DMA_READY_MASK) ++ drm_crtc_handle_vblank(&dpi->pipe.crtc); ++ if (u & DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_MASK) ++ complete(&dpi->finished); ++ } ++ } ++ return u ? IRQ_HANDLED : IRQ_NONE; ++} +diff --git a/drivers/gpu/drm/rp1/rp1-dsi/Kconfig b/drivers/gpu/drm/rp1/rp1-dsi/Kconfig +new file mode 100644 +index 000000000000..80c57bc48792 +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dsi/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config DRM_RP1_DSI ++ tristate "DRM Support for RP1 DSI" ++ depends on DRM && MFD_RP1 ++ select DRM_GEM_DMA_HELPER ++ select DRM_KMS_HELPER ++ select DRM_MIPI_DSI ++ select DRM_VRAM_HELPER ++ select DRM_TTM ++ select DRM_TTM_HELPER ++ select GENERIC_PHY ++ select GENERIC_PHY_MIPI_DPHY ++ help ++ Choose this option to enable DSI display on RP1 +diff --git a/drivers/gpu/drm/rp1/rp1-dsi/Makefile b/drivers/gpu/drm/rp1/rp1-dsi/Makefile +new file mode 100644 +index 000000000000..1a9672c7bda0 +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dsi/Makefile +@@ -0,0 +1,5 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++ ++drm-rp1-dsi-y := rp1_dsi.o rp1_dsi_dma.o rp1_dsi_dsi.o ++ ++obj-$(CONFIG_DRM_RP1_DSI) += drm-rp1-dsi.o +diff --git a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c +new file mode 100644 +index 000000000000..53e0858dd69b +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c +@@ -0,0 +1,535 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for DSI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include <linux/clk.h> ++#include <linux/component.h> ++#include <linux/delay.h> ++#include <linux/dma-mapping.h> ++#include <linux/errno.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/io.h> ++#include <linux/list.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/phy/phy-mipi-dphy.h> ++#include <linux/string.h> ++ ++#include <drm/drm_atomic_helper.h> ++#include <drm/drm_crtc.h> ++#include <drm/drm_crtc_helper.h> ++#include <drm/drm_drv.h> ++#include <drm/drm_encoder.h> ++#include <drm/drm_fourcc.h> ++#include <drm/drm_fb_helper.h> ++#include <drm/drm_fbdev_generic.h> ++#include <drm/drm_framebuffer.h> ++#include <drm/drm_gem.h> ++#include <drm/drm_gem_atomic_helper.h> ++#include <drm/drm_gem_dma_helper.h> ++#include <drm/drm_gem_framebuffer_helper.h> ++#include <drm/drm_managed.h> ++#include <drm/drm_modeset_helper_vtables.h> ++#include <drm/drm_of.h> ++#include <drm/drm_print.h> ++#include <drm/drm_probe_helper.h> ++#include <drm/drm_simple_kms_helper.h> ++#include <drm/drm_vblank.h> ++ ++#include "rp1_dsi.h" ++ ++static inline struct rp1_dsi * ++bridge_to_rp1_dsi(struct drm_bridge *bridge) ++{ ++ return container_of(bridge, struct rp1_dsi, bridge); ++} ++ ++static void rp1_dsi_bridge_pre_enable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_state) ++{ ++ struct rp1_dsi *dsi = bridge_to_rp1_dsi(bridge); ++ ++ rp1dsi_dsi_setup(dsi, &dsi->pipe.crtc.state->adjusted_mode); ++} ++ ++static void rp1_dsi_bridge_enable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_state) ++{ ++} ++ ++static void rp1_dsi_bridge_disable(struct drm_bridge *bridge, ++ struct drm_bridge_state *state) ++{ ++} ++ ++static void rp1_dsi_bridge_post_disable(struct drm_bridge *bridge, ++ struct drm_bridge_state *state) ++{ ++ struct rp1_dsi *dsi = bridge_to_rp1_dsi(bridge); ++ ++ if (dsi->dsi_running) { ++ rp1dsi_dsi_stop(dsi); ++ dsi->dsi_running = false; ++ } ++} ++ ++static int rp1_dsi_bridge_attach(struct drm_bridge *bridge, ++ enum drm_bridge_attach_flags flags) ++{ ++ struct rp1_dsi *dsi = bridge_to_rp1_dsi(bridge); ++ ++ /* Attach the panel or bridge to the dsi bridge */ ++ return drm_bridge_attach(bridge->encoder, dsi->out_bridge, ++ &dsi->bridge, flags); ++ return 0; ++} ++ ++static const struct drm_bridge_funcs rp1_dsi_bridge_funcs = { ++ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, ++ .atomic_reset = drm_atomic_helper_bridge_reset, ++ .atomic_pre_enable = rp1_dsi_bridge_pre_enable, ++ .atomic_enable = rp1_dsi_bridge_enable, ++ .atomic_disable = rp1_dsi_bridge_disable, ++ .atomic_post_disable = rp1_dsi_bridge_post_disable, ++ .attach = rp1_dsi_bridge_attach, ++}; ++ ++static void rp1dsi_pipe_update(struct drm_simple_display_pipe *pipe, ++ struct drm_plane_state *old_state) ++{ ++ struct drm_pending_vblank_event *event; ++ unsigned long flags; ++ struct drm_framebuffer *fb = pipe->plane.state->fb; ++ struct rp1_dsi *dsi = pipe->crtc.dev->dev_private; ++ struct drm_gem_object *gem = fb ? drm_gem_fb_get_obj(fb, 0) : NULL; ++ struct drm_gem_dma_object *dma_obj = gem ? to_drm_gem_dma_obj(gem) : NULL; ++ bool can_update = fb && dma_obj && dsi && dsi->pipe_enabled; ++ ++ /* (Re-)start DSI,DMA where required; and update FB address */ ++ if (can_update) { ++ if (!dsi->dma_running || fb->format->format != dsi->cur_fmt) { ++ if (dsi->dma_running && fb->format->format != dsi->cur_fmt) { ++ rp1dsi_dma_stop(dsi); ++ dsi->dma_running = false; ++ } ++ if (!dsi->dma_running) { ++ rp1dsi_dma_setup(dsi, ++ fb->format->format, dsi->display_format, ++ &pipe->crtc.state->adjusted_mode); ++ dsi->dma_running = true; ++ } ++ dsi->cur_fmt = fb->format->format; ++ drm_crtc_vblank_on(&pipe->crtc); ++ } ++ rp1dsi_dma_update(dsi, dma_obj->dma_addr, fb->offsets0, fb->pitches0); ++ } ++ ++ /* Arm VBLANK event (or call it immediately in some error cases) */ ++ spin_lock_irqsave(&pipe->crtc.dev->event_lock, flags); ++ event = pipe->crtc.state->event; ++ if (event) { ++ pipe->crtc.state->event = NULL; ++ if (can_update && drm_crtc_vblank_get(&pipe->crtc) == 0) ++ drm_crtc_arm_vblank_event(&pipe->crtc, event); ++ else ++ drm_crtc_send_vblank_event(&pipe->crtc, event); ++ } ++ spin_unlock_irqrestore(&pipe->crtc.dev->event_lock, flags); ++} ++ ++static inline struct rp1_dsi * ++encoder_to_rp1_dsi(struct drm_encoder *encoder) ++{ ++ struct drm_simple_display_pipe *pipe = ++ container_of(encoder, struct drm_simple_display_pipe, encoder); ++ return container_of(pipe, struct rp1_dsi, pipe); ++} ++ ++static void rp1dsi_encoder_enable(struct drm_encoder *encoder) ++{ ++ struct rp1_dsi *dsi = encoder_to_rp1_dsi(encoder); ++ ++ /* Put DSI into video mode before starting video */ ++ rp1dsi_dsi_set_cmdmode(dsi, 0); ++ ++ /* Start DMA -> DPI */ ++ dsi->pipe_enabled = true; ++ dsi->cur_fmt = 0xdeadbeef; ++ rp1dsi_pipe_update(&dsi->pipe, 0); ++} ++ ++static void rp1dsi_encoder_disable(struct drm_encoder *encoder) ++{ ++ struct rp1_dsi *dsi = encoder_to_rp1_dsi(encoder); ++ ++ drm_crtc_vblank_off(&dsi->pipe.crtc); ++ if (dsi->dma_running) { ++ rp1dsi_dma_stop(dsi); ++ dsi->dma_running = false; ++ } ++ dsi->pipe_enabled = false; ++ ++ /* Return to command mode after stopping video */ ++ rp1dsi_dsi_set_cmdmode(dsi, 1); ++} ++ ++static const struct drm_encoder_helper_funcs rp1_dsi_encoder_funcs = { ++ .enable = rp1dsi_encoder_enable, ++ .disable = rp1dsi_encoder_disable, ++}; ++ ++static void rp1dsi_pipe_enable(struct drm_simple_display_pipe *pipe, ++ struct drm_crtc_state *crtc_state, ++ struct drm_plane_state *plane_state) ++{ ++} ++ ++static void rp1dsi_pipe_disable(struct drm_simple_display_pipe *pipe) ++{ ++} ++ ++static int rp1dsi_pipe_enable_vblank(struct drm_simple_display_pipe *pipe) ++{ ++ struct rp1_dsi *dsi = pipe->crtc.dev->dev_private; ++ ++ if (dsi) ++ rp1dsi_dma_vblank_ctrl(dsi, 1); ++ ++ return 0; ++} ++ ++static void rp1dsi_pipe_disable_vblank(struct drm_simple_display_pipe *pipe) ++{ ++ struct rp1_dsi *dsi = pipe->crtc.dev->dev_private; ++ ++ if (dsi) ++ rp1dsi_dma_vblank_ctrl(dsi, 0); ++} ++ ++static const struct drm_simple_display_pipe_funcs rp1dsi_pipe_funcs = { ++ .enable = rp1dsi_pipe_enable, ++ .update = rp1dsi_pipe_update, ++ .disable = rp1dsi_pipe_disable, ++ .enable_vblank = rp1dsi_pipe_enable_vblank, ++ .disable_vblank = rp1dsi_pipe_disable_vblank, ++}; ++ ++static const struct drm_mode_config_funcs rp1dsi_mode_funcs = { ++ .fb_create = drm_gem_fb_create, ++ .atomic_check = drm_atomic_helper_check, ++ .atomic_commit = drm_atomic_helper_commit, ++}; ++ ++static const u32 rp1dsi_formats = { ++ DRM_FORMAT_XRGB8888, ++ DRM_FORMAT_XBGR8888, ++ DRM_FORMAT_RGB888, ++ DRM_FORMAT_BGR888, ++ DRM_FORMAT_RGB565 ++}; ++ ++static void rp1dsi_stopall(struct drm_device *drm) ++{ ++ if (drm->dev_private) { ++ struct rp1_dsi *dsi = drm->dev_private; ++ ++ if (dsi->dma_running || rp1dsi_dma_busy(dsi)) { ++ rp1dsi_dma_stop(dsi); ++ dsi->dma_running = false; ++ } ++ if (dsi->dsi_running) { ++ rp1dsi_dsi_stop(dsi); ++ dsi->dsi_running = false; ++ } ++ if (dsi->clocksRP1DSI_CLOCK_CFG) ++ clk_disable_unprepare(dsi->clocksRP1DSI_CLOCK_CFG); ++ } ++} ++ ++DEFINE_DRM_GEM_DMA_FOPS(rp1dsi_fops); ++ ++static struct drm_driver rp1dsi_driver = { ++ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, ++ .fops = &rp1dsi_fops, ++ .name = "drm-rp1-dsi", ++ .desc = "drm-rp1-dsi", ++ .date = "0", ++ .major = 1, ++ .minor = 0, ++ DRM_GEM_DMA_DRIVER_OPS, ++ .release = rp1dsi_stopall, ++}; ++ ++static int rp1dsi_bind(struct rp1_dsi *dsi) ++{ ++ struct platform_device *pdev = dsi->pdev; ++ struct drm_device *drm = dsi->drm; ++ int ret; ++ ++ dsi->out_bridge = drmm_of_get_bridge(drm, pdev->dev.of_node, 0, 0); ++ if (IS_ERR(dsi->out_bridge)) ++ return PTR_ERR(dsi->out_bridge); ++ ++ ret = drmm_mode_config_init(drm); ++ if (ret) ++ goto rtn; ++ ++ drm->mode_config.max_width = 4096; ++ drm->mode_config.max_height = 4096; ++ drm->mode_config.preferred_depth = 32; ++ drm->mode_config.prefer_shadow = 0; ++ drm->mode_config.quirk_addfb_prefer_host_byte_order = true; ++ drm->mode_config.funcs = &rp1dsi_mode_funcs; ++ drm_vblank_init(drm, 1); ++ ++ ret = drm_simple_display_pipe_init(drm, ++ &dsi->pipe, ++ &rp1dsi_pipe_funcs, ++ rp1dsi_formats, ++ ARRAY_SIZE(rp1dsi_formats), ++ NULL, NULL); ++ if (ret) ++ goto rtn; ++ ++ /* We need slightly more complex encoder handling (enabling/disabling ++ * video mode), so add encoder helper functions. ++ */ ++ drm_encoder_helper_add(&dsi->pipe.encoder, &rp1_dsi_encoder_funcs); ++ ++ ret = drm_simple_display_pipe_attach_bridge(&dsi->pipe, &dsi->bridge); ++ if (ret) ++ goto rtn; ++ ++ drm_bridge_add(&dsi->bridge); ++ ++ drm_mode_config_reset(drm); ++ ++ if (dsi->clocksRP1DSI_CLOCK_CFG) ++ clk_prepare_enable(dsi->clocksRP1DSI_CLOCK_CFG); ++ ++ ret = drm_dev_register(drm, 0); ++ ++ if (ret == 0) ++ drm_fbdev_generic_setup(drm, 32); ++ ++rtn: ++ if (ret) ++ dev_err(&pdev->dev, "%s returned %d\n", __func__, ret); ++ else ++ dev_info(&pdev->dev, "%s succeeded", __func__); ++ ++ return ret; ++} ++ ++static void rp1dsi_unbind(struct rp1_dsi *dsi) ++{ ++ struct drm_device *drm = dsi->drm; ++ ++ rp1dsi_stopall(drm); ++ drm_dev_unregister(drm); ++ drm_atomic_helper_shutdown(drm); ++} ++ ++int rp1dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_device *dsi_dev) ++{ ++ struct rp1_dsi *dsi = container_of(host, struct rp1_dsi, dsi_host); ++ ++ dev_info(&dsi->pdev->dev, "%s: Attach DSI device name=%s channel=%d lanes=%d format=%d flags=0x%lx hs_rate=%lu lp_rate=%lu", ++ __func__, dsi_dev->name, dsi_dev->channel, dsi_dev->lanes, ++ dsi_dev->format, dsi_dev->mode_flags, dsi_dev->hs_rate, ++ dsi_dev->lp_rate); ++ dsi->vc = dsi_dev->channel & 3; ++ dsi->lanes = dsi_dev->lanes; ++ ++ switch (dsi_dev->format) { ++ case MIPI_DSI_FMT_RGB666: ++ case MIPI_DSI_FMT_RGB666_PACKED: ++ case MIPI_DSI_FMT_RGB565: ++ case MIPI_DSI_FMT_RGB888: ++ break; ++ default: ++ return -EINVAL; ++ } ++ dsi->display_format = dsi_dev->format; ++ dsi->display_flags = dsi_dev->mode_flags; ++ dsi->display_hs_rate = dsi_dev->hs_rate; ++ dsi->display_lp_rate = dsi_dev->lp_rate; ++ ++ /* ++ * Previously, we added a separate component to handle panel/bridge ++ * discovery and DRM registration, but now it's just a function call. ++ * The downstream/attaching device should deal with -EPROBE_DEFER ++ */ ++ return rp1dsi_bind(dsi); ++} ++ ++int rp1dsi_host_detach(struct mipi_dsi_host *host, struct mipi_dsi_device *dsi_dev) ++{ ++ struct rp1_dsi *dsi = container_of(host, struct rp1_dsi, dsi_host); ++ ++ /* ++ * Unregister the DRM driver. ++ * TODO: Check we are cleaning up correctly and not doing things multiple times! ++ */ ++ rp1dsi_unbind(dsi); ++ return 0; ++} ++ ++ssize_t rp1dsi_host_transfer(struct mipi_dsi_host *host, const struct mipi_dsi_msg *msg) ++{ ++ struct rp1_dsi *dsi = container_of(host, struct rp1_dsi, dsi_host); ++ struct mipi_dsi_packet packet; ++ int ret = 0; ++ ++ /* Write */ ++ ret = mipi_dsi_create_packet(&packet, msg); ++ if (ret) { ++ dev_err(dsi->drm->dev, "RP1DSI: failed to create packet: %d\n", ret); ++ return ret; ++ } ++ ++ rp1dsi_dsi_send(dsi, *(u32 *)(&packet.header), packet.payload_length, packet.payload); ++ ++ /* Optional read back */ ++ if (msg->rx_len && msg->rx_buf) ++ ret = rp1dsi_dsi_recv(dsi, msg->rx_len, msg->rx_buf); ++ ++ return (ssize_t)ret; ++} ++ ++static const struct mipi_dsi_host_ops rp1dsi_mipi_dsi_host_ops = { ++ .attach = rp1dsi_host_attach, ++ .detach = rp1dsi_host_detach, ++ .transfer = rp1dsi_host_transfer ++}; ++ ++static int rp1dsi_platform_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct drm_device *drm; ++ struct rp1_dsi *dsi; ++ int i, ret; ++ ++ drm = drm_dev_alloc(&rp1dsi_driver, dev); ++ if (IS_ERR(drm)) { ++ ret = PTR_ERR(drm); ++ return ret; ++ } ++ dsi = drmm_kzalloc(drm, sizeof(*dsi), GFP_KERNEL); ++ if (!dsi) { ++ ret = -ENOMEM; ++ goto err_free_drm; ++ } ++ init_completion(&dsi->finished); ++ dsi->drm = drm; ++ dsi->pdev = pdev; ++ drm->dev_private = dsi; ++ platform_set_drvdata(pdev, drm); ++ ++ dsi->bridge.funcs = &rp1_dsi_bridge_funcs; ++ dsi->bridge.of_node = dev->of_node; ++ dsi->bridge.type = DRM_MODE_CONNECTOR_DSI; ++ ++ /* Safe default values for DSI mode */ ++ dsi->lanes = 1; ++ dsi->display_format = MIPI_DSI_FMT_RGB888; ++ dsi->display_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM; ++ ++ /* Hardware resources */ ++ for (i = 0; i < RP1DSI_NUM_CLOCKS; i++) { ++ static const char * const myclocknamesRP1DSI_NUM_CLOCKS = { ++ "cfgclk", "dpiclk", "byteclk", "refclk" ++ }; ++ dsi->clocksi = devm_clk_get(dev, myclocknamesi); ++ if (IS_ERR(dsi->clocksi)) { ++ ret = PTR_ERR(dsi->clocksi); ++ dev_err(dev, "Error getting clocks%d\n", i); ++ goto err_free_drm; ++ } ++ } ++ ++ for (i = 0; i < RP1DSI_NUM_HW_BLOCKS; i++) { ++ dsi->hw_basei = ++ devm_ioremap_resource(dev, ++ platform_get_resource(dsi->pdev, ++ IORESOURCE_MEM, ++ i)); ++ if (IS_ERR(dsi->hw_basei)) { ++ ret = PTR_ERR(dsi->hw_basei); ++ dev_err(dev, "Error memory mapping regs%d\n", i); ++ goto err_free_drm; ++ } ++ } ++ ret = platform_get_irq(dsi->pdev, 0); ++ if (ret > 0) ++ ret = devm_request_irq(dev, ret, rp1dsi_dma_isr, ++ IRQF_SHARED, "rp1-dsi", dsi); ++ if (ret) { ++ dev_err(dev, "Unable to request interrupt\n"); ++ ret = -EINVAL; ++ goto err_free_drm; ++ } ++ rp1dsi_mipicfg_setup(dsi); ++ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); ++ ++ /* Create the MIPI DSI Host and wait for the panel/bridge to attach to it */ ++ dsi->dsi_host.ops = &rp1dsi_mipi_dsi_host_ops; ++ dsi->dsi_host.dev = dev; ++ ret = mipi_dsi_host_register(&dsi->dsi_host); ++ if (ret) ++ goto err_free_drm; ++ ++ return ret; ++ ++err_free_drm: ++ dev_err(dev, "%s fail %d\n", __func__, ret); ++ drm_dev_put(drm); ++ return ret; ++} ++ ++static int rp1dsi_platform_remove(struct platform_device *pdev) ++{ ++ struct drm_device *drm = platform_get_drvdata(pdev); ++ struct rp1_dsi *dsi = drm->dev_private; ++ ++ mipi_dsi_host_unregister(&dsi->dsi_host); ++ return 0; ++} ++ ++static void rp1dsi_platform_shutdown(struct platform_device *pdev) ++{ ++ struct drm_device *drm = platform_get_drvdata(pdev); ++ ++ rp1dsi_stopall(drm); ++} ++ ++static const struct of_device_id rp1dsi_of_match = { ++ { ++ .compatible = "raspberrypi,rp1dsi", ++ }, ++ { /* sentinel */ }, ++}; ++ ++MODULE_DEVICE_TABLE(of, rp1dsi_of_match); ++ ++static struct platform_driver rp1dsi_platform_driver = { ++ .probe = rp1dsi_platform_probe, ++ .remove = rp1dsi_platform_remove, ++ .shutdown = rp1dsi_platform_shutdown, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = rp1dsi_of_match, ++ }, ++}; ++ ++module_platform_driver(rp1dsi_platform_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MIPI DSI driver for Raspberry Pi RP1"); ++MODULE_AUTHOR("Nick Hollinghurst"); +diff --git a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h +new file mode 100644 +index 000000000000..c40186748a3f +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h +@@ -0,0 +1,94 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * DRM Driver for DSI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++#ifndef _RP1_DSI_H_ ++#define _RP1_DSI_H_ ++ ++#include <linux/clk.h> ++#include <linux/io.h> ++#include <linux/types.h> ++ ++#include <drm/drm_bridge.h> ++#include <drm/drm_device.h> ++#include <drm/drm_mipi_dsi.h> ++#include <drm/drm_simple_kms_helper.h> ++ ++#define MODULE_NAME "drm-rp1-dsi" ++#define DRIVER_NAME "drm-rp1-dsi" ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define RP1DSI_HW_BLOCK_DMA 0 ++#define RP1DSI_HW_BLOCK_DSI 1 ++#define RP1DSI_HW_BLOCK_CFG 2 ++#define RP1DSI_NUM_HW_BLOCKS 3 ++ ++#define RP1DSI_CLOCK_CFG 0 ++#define RP1DSI_CLOCK_DPI 1 ++#define RP1DSI_CLOCK_BYTE 2 ++#define RP1DSI_CLOCK_REF 3 ++#define RP1DSI_NUM_CLOCKS 4 ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct rp1_dsi { ++ /* DRM and platform device pointers */ ++ struct drm_device *drm; ++ struct platform_device *pdev; ++ ++ /* Framework and helper objects */ ++ struct drm_simple_display_pipe pipe; ++ struct drm_bridge bridge; ++ struct drm_bridge *out_bridge; ++ struct mipi_dsi_host dsi_host; ++ ++ /* Clocks. We need DPI clock; the others are frequency references */ ++ struct clk *clocksRP1DSI_NUM_CLOCKS; ++ ++ /* Block (DSI DMA, DSI Host) base addresses, and current state */ ++ void __iomem *hw_baseRP1DSI_NUM_HW_BLOCKS; ++ u32 cur_fmt; ++ bool dsi_running, dma_running, pipe_enabled; ++ struct completion finished; ++ ++ /* Attached display parameters (from mipi_dsi_device) */ ++ unsigned long display_flags, display_hs_rate, display_lp_rate; ++ enum mipi_dsi_pixel_format display_format; ++ u8 vc; ++ u8 lanes; ++ ++ /* DPHY */ ++ u8 hsfreq_index; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++/* Functions to control the DSI/DPI/DMA block */ ++ ++void rp1dsi_dma_setup(struct rp1_dsi *dsi, ++ u32 in_format, enum mipi_dsi_pixel_format out_format, ++ struct drm_display_mode const *mode); ++void rp1dsi_dma_update(struct rp1_dsi *dsi, dma_addr_t addr, u32 offset, u32 stride); ++void rp1dsi_dma_stop(struct rp1_dsi *dsi); ++int rp1dsi_dma_busy(struct rp1_dsi *dsi); ++irqreturn_t rp1dsi_dma_isr(int irq, void *dev); ++void rp1dsi_dma_vblank_ctrl(struct rp1_dsi *dsi, int enable); ++ ++/* ---------------------------------------------------------------------- */ ++/* Functions to control the MIPICFG block and check RP1 platform */ ++ ++void rp1dsi_mipicfg_setup(struct rp1_dsi *dsi); ++ ++/* ---------------------------------------------------------------------- */ ++/* Functions to control the SNPS D-PHY and DSI block setup */ ++ ++void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode); ++void rp1dsi_dsi_send(struct rp1_dsi *dsi, u32 header, int len, const u8 *buf); ++int rp1dsi_dsi_recv(struct rp1_dsi *dsi, int len, u8 *buf); ++void rp1dsi_dsi_set_cmdmode(struct rp1_dsi *dsi, int cmd_mode); ++void rp1dsi_dsi_stop(struct rp1_dsi *dsi); ++ ++#endif ++ +diff --git a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c +new file mode 100644 +index 000000000000..85bb0615bae9 +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c +@@ -0,0 +1,443 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for DSI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include <linux/interrupt.h> ++#include <linux/platform_device.h> ++ ++#include <drm/drm_fourcc.h> ++#include <drm/drm_print.h> ++#include <drm/drm_vblank.h> ++ ++#include "rp1_dsi.h" ++ ++// --- DPI DMA REGISTERS (derived from Argon firmware, via RP1 drivers/mipi, with corrections) --- ++ ++// Control ++#define DPI_DMA_CONTROL 0x0 ++#define DPI_DMA_CONTROL_ARM_SHIFT 0 ++#define DPI_DMA_CONTROL_ARM_MASK BIT(DPI_DMA_CONTROL_ARM_SHIFT) ++#define DPI_DMA_CONTROL_ALIGN16_SHIFT 2 ++#define DPI_DMA_CONTROL_ALIGN16_MASK BIT(DPI_DMA_CONTROL_ALIGN16_SHIFT) ++#define DPI_DMA_CONTROL_AUTO_REPEAT_SHIFT 1 ++#define DPI_DMA_CONTROL_AUTO_REPEAT_MASK BIT(DPI_DMA_CONTROL_AUTO_REPEAT_SHIFT) ++#define DPI_DMA_CONTROL_HIGH_WATER_SHIFT 3 ++#define DPI_DMA_CONTROL_HIGH_WATER_MASK (0x1FF << DPI_DMA_CONTROL_HIGH_WATER_SHIFT) ++#define DPI_DMA_CONTROL_DEN_POL_SHIFT 12 ++#define DPI_DMA_CONTROL_DEN_POL_MASK BIT(DPI_DMA_CONTROL_DEN_POL_SHIFT) ++#define DPI_DMA_CONTROL_HSYNC_POL_SHIFT 13 ++#define DPI_DMA_CONTROL_HSYNC_POL_MASK BIT(DPI_DMA_CONTROL_HSYNC_POL_SHIFT) ++#define DPI_DMA_CONTROL_VSYNC_POL_SHIFT 14 ++#define DPI_DMA_CONTROL_VSYNC_POL_MASK BIT(DPI_DMA_CONTROL_VSYNC_POL_SHIFT) ++#define DPI_DMA_CONTROL_COLORM_SHIFT 15 ++#define DPI_DMA_CONTROL_COLORM_MASK BIT(DPI_DMA_CONTROL_COLORM_SHIFT) ++#define DPI_DMA_CONTROL_SHUTDN_SHIFT 16 ++#define DPI_DMA_CONTROL_SHUTDN_MASK BIT(DPI_DMA_CONTROL_SHUTDN_SHIFT) ++#define DPI_DMA_CONTROL_HBP_EN_SHIFT 17 ++#define DPI_DMA_CONTROL_HBP_EN_MASK BIT(DPI_DMA_CONTROL_HBP_EN_SHIFT) ++#define DPI_DMA_CONTROL_HFP_EN_SHIFT 18 ++#define DPI_DMA_CONTROL_HFP_EN_MASK BIT(DPI_DMA_CONTROL_HFP_EN_SHIFT) ++#define DPI_DMA_CONTROL_VBP_EN_SHIFT 19 ++#define DPI_DMA_CONTROL_VBP_EN_MASK BIT(DPI_DMA_CONTROL_VBP_EN_SHIFT) ++#define DPI_DMA_CONTROL_VFP_EN_SHIFT 20 ++#define DPI_DMA_CONTROL_VFP_EN_MASK BIT(DPI_DMA_CONTROL_VFP_EN_SHIFT) ++#define DPI_DMA_CONTROL_HSYNC_EN_SHIFT 21 ++#define DPI_DMA_CONTROL_HSYNC_EN_MASK BIT(DPI_DMA_CONTROL_HSYNC_EN_SHIFT) ++#define DPI_DMA_CONTROL_VSYNC_EN_SHIFT 22 ++#define DPI_DMA_CONTROL_VSYNC_EN_MASK BIT(DPI_DMA_CONTROL_VSYNC_EN_SHIFT) ++#define DPI_DMA_CONTROL_FORCE_IMMED_SHIFT 23 ++#define DPI_DMA_CONTROL_FORCE_IMMED_MASK BIT(DPI_DMA_CONTROL_FORCE_IMMED_SHIFT) ++#define DPI_DMA_CONTROL_FORCE_DRAIN_SHIFT 24 ++#define DPI_DMA_CONTROL_FORCE_DRAIN_MASK BIT(DPI_DMA_CONTROL_FORCE_DRAIN_SHIFT) ++#define DPI_DMA_CONTROL_FORCE_EMPTY_SHIFT 25 ++#define DPI_DMA_CONTROL_FORCE_EMPTY_MASK BIT(DPI_DMA_CONTROL_FORCE_EMPTY_SHIFT) ++ ++// IRQ_ENABLES ++#define DPI_DMA_IRQ_EN 0x04 ++#define DPI_DMA_IRQ_EN_DMA_READY_SHIFT 0 ++#define DPI_DMA_IRQ_EN_DMA_READY_MASK BIT(DPI_DMA_IRQ_EN_DMA_READY_SHIFT) ++#define DPI_DMA_IRQ_EN_UNDERFLOW_SHIFT 1 ++#define DPI_DMA_IRQ_EN_UNDERFLOW_MASK BIT(DPI_DMA_IRQ_EN_UNDERFLOW_SHIFT) ++#define DPI_DMA_IRQ_EN_FRAME_START_SHIFT 2 ++#define DPI_DMA_IRQ_EN_FRAME_START_MASK BIT(DPI_DMA_IRQ_EN_FRAME_START_SHIFT) ++#define DPI_DMA_IRQ_EN_AFIFO_EMPTY_SHIFT 3 ++#define DPI_DMA_IRQ_EN_AFIFO_EMPTY_MASK BIT(DPI_DMA_IRQ_EN_AFIFO_EMPTY_SHIFT) ++#define DPI_DMA_IRQ_EN_TE_SHIFT 4 ++#define DPI_DMA_IRQ_EN_TE_MASK BIT(DPI_DMA_IRQ_EN_TE_SHIFT) ++#define DPI_DMA_IRQ_EN_ERROR_SHIFT 5 ++#define DPI_DMA_IRQ_EN_ERROR_MASK BIT(DPI_DMA_IRQ_EN_ERROR_SHIFT) ++#define DPI_DMA_IRQ_EN_MATCH_SHIFT 6 ++#define DPI_DMA_IRQ_EN_MATCH_MASK BIT(DPI_DMA_IRQ_EN_MATCH_SHIFT) ++#define DPI_DMA_IRQ_EN_MATCH_LINE_SHIFT 16 ++#define DPI_DMA_IRQ_EN_MATCH_LINE_MASK (0xFFF << DPI_DMA_IRQ_EN_MATCH_LINE_SHIFT) ++ ++// IRQ_FLAGS ++#define DPI_DMA_IRQ_FLAGS 0x08 ++#define DPI_DMA_IRQ_FLAGS_DMA_READY_SHIFT 0 ++#define DPI_DMA_IRQ_FLAGS_DMA_READY_MASK BIT(DPI_DMA_IRQ_FLAGS_DMA_READY_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_UNDERFLOW_SHIFT 1 ++#define DPI_DMA_IRQ_FLAGS_UNDERFLOW_MASK BIT(DPI_DMA_IRQ_FLAGS_UNDERFLOW_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_FRAME_START_SHIFT 2 ++#define DPI_DMA_IRQ_FLAGS_FRAME_START_MASK BIT(DPI_DMA_IRQ_FLAGS_FRAME_START_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_SHIFT 3 ++#define DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_MASK BIT(DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_TE_SHIFT 4 ++#define DPI_DMA_IRQ_FLAGS_TE_MASK BIT(DPI_DMA_IRQ_FLAGS_TE_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_ERROR_SHIFT 5 ++#define DPI_DMA_IRQ_FLAGS_ERROR_MASK BIT(DPI_DMA_IRQ_FLAGS_ERROR_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_MATCH_SHIFT 6 ++#define DPI_DMA_IRQ_FLAGS_MATCH_MASK BIT(DPI_DMA_IRQ_FLAGS_MATCH_SHIFT) ++ ++// QOS ++#define DPI_DMA_QOS 0xC ++#define DPI_DMA_QOS_DQOS_SHIFT 0 ++#define DPI_DMA_QOS_DQOS_MASK (0xF << DPI_DMA_QOS_DQOS_SHIFT) ++#define DPI_DMA_QOS_ULEV_SHIFT 4 ++#define DPI_DMA_QOS_ULEV_MASK (0xF << DPI_DMA_QOS_ULEV_SHIFT) ++#define DPI_DMA_QOS_UQOS_SHIFT 8 ++#define DPI_DMA_QOS_UQOS_MASK (0xF << DPI_DMA_QOS_UQOS_SHIFT) ++#define DPI_DMA_QOS_LLEV_SHIFT 12 ++#define DPI_DMA_QOS_LLEV_MASK (0xF << DPI_DMA_QOS_LLEV_SHIFT) ++#define DPI_DMA_QOS_LQOS_SHIFT 16 ++#define DPI_DMA_QOS_LQOS_MASK (0xF << DPI_DMA_QOS_LQOS_SHIFT) ++ ++// Panics ++#define DPI_DMA_PANICS 0x38 ++#define DPI_DMA_PANICS_UPPER_COUNT_SHIFT 0 ++#define DPI_DMA_PANICS_UPPER_COUNT_MASK \ ++ (0x0000FFFF << DPI_DMA_PANICS_UPPER_COUNT_SHIFT) ++#define DPI_DMA_PANICS_LOWER_COUNT_SHIFT 16 ++#define DPI_DMA_PANICS_LOWER_COUNT_MASK \ ++ (0x0000FFFF << DPI_DMA_PANICS_LOWER_COUNT_SHIFT) ++ ++// DMA Address Lower: ++#define DPI_DMA_DMA_ADDR_L 0x10 ++ ++// DMA Address Upper: ++#define DPI_DMA_DMA_ADDR_H 0x40 ++ ++// DMA stride ++#define DPI_DMA_DMA_STRIDE 0x14 ++ ++// Visible Area ++#define DPI_DMA_VISIBLE_AREA 0x18 ++#define DPI_DMA_VISIBLE_AREA_ROWSM1_SHIFT 0 ++#define DPI_DMA_VISIBLE_AREA_ROWSM1_MASK (0x0FFF << DPI_DMA_VISIBLE_AREA_ROWSM1_SHIFT) ++#define DPI_DMA_VISIBLE_AREA_COLSM1_SHIFT 16 ++#define DPI_DMA_VISIBLE_AREA_COLSM1_MASK (0x0FFF << DPI_DMA_VISIBLE_AREA_COLSM1_SHIFT) ++ ++// Sync width ++#define DPI_DMA_SYNC_WIDTH 0x1C ++#define DPI_DMA_SYNC_WIDTH_ROWSM1_SHIFT 0 ++#define DPI_DMA_SYNC_WIDTH_ROWSM1_MASK (0x0FFF << DPI_DMA_SYNC_WIDTH_ROWSM1_SHIFT) ++#define DPI_DMA_SYNC_WIDTH_COLSM1_SHIFT 16 ++#define DPI_DMA_SYNC_WIDTH_COLSM1_MASK (0x0FFF << DPI_DMA_SYNC_WIDTH_COLSM1_SHIFT) ++ ++// Back porch ++#define DPI_DMA_BACK_PORCH 0x20 ++#define DPI_DMA_BACK_PORCH_ROWSM1_SHIFT 0 ++#define DPI_DMA_BACK_PORCH_ROWSM1_MASK (0x0FFF << DPI_DMA_BACK_PORCH_ROWSM1_SHIFT) ++#define DPI_DMA_BACK_PORCH_COLSM1_SHIFT 16 ++#define DPI_DMA_BACK_PORCH_COLSM1_MASK (0x0FFF << DPI_DMA_BACK_PORCH_COLSM1_SHIFT) ++ ++// Front porch ++#define DPI_DMA_FRONT_PORCH 0x24 ++#define DPI_DMA_FRONT_PORCH_ROWSM1_SHIFT 0 ++#define DPI_DMA_FRONT_PORCH_ROWSM1_MASK (0x0FFF << DPI_DMA_FRONT_PORCH_ROWSM1_SHIFT) ++#define DPI_DMA_FRONT_PORCH_COLSM1_SHIFT 16 ++#define DPI_DMA_FRONT_PORCH_COLSM1_MASK (0x0FFF << DPI_DMA_FRONT_PORCH_COLSM1_SHIFT) ++ ++// Input masks ++#define DPI_DMA_IMASK 0x2C ++#define DPI_DMA_IMASK_R_SHIFT 0 ++#define DPI_DMA_IMASK_R_MASK (0x3FF << DPI_DMA_IMASK_R_SHIFT) ++#define DPI_DMA_IMASK_G_SHIFT 10 ++#define DPI_DMA_IMASK_G_MASK (0x3FF << DPI_DMA_IMASK_G_SHIFT) ++#define DPI_DMA_IMASK_B_SHIFT 20 ++#define DPI_DMA_IMASK_B_MASK (0x3FF << DPI_DMA_IMASK_B_SHIFT) ++ ++// Output Masks ++#define DPI_DMA_OMASK 0x30 ++#define DPI_DMA_OMASK_R_SHIFT 0 ++#define DPI_DMA_OMASK_R_MASK (0x3FF << DPI_DMA_OMASK_R_SHIFT) ++#define DPI_DMA_OMASK_G_SHIFT 10 ++#define DPI_DMA_OMASK_G_MASK (0x3FF << DPI_DMA_OMASK_G_SHIFT) ++#define DPI_DMA_OMASK_B_SHIFT 20 ++#define DPI_DMA_OMASK_B_MASK (0x3FF << DPI_DMA_OMASK_B_SHIFT) ++ ++// Shifts ++#define DPI_DMA_SHIFT 0x28 ++#define DPI_DMA_SHIFT_IR_SHIFT 0 ++#define DPI_DMA_SHIFT_IR_MASK (0x1F << DPI_DMA_SHIFT_IR_SHIFT) ++#define DPI_DMA_SHIFT_IG_SHIFT 5 ++#define DPI_DMA_SHIFT_IG_MASK (0x1F << DPI_DMA_SHIFT_IG_SHIFT) ++#define DPI_DMA_SHIFT_IB_SHIFT 10 ++#define DPI_DMA_SHIFT_IB_MASK (0x1F << DPI_DMA_SHIFT_IB_SHIFT) ++#define DPI_DMA_SHIFT_OR_SHIFT 15 ++#define DPI_DMA_SHIFT_OR_MASK (0x1F << DPI_DMA_SHIFT_OR_SHIFT) ++#define DPI_DMA_SHIFT_OG_SHIFT 20 ++#define DPI_DMA_SHIFT_OG_MASK (0x1F << DPI_DMA_SHIFT_OG_SHIFT) ++#define DPI_DMA_SHIFT_OB_SHIFT 25 ++#define DPI_DMA_SHIFT_OB_MASK (0x1F << DPI_DMA_SHIFT_OB_SHIFT) ++ ++// Scaling ++#define DPI_DMA_RGBSZ 0x34 ++#define DPI_DMA_RGBSZ_BPP_SHIFT 16 ++#define DPI_DMA_RGBSZ_BPP_MASK (0x3 << DPI_DMA_RGBSZ_BPP_SHIFT) ++#define DPI_DMA_RGBSZ_R_SHIFT 0 ++#define DPI_DMA_RGBSZ_R_MASK (0xF << DPI_DMA_RGBSZ_R_SHIFT) ++#define DPI_DMA_RGBSZ_G_SHIFT 4 ++#define DPI_DMA_RGBSZ_G_MASK (0xF << DPI_DMA_RGBSZ_G_SHIFT) ++#define DPI_DMA_RGBSZ_B_SHIFT 8 ++#define DPI_DMA_RGBSZ_B_MASK (0xF << DPI_DMA_RGBSZ_B_SHIFT) ++ ++// Status ++#define DPI_DMA_STATUS 0x3c ++ ++#define BITS(field, val) (((val) << (field ## _SHIFT)) & (field ## _MASK)) ++ ++static unsigned int rp1dsi_dma_read(struct rp1_dsi *dsi, unsigned int reg) ++{ ++ void __iomem *addr = dsi->hw_baseRP1DSI_HW_BLOCK_DMA + reg; ++ ++ return readl(addr); ++} ++ ++static void rp1dsi_dma_write(struct rp1_dsi *dsi, unsigned int reg, unsigned int val) ++{ ++ void __iomem *addr = dsi->hw_baseRP1DSI_HW_BLOCK_DMA + reg; ++ ++ writel(val, addr); ++} ++ ++int rp1dsi_dma_busy(struct rp1_dsi *dsi) ++{ ++ return (rp1dsi_dma_read(dsi, DPI_DMA_STATUS) & 0xF8F) ? 1 : 0; ++} ++ ++/* Table of supported input (in-memory/DMA) pixel formats. */ ++struct rp1dsi_ipixfmt { ++ u32 format; /* DRM format code */ ++ u32 mask; /* RGB masks (10 bits each, left justified) */ ++ u32 shift; /* RGB MSB positions in the memory word */ ++ u32 rgbsz; /* Shifts used for scaling; also (BPP/8-1) */ ++}; ++ ++#define IMASK_RGB(r, g, b) (BITS(DPI_DMA_IMASK_R, r) | \ ++ BITS(DPI_DMA_IMASK_G, g) | \ ++ BITS(DPI_DMA_IMASK_B, b)) ++#define ISHIFT_RGB(r, g, b) (BITS(DPI_DMA_SHIFT_IR, r) | \ ++ BITS(DPI_DMA_SHIFT_IG, g) | \ ++ BITS(DPI_DMA_SHIFT_IB, b)) ++ ++static const struct rp1dsi_ipixfmt my_formats = { ++ { ++ .format = DRM_FORMAT_XRGB8888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), ++ }, ++ { ++ .format = DRM_FORMAT_XBGR8888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), ++ }, ++ { ++ .format = DRM_FORMAT_RGB888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 2), ++ }, ++ { ++ .format = DRM_FORMAT_BGR888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 2), ++ }, ++ { ++ .format = DRM_FORMAT_RGB565, ++ .mask = IMASK_RGB(0x3e0, 0x3f0, 0x3e0), ++ .shift = ISHIFT_RGB(15, 10, 4), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_R, 5) | BITS(DPI_DMA_RGBSZ_G, 6) | ++ BITS(DPI_DMA_RGBSZ_B, 5) | BITS(DPI_DMA_RGBSZ_BPP, 1), ++ } ++}; ++ ++/* Choose the internal on-the-bus DPI format as expected by DSI Host. */ ++static u32 get_omask_oshift(enum mipi_dsi_pixel_format fmt, u32 *oshift) ++{ ++ switch (fmt) { ++ case MIPI_DSI_FMT_RGB565: ++ *oshift = BITS(DPI_DMA_SHIFT_OR, 15) | ++ BITS(DPI_DMA_SHIFT_OG, 10) | ++ BITS(DPI_DMA_SHIFT_OB, 4); ++ return BITS(DPI_DMA_OMASK_R, 0x3e0) | ++ BITS(DPI_DMA_OMASK_G, 0x3f0) | ++ BITS(DPI_DMA_OMASK_B, 0x3e0); ++ case MIPI_DSI_FMT_RGB666_PACKED: ++ *oshift = BITS(DPI_DMA_SHIFT_OR, 17) | ++ BITS(DPI_DMA_SHIFT_OG, 11) | ++ BITS(DPI_DMA_SHIFT_OB, 5); ++ return BITS(DPI_DMA_OMASK_R, 0x3f0) | ++ BITS(DPI_DMA_OMASK_G, 0x3f0) | ++ BITS(DPI_DMA_OMASK_B, 0x3f0); ++ case MIPI_DSI_FMT_RGB666: ++ *oshift = BITS(DPI_DMA_SHIFT_OR, 21) | ++ BITS(DPI_DMA_SHIFT_OG, 13) | ++ BITS(DPI_DMA_SHIFT_OB, 5); ++ return BITS(DPI_DMA_OMASK_R, 0x3f0) | ++ BITS(DPI_DMA_OMASK_G, 0x3f0) | ++ BITS(DPI_DMA_OMASK_B, 0x3f0); ++ default: ++ *oshift = BITS(DPI_DMA_SHIFT_OR, 23) | ++ BITS(DPI_DMA_SHIFT_OG, 15) | ++ BITS(DPI_DMA_SHIFT_OB, 7); ++ return BITS(DPI_DMA_OMASK_R, 0x3fc) | ++ BITS(DPI_DMA_OMASK_G, 0x3fc) | ++ BITS(DPI_DMA_OMASK_B, 0x3fc); ++ } ++} ++ ++void rp1dsi_dma_setup(struct rp1_dsi *dsi, ++ u32 in_format, enum mipi_dsi_pixel_format out_format, ++ struct drm_display_mode const *mode) ++{ ++ u32 oshift; ++ int i; ++ ++ /* ++ * Configure all DSI/DPI/DMA block registers, except base address. ++ * DMA will not actually start until a FB base address is specified ++ * using rp1dsi_dma_update(). ++ */ ++ ++ rp1dsi_dma_write(dsi, DPI_DMA_VISIBLE_AREA, ++ BITS(DPI_DMA_VISIBLE_AREA_ROWSM1, mode->vdisplay - 1) | ++ BITS(DPI_DMA_VISIBLE_AREA_COLSM1, mode->hdisplay - 1)); ++ ++ rp1dsi_dma_write(dsi, DPI_DMA_SYNC_WIDTH, ++ BITS(DPI_DMA_SYNC_WIDTH_ROWSM1, mode->vsync_end - mode->vsync_start - 1) | ++ BITS(DPI_DMA_SYNC_WIDTH_COLSM1, mode->hsync_end - mode->hsync_start - 1)); ++ ++ /* In the DPIDMA registers, "back porch" time includes sync width */ ++ rp1dsi_dma_write(dsi, DPI_DMA_BACK_PORCH, ++ BITS(DPI_DMA_BACK_PORCH_ROWSM1, mode->vtotal - mode->vsync_start - 1) | ++ BITS(DPI_DMA_BACK_PORCH_COLSM1, mode->htotal - mode->hsync_start - 1)); ++ ++ rp1dsi_dma_write(dsi, DPI_DMA_FRONT_PORCH, ++ BITS(DPI_DMA_FRONT_PORCH_ROWSM1, mode->vsync_start - mode->vdisplay - 1) | ++ BITS(DPI_DMA_FRONT_PORCH_COLSM1, mode->hsync_start - mode->hdisplay - 1)); ++ ++ /* Input to output pixel format conversion */ ++ for (i = 0; i < ARRAY_SIZE(my_formats); ++i) { ++ if (my_formatsi.format == in_format) ++ break; ++ } ++ if (i >= ARRAY_SIZE(my_formats)) { ++ drm_err(dsi->drm, "%s: bad input format\n", __func__); ++ i = 0; ++ } ++ rp1dsi_dma_write(dsi, DPI_DMA_IMASK, my_formatsi.mask); ++ rp1dsi_dma_write(dsi, DPI_DMA_OMASK, get_omask_oshift(out_format, &oshift)); ++ rp1dsi_dma_write(dsi, DPI_DMA_SHIFT, my_formatsi.shift | oshift); ++ if (out_format == MIPI_DSI_FMT_RGB888) ++ rp1dsi_dma_write(dsi, DPI_DMA_RGBSZ, my_formatsi.rgbsz); ++ else ++ rp1dsi_dma_write(dsi, DPI_DMA_RGBSZ, my_formatsi.rgbsz & DPI_DMA_RGBSZ_BPP_MASK); ++ ++ rp1dsi_dma_write(dsi, DPI_DMA_QOS, ++ BITS(DPI_DMA_QOS_DQOS, 0x0) | ++ BITS(DPI_DMA_QOS_ULEV, 0xb) | ++ BITS(DPI_DMA_QOS_UQOS, 0x2) | ++ BITS(DPI_DMA_QOS_LLEV, 0x8) | ++ BITS(DPI_DMA_QOS_LQOS, 0x7)); ++ ++ rp1dsi_dma_write(dsi, DPI_DMA_IRQ_FLAGS, -1); ++ rp1dsi_dma_vblank_ctrl(dsi, 1); ++ ++ i = rp1dsi_dma_busy(dsi); ++ if (i) ++ drm_err(dsi->drm, "RP1DSI: Unexpectedly busy at start!"); ++ ++ rp1dsi_dma_write(dsi, DPI_DMA_CONTROL, ++ BITS(DPI_DMA_CONTROL_ARM, (i == 0)) | ++ BITS(DPI_DMA_CONTROL_AUTO_REPEAT, 1) | ++ BITS(DPI_DMA_CONTROL_HIGH_WATER, 448) | ++ BITS(DPI_DMA_CONTROL_DEN_POL, 0) | ++ BITS(DPI_DMA_CONTROL_HSYNC_POL, 0) | ++ BITS(DPI_DMA_CONTROL_VSYNC_POL, 0) | ++ BITS(DPI_DMA_CONTROL_COLORM, 0) | ++ BITS(DPI_DMA_CONTROL_SHUTDN, 0) | ++ BITS(DPI_DMA_CONTROL_HBP_EN, 1) | ++ BITS(DPI_DMA_CONTROL_HFP_EN, 1) | ++ BITS(DPI_DMA_CONTROL_VBP_EN, 1) | ++ BITS(DPI_DMA_CONTROL_VFP_EN, 1) | ++ BITS(DPI_DMA_CONTROL_HSYNC_EN, 1) | ++ BITS(DPI_DMA_CONTROL_VSYNC_EN, 1)); ++} ++ ++void rp1dsi_dma_update(struct rp1_dsi *dsi, dma_addr_t addr, u32 offset, u32 stride) ++{ ++ /* ++ * Update STRIDE, DMAH and DMAL only. When called after rp1dsi_dma_setup(), ++ * DMA starts immediately; if already running, the buffer will flip at ++ * the next vertical sync event. ++ */ ++ u64 a = addr + offset; ++ ++ rp1dsi_dma_write(dsi, DPI_DMA_DMA_STRIDE, stride); ++ rp1dsi_dma_write(dsi, DPI_DMA_DMA_ADDR_H, a >> 32); ++ rp1dsi_dma_write(dsi, DPI_DMA_DMA_ADDR_L, a & 0xFFFFFFFFu); ++} ++ ++void rp1dsi_dma_stop(struct rp1_dsi *dsi) ++{ ++ /* ++ * Stop DMA by turning off the Auto-Repeat flag, and wait up to 100ms for ++ * the current and any queued frame to end. "Force drain" flags are not used, ++ * as they seem to prevent DMA from re-starting properly; it's safer to wait. ++ */ ++ u32 ctrl; ++ ++ reinit_completion(&dsi->finished); ++ ctrl = rp1dsi_dma_read(dsi, DPI_DMA_CONTROL); ++ ctrl &= ~(DPI_DMA_CONTROL_ARM_MASK | DPI_DMA_CONTROL_AUTO_REPEAT_MASK); ++ rp1dsi_dma_write(dsi, DPI_DMA_CONTROL, ctrl); ++ if (!wait_for_completion_timeout(&dsi->finished, HZ / 10)) ++ drm_err(dsi->drm, "%s: timed out waiting for idle\n", __func__); ++ rp1dsi_dma_write(dsi, DPI_DMA_IRQ_EN, 0); ++} ++ ++void rp1dsi_dma_vblank_ctrl(struct rp1_dsi *dsi, int enable) ++{ ++ rp1dsi_dma_write(dsi, DPI_DMA_IRQ_EN, ++ BITS(DPI_DMA_IRQ_EN_AFIFO_EMPTY, 1) | ++ BITS(DPI_DMA_IRQ_EN_UNDERFLOW, 1) | ++ BITS(DPI_DMA_IRQ_EN_DMA_READY, !!enable) | ++ BITS(DPI_DMA_IRQ_EN_MATCH_LINE, 4095)); ++} ++ ++irqreturn_t rp1dsi_dma_isr(int irq, void *dev) ++{ ++ struct rp1_dsi *dsi = dev; ++ u32 u = rp1dsi_dma_read(dsi, DPI_DMA_IRQ_FLAGS); ++ ++ if (u) { ++ rp1dsi_dma_write(dsi, DPI_DMA_IRQ_FLAGS, u); ++ if (dsi) { ++ if (u & DPI_DMA_IRQ_FLAGS_UNDERFLOW_MASK) ++ drm_err_ratelimited(dsi->drm, ++ "Underflow! (panics=0x%08x)\n", ++ rp1dsi_dma_read(dsi, DPI_DMA_PANICS)); ++ if (u & DPI_DMA_IRQ_FLAGS_DMA_READY_MASK) ++ drm_crtc_handle_vblank(&dsi->pipe.crtc); ++ if (u & DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_MASK) ++ complete(&dsi->finished); ++ } ++ } ++ return u ? IRQ_HANDLED : IRQ_NONE; ++} +diff --git a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c +new file mode 100644 +index 000000000000..f6fefa4acb3b +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c +@@ -0,0 +1,1504 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for DSI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/errno.h> ++#include <linux/platform_device.h> ++#include <linux/rp1_platform.h> ++#include "drm/drm_print.h" ++ ++#include "rp1_dsi.h" ++ ++/* ------------------------------- Synopsis DSI ------------------------ */ ++#define DSI_VERSION_CFG 0x000 ++#define DSI_PWR_UP 0x004 ++#define DSI_CLKMGR_CFG 0x008 ++#define DSI_DPI_VCID 0x00C ++#define DSI_DPI_COLOR_CODING 0x010 ++#define DSI_DPI_CFG_POL 0x014 ++#define DSI_DPI_LP_CMD_TIM 0x018 ++#define DSI_DBI_VCID 0x01C ++#define DSI_DBI_CFG 0x020 ++#define DSI_DBI_PARTITIONING_EN 0x024 ++#define DSI_DBI_CMDSIZE 0x028 ++#define DSI_PCKHDL_CFG 0x02C ++#define DSI_GEN_VCID 0x030 ++#define DSI_MODE_CFG 0x034 ++#define DSI_VID_MODE_CFG 0x038 ++#define DSI_VID_PKT_SIZE 0x03C ++#define DSI_VID_NUM_CHUNKS 0x040 ++#define DSI_VID_NULL_SIZE 0x044 ++#define DSI_VID_HSA_TIME 0x048 ++#define DSI_VID_HBP_TIME 0x04C ++#define DSI_VID_HLINE_TIME 0x050 ++#define DSI_VID_VSA_LINES 0x054 ++#define DSI_VID_VBP_LINES 0x058 ++#define DSI_VID_VFP_LINES 0x05C ++#define DSI_VID_VACTIVE_LINES 0x060 ++#define DSI_EDPI_CMD_SIZE 0x064 ++#define DSI_CMD_MODE_CFG 0x068 ++#define DSI_GEN_HDR 0x06C ++#define DSI_GEN_PLD_DATA 0x070 ++#define DSI_CMD_PKT_STATUS 0x074 ++#define DSI_TO_CNT_CFG 0x078 ++#define DSI_HS_RD_TO_CNT 0x07C ++#define DSI_LP_RD_TO_CNT 0x080 ++#define DSI_HS_WR_TO_CNT 0x084 ++#define DSI_LP_WR_TO_CNT 0x088 ++#define DSI_BTA_TO_CNT 0x08C ++#define DSI_SDF_3D 0x090 ++#define DSI_LPCLK_CTRL 0x094 ++#define DSI_PHY_TMR_LPCLK_CFG 0x098 ++#define DSI_PHY_TMR_HS2LP_LSB 16 ++#define DSI_PHY_TMR_LP2HS_LSB 0 ++#define DSI_PHY_TMR_CFG 0x09C ++#define DSI_PHY_TMR_RD_CFG 0x0F4 ++#define DSI_PHYRSTZ 0x0A0 ++#define DSI_PHY_IF_CFG 0x0A4 ++#define DSI_PHY_ULPS_CTRL 0x0A8 ++#define DSI_PHY_TX_TRIGGERS 0x0AC ++#define DSI_PHY_STATUS 0x0B0 ++ ++#define DSI_PHY_TST_CTRL0 0x0B4 ++#define DSI_PHY_TST_CTRL1 0x0B8 ++#define DSI_INT_ST0 0x0BC ++#define DSI_INT_ST1 0x0C0 ++#define DSI_INT_MASK0_CFG 0x0C4 ++#define DSI_INT_MASK1_CFG 0x0C8 ++#define DSI_PHY_CAL 0x0CC ++#define DSI_HEXP_NPKT_CLR 0x104 ++#define DSI_HEXP_NPKT_SIZE 0x108 ++#define DSI_VID_SHADOW_CTRL 0x100 ++ ++#define DSI_DPI_VCID_ACT 0x10C ++#define DSI_DPI_COLOR_CODING_ACT 0x110 ++#define DSI_DPI_LP_CMD_TIM_ACT 0x118 ++#define DSI_VID_MODE_CFG_ACT 0x138 ++#define DSI_VID_PKT_SIZE_ACT 0x13C ++#define DSI_VID_NUM_CHUNKS_ACT 0x140 ++#define DSI_VID_NULL_SIZE_ACT 0x144 ++#define DSI_VID_HSA_TIME_ACT 0x148 ++#define DSI_VID_HBP_TIME_ACT 0x14C ++#define DSI_VID_HLINE_TIME_ACT 0x150 ++#define DSI_VID_VSA_LINES_ACT 0x154 ++#define DSI_VID_VBP_LINES_ACT 0x158 ++#define DSI_VID_VFP_LINES_ACT 0x15C ++#define DSI_VID_VACTIVE_LINES_ACT 0x160 ++#define DSI_SDF_3D_CFG_ACT 0x190 ++ ++#define DSI_INT_FORCE0 0x0D8 ++#define DSI_INT_FORCE1 0x0DC ++ ++#define DSI_AUTO_ULPS_MODE 0x0E0 ++#define DSI_AUTO_ULPS_ENTRY_DELAY 0x0E4 ++#define DSI_AUTO_ULPS_WAKEUP_TIME 0x0E8 ++#define DSI_EDPI_ADV_FEATURES 0x0EC ++ ++#define DSI_DSC_PARAMETER 0x0F0 ++ ++/* And some bitfield definitions */ ++ ++#define DPHY_PWR_UP_SHUTDOWNZ_LSB 0 ++#define DPHY_PWR_UP_SHUTDOWNZ_BITS BIT(DPHY_PWR_UP_SHUTDOWNZ_LSB) ++ ++#define DPHY_CTRL0_PHY_TESTCLK_LSB 1 ++#define DPHY_CTRL0_PHY_TESTCLK_BITS BIT(DPHY_CTRL0_PHY_TESTCLK_LSB) ++#define DPHY_CTRL0_PHY_TESTCLR_LSB 0 ++#define DPHY_CTRL0_PHY_TESTCLR_BITS BIT(DPHY_CTRL0_PHY_TESTCLR_LSB) ++ ++#define DPHY_CTRL1_PHY_TESTDIN_LSB 0 ++#define DPHY_CTRL1_PHY_TESTDIN_BITS (0xff << DPHY_CTRL1_PHY_TESTDIN_LSB) ++#define DPHY_CTRL1_PHY_TESTDOUT_LSB 8 ++#define DPHY_CTRL1_PHY_TESTDOUT_BITS (0xff << DPHY_CTRL1_PHY_TESTDOUT_LSB) ++#define DPHY_CTRL1_PHY_TESTEN_LSB 16 ++#define DPHY_CTRL1_PHY_TESTEN_BITS BIT(DPHY_CTRL1_PHY_TESTEN_LSB) ++ ++#define DSI_PHYRSTZ_SHUTDOWNZ_LSB 0 ++#define DSI_PHYRSTZ_SHUTDOWNZ_BITS BIT(DSI_PHYRSTZ_SHUTDOWNZ_LSB) ++#define DSI_PHYRSTZ_RSTZ_LSB 1 ++#define DSI_PHYRSTZ_RSTZ_BITS BIT(DSI_PHYRSTZ_RSTZ_LSB) ++#define DSI_PHYRSTZ_ENABLECLK_LSB 2 ++#define DSI_PHYRSTZ_ENABLECLK_BITS BIT(DSI_PHYRSTZ_ENABLECLK_LSB) ++#define DSI_PHYRSTZ_FORCEPLL_LSB 3 ++#define DSI_PHYRSTZ_FORCEPLL_BITS BIT(DSI_PHYRSTZ_FORCEPLL_LSB) ++ ++#define DPHY_HS_RX_CTRL_LANE0_OFFSET 0x44 ++#define DPHY_PLL_INPUT_DIV_OFFSET 0x17 ++#define DPHY_PLL_LOOP_DIV_OFFSET 0x18 ++#define DPHY_PLL_DIV_CTRL_OFFSET 0x19 ++ ++#define DPHY_PLL_BIAS_OFFSET 0x10 ++#define DPHY_PLL_BIAS_VCO_RANGE_LSB 3 ++#define DPHY_PLL_BIAS_USE_PROGRAMMED_VCO_RANGE BIT(7) ++ ++#define DPHY_PLL_CHARGE_PUMP_OFFSET 0x11 ++#define DPHY_PLL_LPF_OFFSET 0x12 ++ ++#define DSI_WRITE(reg, val) writel((val), dsi->hw_baseRP1DSI_HW_BLOCK_DSI + (reg)) ++#define DSI_READ(reg) readl(dsi->hw_baseRP1DSI_HW_BLOCK_DSI + (reg)) ++ ++// ================================================================================ ++// Register block : RPI_MIPICFG ++// Version : 1 ++// Bus type : apb ++// Description : Register block to control mipi DPHY ++// ================================================================================ ++#define RPI_MIPICFG_REGS_RWTYPE_MSB 13 ++#define RPI_MIPICFG_REGS_RWTYPE_LSB 12 ++// ================================================================================ ++// Register : RPI_MIPICFG_CLK2FC ++// JTAG access : synchronous ++// Description : None ++#define RPI_MIPICFG_CLK2FC_OFFSET 0x00000000 ++#define RPI_MIPICFG_CLK2FC_BITS 0x00000007 ++#define RPI_MIPICFG_CLK2FC_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_CLK2FC_SEL ++// Description : select a clock to be sent to the frequency counter ++// 7 = none ++// 6 = none ++// 5 = none ++// 4 = rxbyteclkhs (187.5MHz) ++// 3 = rxclkesc0 (20MHz) ++// 2 = txbyteclkhs (187.5MHz) ++// 1 = txclkesc (125MHz) ++// 0 = none ++#define RPI_MIPICFG_CLK2FC_SEL_RESET 0x0 ++#define RPI_MIPICFG_CLK2FC_SEL_BITS 0x00000007 ++#define RPI_MIPICFG_CLK2FC_SEL_MSB 2 ++#define RPI_MIPICFG_CLK2FC_SEL_LSB 0 ++#define RPI_MIPICFG_CLK2FC_SEL_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_CFG ++// JTAG access : asynchronous ++// Description : Top level configuration ++#define RPI_MIPICFG_CFG_OFFSET 0x00000004 ++#define RPI_MIPICFG_CFG_BITS 0x00000111 ++#define RPI_MIPICFG_CFG_RESET 0x00000001 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_CFG_DPIUPDATE ++// Description : Indicate the DSI block that the next frame will have a new video configuration ++#define RPI_MIPICFG_CFG_DPIUPDATE_RESET 0x0 ++#define RPI_MIPICFG_CFG_DPIUPDATE_BITS 0x00000100 ++#define RPI_MIPICFG_CFG_DPIUPDATE_MSB 8 ++#define RPI_MIPICFG_CFG_DPIUPDATE_LSB 8 ++#define RPI_MIPICFG_CFG_DPIUPDATE_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_CFG_SEL_TE_EXT ++// Description : Select the TE source: 1 - ext, 0 - int ++#define RPI_MIPICFG_CFG_SEL_TE_EXT_RESET 0x0 ++#define RPI_MIPICFG_CFG_SEL_TE_EXT_BITS 0x00000010 ++#define RPI_MIPICFG_CFG_SEL_TE_EXT_MSB 4 ++#define RPI_MIPICFG_CFG_SEL_TE_EXT_LSB 4 ++#define RPI_MIPICFG_CFG_SEL_TE_EXT_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_CFG_SEL_CSI_DSI_N ++// Description : Select PHY direction: input to CSI, output from DSI. CSI 1 DSI 0 ++#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_RESET 0x1 ++#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_BITS 0x00000001 ++#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_MSB 0 ++#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_LSB 0 ++#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_TE ++// JTAG access : synchronous ++// Description : Tearing effect processing ++#define RPI_MIPICFG_TE_OFFSET 0x00000008 ++#define RPI_MIPICFG_TE_BITS 0x10ffffff ++#define RPI_MIPICFG_TE_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_TE_ARM ++// Description : Tearing effect arm ++#define RPI_MIPICFG_TE_ARM_RESET 0x0 ++#define RPI_MIPICFG_TE_ARM_BITS 0x10000000 ++#define RPI_MIPICFG_TE_ARM_MSB 28 ++#define RPI_MIPICFG_TE_ARM_LSB 28 ++#define RPI_MIPICFG_TE_ARM_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_TE_HALT_CYC ++// Description : When arm pulse has been seen, wait for te; then halt the dpi block ++// for this many clk_dpi cycles ++#define RPI_MIPICFG_TE_HALT_CYC_RESET 0x000000 ++#define RPI_MIPICFG_TE_HALT_CYC_BITS 0x00ffffff ++#define RPI_MIPICFG_TE_HALT_CYC_MSB 23 ++#define RPI_MIPICFG_TE_HALT_CYC_LSB 0 ++#define RPI_MIPICFG_TE_HALT_CYC_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_DPHY_MONITOR ++// JTAG access : asynchronous ++// Description : DPHY status monitors for analog DFT ++#define RPI_MIPICFG_DPHY_MONITOR_OFFSET 0x00000010 ++#define RPI_MIPICFG_DPHY_MONITOR_BITS 0x00111fff ++#define RPI_MIPICFG_DPHY_MONITOR_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_MONITOR_LOCK ++// Description : None ++#define RPI_MIPICFG_DPHY_MONITOR_LOCK_RESET 0x0 ++#define RPI_MIPICFG_DPHY_MONITOR_LOCK_BITS 0x00100000 ++#define RPI_MIPICFG_DPHY_MONITOR_LOCK_MSB 20 ++#define RPI_MIPICFG_DPHY_MONITOR_LOCK_LSB 20 ++#define RPI_MIPICFG_DPHY_MONITOR_LOCK_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_MONITOR_BISTOK ++// Description : None ++#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_RESET 0x0 ++#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_BITS 0x00010000 ++#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_MSB 16 ++#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_LSB 16 ++#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK ++// Description : None ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_RESET 0x0 ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_BITS 0x00001000 ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_MSB 12 ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_LSB 12 ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA ++// Description : None ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_RESET 0x0 ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_BITS 0x00000f00 ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_MSB 11 ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_LSB 8 ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_MONITOR_TESTDOUT ++// Description : None ++#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_RESET 0x00 ++#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_BITS 0x000000ff ++#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_MSB 7 ++#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_LSB 0 ++#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_ACCESS "RO" ++// ================================================================================ ++// Register : RPI_MIPICFG_DPHY_CTRL_0 ++// JTAG access : asynchronous ++// Description : DPHY control for analog DFT ++#define RPI_MIPICFG_DPHY_CTRL_0_OFFSET 0x00000014 ++#define RPI_MIPICFG_DPHY_CTRL_0_BITS 0x0000003f ++#define RPI_MIPICFG_DPHY_CTRL_0_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE ++// Description : When set in lpmode, TXCLKESC is driven from clk_vec(driven from clocks block) ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_BITS 0x00000020 ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_MSB 5 ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_LSB 5 ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA ++// Description : When set, drive the DPHY from the test registers ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_BITS 0x00000010 ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_MSB 4 ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_LSB 4 ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS ++// Description : When test_ena is set, disable cfg_clk ++#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_BITS 0x00000008 ++#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_MSB 3 ++#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_LSB 3 ++#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS ++// Description : When test_ena is set, disable refclk ++#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_BITS 0x00000004 ++#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_MSB 2 ++#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_LSB 2 ++#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS ++// Description : When test_ena is set, disable txclkesc ++#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_BITS 0x00000002 ++#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_MSB 1 ++#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_LSB 1 ++#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS ++// Description : When test_ena is set, disable txbyteclkhs ++#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_BITS 0x00000001 ++#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_MSB 0 ++#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_LSB 0 ++#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_DPHY_CTRL_1 ++// JTAG access : asynchronous ++// Description : DPHY control for analog DFT ++#define RPI_MIPICFG_DPHY_CTRL_1_OFFSET 0x00000018 ++#define RPI_MIPICFG_DPHY_CTRL_1_BITS 0x7fffffff ++#define RPI_MIPICFG_DPHY_CTRL_1_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_BITS 0x40000000 ++#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_MSB 30 ++#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_LSB 30 ++#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_BITS 0x20000000 ++#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_MSB 29 ++#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_LSB 29 ++#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_RSTZ ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_BITS 0x10000000 ++#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_MSB 28 ++#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_LSB 28 ++#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_BITS 0x08000000 ++#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_MSB 27 ++#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_LSB 27 ++#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_BISTON ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_BITS 0x04000000 ++#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_MSB 26 ++#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_LSB 26 ++#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_BITS 0x02000000 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_MSB 25 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_LSB 25 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_BITS 0x01000000 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_MSB 24 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_LSB 24 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_BITS 0x00800000 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_MSB 23 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_LSB 23 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_BITS 0x00400000 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_MSB 22 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_LSB 22 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_BITS 0x00200000 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_MSB 21 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_LSB 21 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_BITS 0x00100000 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_MSB 20 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_LSB 20 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_BITS 0x00080000 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_MSB 19 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_LSB 19 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_BITS 0x00040000 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_MSB 18 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_LSB 18 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_BITS 0x00020000 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_MSB 17 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_LSB 17 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_BITS 0x00010000 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_MSB 16 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_LSB 16 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_BITS 0x00008000 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_MSB 15 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_LSB 15 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_BITS 0x00004000 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_MSB 14 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_LSB 14 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_BITS 0x00002000 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_MSB 13 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_LSB 13 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_BITS 0x00001000 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_MSB 12 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_LSB 12 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_BITS 0x00000800 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_MSB 11 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_LSB 11 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_BITS 0x00000400 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_MSB 10 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_LSB 10 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_BITS 0x00000200 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_MSB 9 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_LSB 9 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_BITS 0x00000100 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_MSB 8 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_LSB 8 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_BITS 0x00000080 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_MSB 7 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_LSB 7 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_BITS 0x00000040 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_MSB 6 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_LSB 6 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_BITS 0x00000020 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_MSB 5 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_LSB 5 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_BITS 0x00000010 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_MSB 4 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_LSB 4 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_BITS 0x00000008 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_MSB 3 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_LSB 3 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_BITS 0x00000004 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_MSB 2 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_LSB 2 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_BITS 0x00000002 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_MSB 1 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_LSB 1 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_BITS 0x00000001 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_MSB 0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_LSB 0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_DPHY_CTRL_2 ++// JTAG access : asynchronous ++// Description : DPHY control for analog DFT ++#define RPI_MIPICFG_DPHY_CTRL_2_OFFSET 0x0000001c ++#define RPI_MIPICFG_DPHY_CTRL_2_BITS 0x000007ff ++#define RPI_MIPICFG_DPHY_CTRL_2_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_2_TESTCLK ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_BITS 0x00000400 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_MSB 10 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_LSB 10 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_2_TESTEN ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_BITS 0x00000200 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_MSB 9 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_LSB 9 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_2_TESTCLR ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_BITS 0x00000100 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_MSB 8 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_LSB 8 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_2_TESTDIN ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_BITS 0x000000ff ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_MSB 7 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_LSB 0 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_DPHY_CTRL_3 ++// JTAG access : asynchronous ++// Description : DPHY control for analog DFT ++#define RPI_MIPICFG_DPHY_CTRL_3_OFFSET 0x00000020 ++#define RPI_MIPICFG_DPHY_CTRL_3_BITS 0xffffffff ++#define RPI_MIPICFG_DPHY_CTRL_3_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_BITS 0xff000000 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_MSB 31 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_LSB 24 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_BITS 0x00ff0000 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_MSB 23 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_LSB 16 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_BITS 0x0000ff00 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_MSB 15 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_LSB 8 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_BITS 0x000000ff ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_MSB 7 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_LSB 0 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_DPHY_CTRL_4 ++// JTAG access : asynchronous ++// Description : DPHY control for analog DFT ++#define RPI_MIPICFG_DPHY_CTRL_4_OFFSET 0x00000024 ++#define RPI_MIPICFG_DPHY_CTRL_4_BITS 0xffffffff ++#define RPI_MIPICFG_DPHY_CTRL_4_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_BITS 0xff000000 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_MSB 31 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_LSB 24 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_BITS 0x00ff0000 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_MSB 23 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_LSB 16 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_BITS 0x0000ff00 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_MSB 15 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_LSB 8 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_BITS 0x000000ff ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_MSB 7 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_LSB 0 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_INTR ++// JTAG access : synchronous ++// Description : Raw Interrupts ++#define RPI_MIPICFG_INTR_OFFSET 0x00000028 ++#define RPI_MIPICFG_INTR_BITS 0x0000000f ++#define RPI_MIPICFG_INTR_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTR_DSI_HOST ++// Description : None ++#define RPI_MIPICFG_INTR_DSI_HOST_RESET 0x0 ++#define RPI_MIPICFG_INTR_DSI_HOST_BITS 0x00000008 ++#define RPI_MIPICFG_INTR_DSI_HOST_MSB 3 ++#define RPI_MIPICFG_INTR_DSI_HOST_LSB 3 ++#define RPI_MIPICFG_INTR_DSI_HOST_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTR_CSI_HOST ++// Description : None ++#define RPI_MIPICFG_INTR_CSI_HOST_RESET 0x0 ++#define RPI_MIPICFG_INTR_CSI_HOST_BITS 0x00000004 ++#define RPI_MIPICFG_INTR_CSI_HOST_MSB 2 ++#define RPI_MIPICFG_INTR_CSI_HOST_LSB 2 ++#define RPI_MIPICFG_INTR_CSI_HOST_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTR_DSI_DMA ++// Description : None ++#define RPI_MIPICFG_INTR_DSI_DMA_RESET 0x0 ++#define RPI_MIPICFG_INTR_DSI_DMA_BITS 0x00000002 ++#define RPI_MIPICFG_INTR_DSI_DMA_MSB 1 ++#define RPI_MIPICFG_INTR_DSI_DMA_LSB 1 ++#define RPI_MIPICFG_INTR_DSI_DMA_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTR_CSI_DMA ++// Description : None ++#define RPI_MIPICFG_INTR_CSI_DMA_RESET 0x0 ++#define RPI_MIPICFG_INTR_CSI_DMA_BITS 0x00000001 ++#define RPI_MIPICFG_INTR_CSI_DMA_MSB 0 ++#define RPI_MIPICFG_INTR_CSI_DMA_LSB 0 ++#define RPI_MIPICFG_INTR_CSI_DMA_ACCESS "RO" ++// ================================================================================ ++// Register : RPI_MIPICFG_INTE ++// JTAG access : synchronous ++// Description : Interrupt Enable ++#define RPI_MIPICFG_INTE_OFFSET 0x0000002c ++#define RPI_MIPICFG_INTE_BITS 0x0000000f ++#define RPI_MIPICFG_INTE_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTE_DSI_HOST ++// Description : None ++#define RPI_MIPICFG_INTE_DSI_HOST_RESET 0x0 ++#define RPI_MIPICFG_INTE_DSI_HOST_BITS 0x00000008 ++#define RPI_MIPICFG_INTE_DSI_HOST_MSB 3 ++#define RPI_MIPICFG_INTE_DSI_HOST_LSB 3 ++#define RPI_MIPICFG_INTE_DSI_HOST_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTE_CSI_HOST ++// Description : None ++#define RPI_MIPICFG_INTE_CSI_HOST_RESET 0x0 ++#define RPI_MIPICFG_INTE_CSI_HOST_BITS 0x00000004 ++#define RPI_MIPICFG_INTE_CSI_HOST_MSB 2 ++#define RPI_MIPICFG_INTE_CSI_HOST_LSB 2 ++#define RPI_MIPICFG_INTE_CSI_HOST_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTE_DSI_DMA ++// Description : None ++#define RPI_MIPICFG_INTE_DSI_DMA_RESET 0x0 ++#define RPI_MIPICFG_INTE_DSI_DMA_BITS 0x00000002 ++#define RPI_MIPICFG_INTE_DSI_DMA_MSB 1 ++#define RPI_MIPICFG_INTE_DSI_DMA_LSB 1 ++#define RPI_MIPICFG_INTE_DSI_DMA_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTE_CSI_DMA ++// Description : None ++#define RPI_MIPICFG_INTE_CSI_DMA_RESET 0x0 ++#define RPI_MIPICFG_INTE_CSI_DMA_BITS 0x00000001 ++#define RPI_MIPICFG_INTE_CSI_DMA_MSB 0 ++#define RPI_MIPICFG_INTE_CSI_DMA_LSB 0 ++#define RPI_MIPICFG_INTE_CSI_DMA_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_INTF ++// JTAG access : synchronous ++// Description : Interrupt Force ++#define RPI_MIPICFG_INTF_OFFSET 0x00000030 ++#define RPI_MIPICFG_INTF_BITS 0x0000000f ++#define RPI_MIPICFG_INTF_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTF_DSI_HOST ++// Description : None ++#define RPI_MIPICFG_INTF_DSI_HOST_RESET 0x0 ++#define RPI_MIPICFG_INTF_DSI_HOST_BITS 0x00000008 ++#define RPI_MIPICFG_INTF_DSI_HOST_MSB 3 ++#define RPI_MIPICFG_INTF_DSI_HOST_LSB 3 ++#define RPI_MIPICFG_INTF_DSI_HOST_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTF_CSI_HOST ++// Description : None ++#define RPI_MIPICFG_INTF_CSI_HOST_RESET 0x0 ++#define RPI_MIPICFG_INTF_CSI_HOST_BITS 0x00000004 ++#define RPI_MIPICFG_INTF_CSI_HOST_MSB 2 ++#define RPI_MIPICFG_INTF_CSI_HOST_LSB 2 ++#define RPI_MIPICFG_INTF_CSI_HOST_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTF_DSI_DMA ++// Description : None ++#define RPI_MIPICFG_INTF_DSI_DMA_RESET 0x0 ++#define RPI_MIPICFG_INTF_DSI_DMA_BITS 0x00000002 ++#define RPI_MIPICFG_INTF_DSI_DMA_MSB 1 ++#define RPI_MIPICFG_INTF_DSI_DMA_LSB 1 ++#define RPI_MIPICFG_INTF_DSI_DMA_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTF_CSI_DMA ++// Description : None ++#define RPI_MIPICFG_INTF_CSI_DMA_RESET 0x0 ++#define RPI_MIPICFG_INTF_CSI_DMA_BITS 0x00000001 ++#define RPI_MIPICFG_INTF_CSI_DMA_MSB 0 ++#define RPI_MIPICFG_INTF_CSI_DMA_LSB 0 ++#define RPI_MIPICFG_INTF_CSI_DMA_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_INTS ++// JTAG access : synchronous ++// Description : Interrupt status after masking & forcing ++#define RPI_MIPICFG_INTS_OFFSET 0x00000034 ++#define RPI_MIPICFG_INTS_BITS 0x0000000f ++#define RPI_MIPICFG_INTS_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTS_DSI_HOST ++// Description : None ++#define RPI_MIPICFG_INTS_DSI_HOST_RESET 0x0 ++#define RPI_MIPICFG_INTS_DSI_HOST_BITS 0x00000008 ++#define RPI_MIPICFG_INTS_DSI_HOST_MSB 3 ++#define RPI_MIPICFG_INTS_DSI_HOST_LSB 3 ++#define RPI_MIPICFG_INTS_DSI_HOST_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTS_CSI_HOST ++// Description : None ++#define RPI_MIPICFG_INTS_CSI_HOST_RESET 0x0 ++#define RPI_MIPICFG_INTS_CSI_HOST_BITS 0x00000004 ++#define RPI_MIPICFG_INTS_CSI_HOST_MSB 2 ++#define RPI_MIPICFG_INTS_CSI_HOST_LSB 2 ++#define RPI_MIPICFG_INTS_CSI_HOST_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTS_DSI_DMA ++// Description : None ++#define RPI_MIPICFG_INTS_DSI_DMA_RESET 0x0 ++#define RPI_MIPICFG_INTS_DSI_DMA_BITS 0x00000002 ++#define RPI_MIPICFG_INTS_DSI_DMA_MSB 1 ++#define RPI_MIPICFG_INTS_DSI_DMA_LSB 1 ++#define RPI_MIPICFG_INTS_DSI_DMA_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTS_CSI_DMA ++// Description : None ++#define RPI_MIPICFG_INTS_CSI_DMA_RESET 0x0 ++#define RPI_MIPICFG_INTS_CSI_DMA_BITS 0x00000001 ++#define RPI_MIPICFG_INTS_CSI_DMA_MSB 0 ++#define RPI_MIPICFG_INTS_CSI_DMA_LSB 0 ++#define RPI_MIPICFG_INTS_CSI_DMA_ACCESS "RO" ++// ================================================================================ ++// Register : RPI_MIPICFG_BLOCK_ID ++// JTAG access : asynchronous ++// Description : Block Identifier ++#define RPI_MIPICFG_BLOCK_ID_OFFSET 0x00000038 ++#define RPI_MIPICFG_BLOCK_ID_BITS 0xffffffff ++#define RPI_MIPICFG_BLOCK_ID_RESET 0x4d495049 ++#define RPI_MIPICFG_BLOCK_ID_MSB 31 ++#define RPI_MIPICFG_BLOCK_ID_LSB 0 ++#define RPI_MIPICFG_BLOCK_ID_ACCESS "RO" ++// ================================================================================ ++// Register : RPI_MIPICFG_INSTANCE_ID ++// JTAG access : asynchronous ++// Description : Block Instance Identifier ++#define RPI_MIPICFG_INSTANCE_ID_OFFSET 0x0000003c ++#define RPI_MIPICFG_INSTANCE_ID_BITS 0x0000000f ++#define RPI_MIPICFG_INSTANCE_ID_RESET 0x00000000 ++#define RPI_MIPICFG_INSTANCE_ID_MSB 3 ++#define RPI_MIPICFG_INSTANCE_ID_LSB 0 ++#define RPI_MIPICFG_INSTANCE_ID_ACCESS "RO" ++// ================================================================================ ++// Register : RPI_MIPICFG_RSTSEQ_AUTO ++// JTAG access : synchronous ++// Description : None ++#define RPI_MIPICFG_RSTSEQ_AUTO_OFFSET 0x00000040 ++#define RPI_MIPICFG_RSTSEQ_AUTO_BITS 0x00000007 ++#define RPI_MIPICFG_RSTSEQ_AUTO_RESET 0x00000007 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_AUTO_CSI ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_RESET 0x1 ++#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_BITS 0x00000004 ++#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_MSB 2 ++#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_LSB 2 ++#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_AUTO_DPI ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_RESET 0x1 ++#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_BITS 0x00000002 ++#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_MSB 1 ++#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_LSB 1 ++#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_RESET 0x1 ++#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_BITS 0x00000001 ++#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_MSB 0 ++#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_LSB 0 ++#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_RSTSEQ_PARALLEL ++// JTAG access : synchronous ++// Description : None ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_OFFSET 0x00000044 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_BITS 0x00000007 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_RESET 0x00000006 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_PARALLEL_CSI ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_RESET 0x1 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_BITS 0x00000004 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_MSB 2 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_LSB 2 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_PARALLEL_DPI ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_RESET 0x1 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_BITS 0x00000002 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_MSB 1 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_LSB 1 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_BITS 0x00000001 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_MSB 0 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_LSB 0 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_ACCESS "RO" ++// ================================================================================ ++// Register : RPI_MIPICFG_RSTSEQ_CTRL ++// JTAG access : synchronous ++// Description : None ++#define RPI_MIPICFG_RSTSEQ_CTRL_OFFSET 0x00000048 ++#define RPI_MIPICFG_RSTSEQ_CTRL_BITS 0x00000007 ++#define RPI_MIPICFG_RSTSEQ_CTRL_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_CTRL_CSI ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_BITS 0x00000004 ++#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_MSB 2 ++#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_LSB 2 ++#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_CTRL_DPI ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_BITS 0x00000002 ++#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_MSB 1 ++#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_LSB 1 ++#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_BITS 0x00000001 ++#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_MSB 0 ++#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_LSB 0 ++#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_RSTSEQ_TRIG ++// JTAG access : synchronous ++// Description : None ++#define RPI_MIPICFG_RSTSEQ_TRIG_OFFSET 0x0000004c ++#define RPI_MIPICFG_RSTSEQ_TRIG_BITS 0x00000007 ++#define RPI_MIPICFG_RSTSEQ_TRIG_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_TRIG_CSI ++// Description : Pulses the reset output ++#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_BITS 0x00000004 ++#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_MSB 2 ++#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_LSB 2 ++#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_ACCESS "SC" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_TRIG_DPI ++// Description : Pulses the reset output ++#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_BITS 0x00000002 ++#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_MSB 1 ++#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_LSB 1 ++#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_ACCESS "SC" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER ++// Description : Pulses the reset output ++#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_BITS 0x00000001 ++#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_MSB 0 ++#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_LSB 0 ++#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_ACCESS "SC" ++// ================================================================================ ++// Register : RPI_MIPICFG_RSTSEQ_DONE ++// JTAG access : synchronous ++// Description : None ++#define RPI_MIPICFG_RSTSEQ_DONE_OFFSET 0x00000050 ++#define RPI_MIPICFG_RSTSEQ_DONE_BITS 0x00000007 ++#define RPI_MIPICFG_RSTSEQ_DONE_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_DONE_CSI ++// Description : Indicates the current state of the reset ++#define RPI_MIPICFG_RSTSEQ_DONE_CSI_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_DONE_CSI_BITS 0x00000004 ++#define RPI_MIPICFG_RSTSEQ_DONE_CSI_MSB 2 ++#define RPI_MIPICFG_RSTSEQ_DONE_CSI_LSB 2 ++#define RPI_MIPICFG_RSTSEQ_DONE_CSI_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_DONE_DPI ++// Description : Indicates the current state of the reset ++#define RPI_MIPICFG_RSTSEQ_DONE_DPI_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_DONE_DPI_BITS 0x00000002 ++#define RPI_MIPICFG_RSTSEQ_DONE_DPI_MSB 1 ++#define RPI_MIPICFG_RSTSEQ_DONE_DPI_LSB 1 ++#define RPI_MIPICFG_RSTSEQ_DONE_DPI_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER ++// Description : Indicates the current state of the reset ++#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_BITS 0x00000001 ++#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_MSB 0 ++#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_LSB 0 ++#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_ACCESS "RO" ++// ================================================================================ ++// Register : RPI_MIPICFG_DFTSS ++// JTAG access : asynchronous ++// Description : None ++#define RPI_MIPICFG_DFTSS_OFFSET 0x00000054 ++#define RPI_MIPICFG_DFTSS_BITS 0x0000001f ++#define RPI_MIPICFG_DFTSS_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DFTSS_JTAG_COPY ++// Description : None ++#define RPI_MIPICFG_DFTSS_JTAG_COPY_RESET 0x0 ++#define RPI_MIPICFG_DFTSS_JTAG_COPY_BITS 0x00000010 ++#define RPI_MIPICFG_DFTSS_JTAG_COPY_MSB 4 ++#define RPI_MIPICFG_DFTSS_JTAG_COPY_LSB 4 ++#define RPI_MIPICFG_DFTSS_JTAG_COPY_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY ++// Description : None ++#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_RESET 0x0 ++#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_BITS 0x00000008 ++#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_MSB 3 ++#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_LSB 3 ++#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS ++// Description : None ++#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_RESET 0x0 ++#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_BITS 0x00000004 ++#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_MSB 2 ++#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_LSB 2 ++#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DFTSS_BYPASS_INSYNCS ++// Description : None ++#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_RESET 0x0 ++#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_BITS 0x00000002 ++#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_MSB 1 ++#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_LSB 1 ++#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS ++// Description : None ++#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_RESET 0x0 ++#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_BITS 0x00000001 ++#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_MSB 0 ++#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_LSB 0 ++#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_ACCESS "RW" ++ ++#define CFG_WRITE(reg, val) writel((val), dsi->hw_baseRP1DSI_HW_BLOCK_CFG + (reg ## _OFFSET)) ++#define CFG_READ(reg) readl(dsi->hw_baseRP1DSI_HW_BLOCK_CFG + (reg ## _OFFSET)) ++ ++/* ------------------------------- DPHY setup stuff ------------------------ */ ++ ++static void dphy_transaction(struct rp1_dsi *dsi, uint8_t test_code, uint8_t test_data) ++{ ++ /* ++ * See pg 101 of mipi dphy bidir databook ++ * Assume we start with testclk high. ++ * Each APB write takes at least 10ns and we ignore TESTDOUT ++ * so there is no need for extra delays between the transitions. ++ */ ++ u32 tmp; ++ ++ DSI_WRITE(DSI_PHY_TST_CTRL1, test_code | DPHY_CTRL1_PHY_TESTEN_BITS); ++ DSI_WRITE(DSI_PHY_TST_CTRL0, 0); ++ tmp = (DSI_READ(DSI_PHY_TST_CTRL1) >> DPHY_CTRL1_PHY_TESTDOUT_LSB) & 0xFF; ++ DSI_WRITE(DSI_PHY_TST_CTRL1, test_data); ++ DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS); ++} ++ ++static uint8_t dphy_get_div(u32 refclk_khz, u32 vco_freq_khz, u32 *ptr_m, u32 *ptr_n) ++{ ++ /* ++ * See pg 77-78 of dphy databook ++ * fvco = m/n * refclk ++ * with the limit ++ * 40MHz >= fREFCLK / N >= 5MHz ++ * M (multiplier) must be an even number between 2 and 300 ++ * N (input divider) must be an integer between 1 and 100 ++ * ++ * In practice, given a 50MHz reference clock, it can produce any ++ * multiple of 10MHz, 11.1111MHz, 12.5MHz, 14.286MHz or 16.667MHz ++ * with < 1% error for all frequencies above 495MHz. ++ */ ++ ++ static const u32 REF_DIVN_MAX = 40000u; ++ static const u32 REF_DIVN_MIN = 5000u; ++ u32 best_n, best_m, best_err = 0x7fffffff; ++ unsigned int n; ++ ++ for (n = 1 + refclk_khz / REF_DIVN_MAX; n * REF_DIVN_MIN <= refclk_khz && n < 100; ++n) { ++ u32 half_m = (n * vco_freq_khz + refclk_khz) / (2 * refclk_khz); ++ ++ if (half_m < 150) { ++ u32 f = (2 * half_m * refclk_khz) / n; ++ u32 err = (f > vco_freq_khz) ? f - vco_freq_khz : vco_freq_khz - f; ++ ++ if (err < best_err) { ++ best_n = n; ++ best_m = 2 * half_m; ++ best_err = err; ++ if (err == 0) ++ break; ++ } ++ } ++ } ++ ++ if (64 * best_err < vco_freq_khz) { /* tolerate small error */ ++ *ptr_n = best_n; ++ *ptr_m = best_m; ++ return 1; ++ } ++ return 0; ++} ++ ++struct hsfreq_range { ++ u16 mhz_max; ++ u8 hsfreqrange; ++ u8 clk_lp2hs; ++ u8 clk_hs2lp; ++ u8 data_lp2hs; /* excluding clk lane entry */ ++ u8 data_hs2lp; ++}; ++ ++/* See Table A-3 on page 258 of dphy databook */ ++static const struct hsfreq_range hsfreq_table = { ++ { 89, 0b000000, 32, 20, 26, 13 }, ++ { 99, 0b010000, 35, 23, 28, 14 }, ++ { 109, 0b100000, 32, 22, 26, 13 }, ++ { 129, 0b000001, 31, 20, 27, 13 }, ++ { 139, 0b010001, 33, 22, 26, 14 }, ++ { 149, 0b100001, 33, 21, 26, 14 }, ++ { 169, 0b000010, 32, 20, 27, 13 }, ++ { 179, 0b010010, 36, 23, 30, 15 }, ++ { 199, 0b100010, 40, 22, 33, 15 }, ++ { 219, 0b000011, 40, 22, 33, 15 }, ++ { 239, 0b010011, 44, 24, 36, 16 }, ++ { 249, 0b100011, 48, 24, 38, 17 }, ++ { 269, 0b000100, 48, 24, 38, 17 }, ++ { 299, 0b010100, 50, 27, 41, 18 }, ++ { 329, 0b000101, 56, 28, 45, 18 }, ++ { 359, 0b010101, 59, 28, 48, 19 }, ++ { 399, 0b100101, 61, 30, 50, 20 }, ++ { 449, 0b000110, 67, 31, 55, 21 }, ++ { 499, 0b010110, 73, 31, 59, 22 }, ++ { 549, 0b000111, 79, 36, 63, 24 }, ++ { 599, 0b010111, 83, 37, 68, 25 }, ++ { 649, 0b001000, 90, 38, 73, 27 }, ++ { 699, 0b011000, 95, 40, 77, 28 }, ++ { 749, 0b001001, 102, 40, 84, 28 }, ++ { 799, 0b011001, 106, 42, 87, 30 }, ++ { 849, 0b101001, 113, 44, 93, 31 }, ++ { 899, 0b111001, 118, 47, 98, 32 }, ++ { 949, 0b001010, 124, 47, 102, 34 }, ++ { 999, 0b011010, 130, 49, 107, 35 }, ++ { 1049, 0b101010, 135, 51, 111, 37 }, ++ { 1099, 0b111010, 139, 51, 114, 38 }, ++ { 1149, 0b001011, 146, 54, 120, 40 }, ++ { 1199, 0b011011, 153, 57, 125, 41 }, ++ { 1249, 0b101011, 158, 58, 130, 42 }, ++ { 1299, 0b111011, 163, 58, 135, 44 }, ++ { 1349, 0b001100, 168, 60, 140, 45 }, ++ { 1399, 0b011100, 172, 64, 144, 47 }, ++ { 1449, 0b101100, 176, 65, 148, 48 }, ++ { 1500, 0b111100, 181, 66, 153, 50 }, ++}; ++ ++static void dphy_set_hsfreqrange(struct rp1_dsi *dsi, u32 freq_mhz) ++{ ++ unsigned int i; ++ ++ if (freq_mhz < 80 || freq_mhz > 1500) ++ drm_err(dsi->drm, "DPHY: Frequency %u MHz out of range\n", ++ freq_mhz); ++ ++ for (i = 0; i < ARRAY_SIZE(hsfreq_table) - 1; i++) { ++ if (freq_mhz <= hsfreq_tablei.mhz_max) ++ break; ++ } ++ ++ dsi->hsfreq_index = i; ++ dphy_transaction(dsi, DPHY_HS_RX_CTRL_LANE0_OFFSET, ++ hsfreq_tablei.hsfreqrange << 1); ++} ++ ++static void dphy_configure_pll(struct rp1_dsi *dsi, u32 refclk_khz, u32 vco_freq_khz) ++{ ++ u32 m = 0; ++ u32 n = 0; ++ ++ if (dphy_get_div(refclk_khz, vco_freq_khz, &m, &n)) { ++ dphy_set_hsfreqrange(dsi, vco_freq_khz / 1000); ++ /* Program m,n from registers */ ++ dphy_transaction(dsi, DPHY_PLL_DIV_CTRL_OFFSET, 0x30); ++ /* N (program N-1) */ ++ dphy_transaction(dsi, DPHY_PLL_INPUT_DIV_OFFSET, n - 1); ++ /* M8:5 ?? */ ++ dphy_transaction(dsi, DPHY_PLL_LOOP_DIV_OFFSET, 0x80 | ((m - 1) >> 5)); ++ /* M4:0 (program M-1) */ ++ dphy_transaction(dsi, DPHY_PLL_LOOP_DIV_OFFSET, ((m - 1) & 0x1F)); ++ drm_dbg_driver(dsi->drm, ++ "DPHY: vco freq want %dkHz got %dkHz = %d * (%dkHz / %d), hsfreqrange = 0x%02x\r\n", ++ vco_freq_khz, refclk_khz * m / n, m, refclk_khz, ++ n, hsfreq_tabledsi->hsfreq_index.hsfreqrange); ++ } else { ++ drm_info(dsi->drm, ++ "rp1dsi: Error configuring DPHY PLL! %dkHz = %d * (%dkHz / %d)\r\n", ++ vco_freq_khz, m, refclk_khz, n); ++ } ++} ++ ++static void dphy_init_khz(struct rp1_dsi *dsi, u32 ref_freq, u32 vco_freq) ++{ ++ /* Reset the PHY */ ++ DSI_WRITE(DSI_PHYRSTZ, 0); ++ DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS); ++ DSI_WRITE(DSI_PHY_TST_CTRL1, 0); ++ DSI_WRITE(DSI_PHY_TST_CTRL0, (DPHY_CTRL0_PHY_TESTCLK_BITS | DPHY_CTRL0_PHY_TESTCLR_BITS)); ++ udelay(1); ++ DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS); ++ udelay(1); ++ /* Since we are in DSI (not CSI2) mode here, start the PLL */ ++ dphy_configure_pll(dsi, ref_freq, vco_freq); ++ udelay(1); ++ /* Unreset */ ++ DSI_WRITE(DSI_PHYRSTZ, DSI_PHYRSTZ_SHUTDOWNZ_BITS); ++ udelay(1); ++ DSI_WRITE(DSI_PHYRSTZ, (DSI_PHYRSTZ_SHUTDOWNZ_BITS | DSI_PHYRSTZ_RSTZ_BITS)); ++ udelay(1); /* so we can see PLL coming up? */ ++} ++ ++void rp1dsi_mipicfg_setup(struct rp1_dsi *dsi) ++{ ++ /* Select DSI rather than CSI-2 */ ++ CFG_WRITE(RPI_MIPICFG_CFG, 0); ++ /* Enable DSIDMA interrupt only */ ++ CFG_WRITE(RPI_MIPICFG_INTE, RPI_MIPICFG_INTE_DSI_DMA_BITS); ++} ++ ++static unsigned long rp1dsi_refclk_freq(struct rp1_dsi *dsi) ++{ ++ unsigned long u; ++ ++ u = (dsi->clocksRP1DSI_CLOCK_REF) ? clk_get_rate(dsi->clocksRP1DSI_CLOCK_REF) : 0; ++ if (u < 1 || u >= (1ul << 30)) ++ u = 50000000ul; /* default XOSC frequency */ ++ return u; ++} ++ ++static void rp1dsi_dpiclk_start(struct rp1_dsi *dsi, unsigned int bpp, unsigned int lanes) ++{ ++ unsigned long u; ++ ++ if (dsi->clocksRP1DSI_CLOCK_DPI) { ++ u = (dsi->clocksRP1DSI_CLOCK_BYTE) ? ++ clk_get_rate(dsi->clocksRP1DSI_CLOCK_BYTE) : 0; ++ drm_info(dsi->drm, ++ "rp1dsi: Nominal byte clock %lu; scale by %u/%u", ++ u, 4 * lanes, (bpp >> 1)); ++ if (u < 1 || u >= (1ul << 28)) ++ u = 72000000ul; /* default DUMMY frequency for byteclock */ ++ ++ clk_set_parent(dsi->clocksRP1DSI_CLOCK_DPI, dsi->clocksRP1DSI_CLOCK_BYTE); ++ clk_set_rate(dsi->clocksRP1DSI_CLOCK_DPI, (4 * lanes * u) / (bpp >> 1)); ++ clk_prepare_enable(dsi->clocksRP1DSI_CLOCK_DPI); ++ } ++} ++ ++static void rp1dsi_dpiclk_stop(struct rp1_dsi *dsi) ++{ ++ if (dsi->clocksRP1DSI_CLOCK_DPI) ++ clk_disable_unprepare(dsi->clocksRP1DSI_CLOCK_DPI); ++} ++ ++/* Choose the internal on-the-bus DPI format, and DSI packing flag. */ ++static u32 get_colorcode(enum mipi_dsi_pixel_format fmt) ++{ ++ switch (fmt) { ++ case MIPI_DSI_FMT_RGB666: ++ return 0x104; ++ case MIPI_DSI_FMT_RGB666_PACKED: ++ return 0x003; ++ case MIPI_DSI_FMT_RGB565: ++ return 0x000; ++ case MIPI_DSI_FMT_RGB888: ++ return 0x005; ++ } ++ ++ /* This should be impossible as the format is validated in ++ * rp1dsi_host_attach ++ */ ++ WARN_ONCE(1, "Invalid colour format configured for DSI"); ++ return 0x005; ++} ++ ++void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode) ++{ ++ u32 timeout, mask, vid_mode_cfg; ++ u32 freq_khz; ++ unsigned int bpp = mipi_dsi_pixel_format_to_bpp(dsi->display_format); ++ ++ DSI_WRITE(DSI_PHY_IF_CFG, dsi->lanes - 1); ++ DSI_WRITE(DSI_DPI_CFG_POL, 0); ++ DSI_WRITE(DSI_GEN_VCID, dsi->vc); ++ DSI_WRITE(DSI_DPI_COLOR_CODING, get_colorcode(dsi->display_format)); ++ /* a conservative guess (LP escape is slow!) */ ++ DSI_WRITE(DSI_DPI_LP_CMD_TIM, 0x00100000); ++ ++ /* Drop to LP where possible */ ++ vid_mode_cfg = 0xbf00; ++ if (!(dsi->display_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) ++ vid_mode_cfg |= 0x01; ++ if (dsi->display_flags & MIPI_DSI_MODE_VIDEO_BURST) ++ vid_mode_cfg |= 0x02; ++ DSI_WRITE(DSI_VID_MODE_CFG, vid_mode_cfg); ++ ++ /* Use LP Escape Data signalling for all commands */ ++ DSI_WRITE(DSI_CMD_MODE_CFG, 0x10F7F00); ++ /* Select Command Mode */ ++ DSI_WRITE(DSI_MODE_CFG, 1); ++ /* XXX magic number */ ++ DSI_WRITE(DSI_TO_CNT_CFG, 0x02000200); ++ /* XXX magic number */ ++ DSI_WRITE(DSI_BTA_TO_CNT, 0x800); ++ ++ DSI_WRITE(DSI_VID_PKT_SIZE, mode->hdisplay); ++ DSI_WRITE(DSI_VID_NUM_CHUNKS, 0); ++ DSI_WRITE(DSI_VID_NULL_SIZE, 0); ++ ++ /* Note, unlike Argon firmware, here we DON'T consider sync to be concurrent with porch */ ++ DSI_WRITE(DSI_VID_HSA_TIME, ++ (bpp * (mode->hsync_end - mode->hsync_start)) / (8 * dsi->lanes)); ++ DSI_WRITE(DSI_VID_HBP_TIME, ++ (bpp * (mode->htotal - mode->hsync_end)) / (8 * dsi->lanes)); ++ DSI_WRITE(DSI_VID_HLINE_TIME, (bpp * mode->htotal) / (8 * dsi->lanes)); ++ DSI_WRITE(DSI_VID_VSA_LINES, (mode->vsync_end - mode->vsync_start)); ++ DSI_WRITE(DSI_VID_VBP_LINES, (mode->vtotal - mode->vsync_end)); ++ DSI_WRITE(DSI_VID_VFP_LINES, (mode->vsync_start - mode->vdisplay)); ++ DSI_WRITE(DSI_VID_VACTIVE_LINES, mode->vdisplay); ++ ++ freq_khz = (bpp * mode->clock) / dsi->lanes; ++ ++ dphy_init_khz(dsi, rp1dsi_refclk_freq(dsi) / 1000, freq_khz); ++ ++ DSI_WRITE(DSI_PHY_TMR_LPCLK_CFG, ++ (hsfreq_tabledsi->hsfreq_index.clk_lp2hs << DSI_PHY_TMR_LP2HS_LSB) | ++ (hsfreq_tabledsi->hsfreq_index.clk_hs2lp << DSI_PHY_TMR_HS2LP_LSB)); ++ DSI_WRITE(DSI_PHY_TMR_CFG, ++ (hsfreq_tabledsi->hsfreq_index.data_lp2hs << DSI_PHY_TMR_LP2HS_LSB) | ++ (hsfreq_tabledsi->hsfreq_index.data_hs2lp << DSI_PHY_TMR_HS2LP_LSB)); ++ ++ DSI_WRITE(DSI_CLKMGR_CFG, 0x00000505); ++ ++ /* Wait for PLL lock */ ++ for (timeout = (1 << 14); timeout != 0; --timeout) { ++ usleep_range(10, 50); ++ if (DSI_READ(DSI_PHY_STATUS) & (1 << 0)) ++ break; ++ } ++ if (timeout == 0) ++ drm_err(dsi->drm, "RP1DSI: Time out waiting for PLL\n"); ++ ++ DSI_WRITE(DSI_LPCLK_CTRL, 0x1); /* configure the requesthsclk */ ++ DSI_WRITE(DSI_PHY_TST_CTRL0, 0x2); ++ DSI_WRITE(DSI_PCKHDL_CFG, 1 << 2); /* allow bus turnaround */ ++ DSI_WRITE(DSI_PWR_UP, 0x1); /* power up */ ++ ++ /* Now it should be safe to start the external DPI clock divider */ ++ rp1dsi_dpiclk_start(dsi, bpp, dsi->lanes); ++ ++ /* Wait for all lane(s) to be in Stopstate */ ++ mask = (1 << 4); ++ if (dsi->lanes >= 2) ++ mask |= (1 << 7); ++ if (dsi->lanes >= 3) ++ mask |= (1 << 9); ++ if (dsi->lanes >= 4) ++ mask |= (1 << 11); ++ for (timeout = (1 << 10); timeout != 0; --timeout) { ++ usleep_range(10, 50); ++ if ((DSI_READ(DSI_PHY_STATUS) & mask) == mask) ++ break; ++ } ++ if (timeout == 0) ++ drm_err(dsi->drm, "RP1DSI: Time out waiting for lanes (%x %x)\n", ++ mask, DSI_READ(DSI_PHY_STATUS)); ++} ++ ++void rp1dsi_dsi_send(struct rp1_dsi *dsi, u32 hdr, int len, const u8 *buf) ++{ ++ u32 val; ++ ++ /* Wait for both FIFOs empty */ ++ for (val = 256; val > 0; --val) { ++ if ((DSI_READ(DSI_CMD_PKT_STATUS) & 0xF) == 0x5) ++ break; ++ usleep_range(100, 150); ++ } ++ ++ /* Write payload (in 32-bit words) and header */ ++ for (; len > 0; len -= 4) { ++ val = *buf++; ++ if (len > 1) ++ val |= (*buf++) << 8; ++ if (len > 2) ++ val |= (*buf++) << 16; ++ if (len > 3) ++ val |= (*buf++) << 24; ++ DSI_WRITE(DSI_GEN_PLD_DATA, val); ++ } ++ DSI_WRITE(DSI_GEN_HDR, hdr); ++ ++ /* Wait for both FIFOs empty */ ++ for (val = 256; val > 0; --val) { ++ if ((DSI_READ(DSI_CMD_PKT_STATUS) & 0xF) == 0x5) ++ break; ++ usleep_range(100, 150); ++ } ++} ++ ++int rp1dsi_dsi_recv(struct rp1_dsi *dsi, int len, u8 *buf) ++{ ++ int i, j; ++ u32 val; ++ ++ /* Wait until not busy and FIFO not empty */ ++ for (i = 1024; i > 0; --i) { ++ val = DSI_READ(DSI_CMD_PKT_STATUS); ++ if ((val & ((1 << 6) | (1 << 4))) == 0) ++ break; ++ usleep_range(100, 150); ++ } ++ if (i == 0) ++ return -EIO; ++ ++ for (i = 0; i < len; i += 4) { ++ /* Read fifo must not be empty before all bytes are read */ ++ if (DSI_READ(DSI_CMD_PKT_STATUS) & (1 << 4)) ++ break; ++ ++ val = DSI_READ(DSI_GEN_PLD_DATA); ++ for (j = 0; j < 4 && j + i < len; j++) ++ *buf++ = val >> (8 * j); ++ } ++ ++ return (i >= len) ? len : (i > 0) ? i : -EIO; ++} ++ ++void rp1dsi_dsi_stop(struct rp1_dsi *dsi) ++{ ++ DSI_WRITE(DSI_MODE_CFG, 1); /* Return to Command Mode */ ++ DSI_WRITE(DSI_LPCLK_CTRL, 2); /* Stop the HS clock */ ++ DSI_WRITE(DSI_PWR_UP, 0x0); /* Power down host controller */ ++ DSI_WRITE(DSI_PHYRSTZ, 0); /* PHY into reset. */ ++ rp1dsi_dpiclk_stop(dsi); ++} ++ ++void rp1dsi_dsi_set_cmdmode(struct rp1_dsi *dsi, int mode) ++{ ++ DSI_WRITE(DSI_MODE_CFG, mode); ++} +diff --git a/drivers/gpu/drm/rp1/rp1-vec/Kconfig b/drivers/gpu/drm/rp1/rp1-vec/Kconfig +new file mode 100644 +index 000000000000..f646c01af5ae +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-vec/Kconfig +@@ -0,0 +1,11 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config DRM_RP1_VEC ++ tristate "DRM Support for RP1 VEC" ++ depends on DRM && MFD_RP1 ++ select DRM_GEM_DMA_HELPER ++ select DRM_KMS_HELPER ++ select DRM_VRAM_HELPER ++ select DRM_TTM ++ select DRM_TTM_HELPER ++ help ++ Choose this option to enable Video Out on RP1 +diff --git a/drivers/gpu/drm/rp1/rp1-vec/Makefile b/drivers/gpu/drm/rp1/rp1-vec/Makefile +new file mode 100644 +index 000000000000..7e941cad342e +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-vec/Makefile +@@ -0,0 +1,5 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++ ++drm-rp1-vec-y := rp1_vec.o rp1_vec_hw.o rp1_vec_cfg.o ++ ++obj-$(CONFIG_DRM_RP1_VEC) += drm-rp1-vec.o +diff --git a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c +new file mode 100644 +index 000000000000..34a6033e3430 +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c +@@ -0,0 +1,506 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for VEC output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/slab.h> ++#include <linux/mm.h> ++#include <linux/fb.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/ioport.h> ++#include <linux/list.h> ++#include <linux/platform_device.h> ++#include <linux/clk.h> ++#include <linux/console.h> ++#include <linux/debugfs.h> ++#include <linux/uaccess.h> ++#include <linux/io.h> ++#include <linux/dma-mapping.h> ++#include <linux/cred.h> ++#include <drm/drm_drv.h> ++#include <drm/drm_mm.h> ++#include <drm/drm_fourcc.h> ++#include <drm/drm_atomic_helper.h> ++#include <drm/drm_managed.h> ++#include <drm/drm_crtc.h> ++#include <drm/drm_crtc_helper.h> ++#include <drm/drm_encoder.h> ++#include <drm/drm_fb_helper.h> ++#include <drm/drm_fbdev_generic.h> ++#include <drm/drm_framebuffer.h> ++#include <drm/drm_gem.h> ++#include <drm/drm_gem_atomic_helper.h> ++#include <drm/drm_gem_dma_helper.h> ++#include <drm/drm_gem_framebuffer_helper.h> ++#include <drm/drm_simple_kms_helper.h> ++#include <drm/drm_probe_helper.h> ++#include <drm/drm_modeset_helper_vtables.h> ++#include <drm/drm_vblank.h> ++#include <drm/drm_of.h> ++ ++#include "rp1_vec.h" ++ ++static void rp1vec_pipe_update(struct drm_simple_display_pipe *pipe, ++ struct drm_plane_state *old_state) ++{ ++ struct drm_pending_vblank_event *event; ++ unsigned long flags; ++ struct drm_framebuffer *fb = pipe->plane.state->fb; ++ struct rp1_vec *vec = pipe->crtc.dev->dev_private; ++ struct drm_gem_object *gem = fb ? drm_gem_fb_get_obj(fb, 0) : NULL; ++ struct drm_gem_dma_object *dma_obj = gem ? to_drm_gem_dma_obj(gem) : NULL; ++ bool can_update = fb && dma_obj && vec && vec->pipe_enabled; ++ ++ /* (Re-)start VEC where required; and update FB address */ ++ if (can_update) { ++ if (!vec->vec_running || fb->format->format != vec->cur_fmt) { ++ if (vec->vec_running && fb->format->format != vec->cur_fmt) { ++ rp1vec_hw_stop(vec); ++ vec->vec_running = false; ++ } ++ if (!vec->vec_running) { ++ rp1vec_hw_setup(vec, ++ fb->format->format, ++ &pipe->crtc.state->mode, ++ vec->connector.state->tv.mode); ++ vec->vec_running = true; ++ } ++ vec->cur_fmt = fb->format->format; ++ drm_crtc_vblank_on(&pipe->crtc); ++ } ++ rp1vec_hw_update(vec, dma_obj->dma_addr, fb->offsets0, fb->pitches0); ++ } ++ ++ /* Check if VBLANK callback needs to be armed (or sent immediately in some error cases). ++ * Note there is a tiny probability of a race between rp1vec_dma_update() and IRQ; ++ * ordering it this way around is safe, but theoretically might delay an extra frame. ++ */ ++ spin_lock_irqsave(&pipe->crtc.dev->event_lock, flags); ++ event = pipe->crtc.state->event; ++ if (event) { ++ pipe->crtc.state->event = NULL; ++ if (can_update && drm_crtc_vblank_get(&pipe->crtc) == 0) ++ drm_crtc_arm_vblank_event(&pipe->crtc, event); ++ else ++ drm_crtc_send_vblank_event(&pipe->crtc, event); ++ } ++ spin_unlock_irqrestore(&pipe->crtc.dev->event_lock, flags); ++} ++ ++static void rp1vec_pipe_enable(struct drm_simple_display_pipe *pipe, ++ struct drm_crtc_state *crtc_state, ++ struct drm_plane_state *plane_state) ++{ ++ struct rp1_vec *vec = pipe->crtc.dev->dev_private; ++ ++ dev_info(&vec->pdev->dev, __func__); ++ vec->pipe_enabled = true; ++ vec->cur_fmt = 0xdeadbeef; ++ rp1vec_vidout_setup(vec); ++ rp1vec_pipe_update(pipe, 0); ++} ++ ++static void rp1vec_pipe_disable(struct drm_simple_display_pipe *pipe) ++{ ++ struct rp1_vec *vec = pipe->crtc.dev->dev_private; ++ ++ dev_info(&vec->pdev->dev, __func__); ++ drm_crtc_vblank_off(&pipe->crtc); ++ if (vec) { ++ if (vec->vec_running) { ++ rp1vec_hw_stop(vec); ++ vec->vec_running = false; ++ } ++ vec->pipe_enabled = false; ++ } ++} ++ ++static int rp1vec_pipe_enable_vblank(struct drm_simple_display_pipe *pipe) ++{ ++ if (pipe && pipe->crtc.dev) { ++ struct rp1_vec *vec = pipe->crtc.dev->dev_private; ++ ++ if (vec) ++ rp1vec_hw_vblank_ctrl(vec, 1); ++ } ++ return 0; ++} ++ ++static void rp1vec_pipe_disable_vblank(struct drm_simple_display_pipe *pipe) ++{ ++ if (pipe && pipe->crtc.dev) { ++ struct rp1_vec *vec = pipe->crtc.dev->dev_private; ++ ++ if (vec) ++ rp1vec_hw_vblank_ctrl(vec, 0); ++ } ++} ++ ++static const struct drm_simple_display_pipe_funcs rp1vec_pipe_funcs = { ++ .enable = rp1vec_pipe_enable, ++ .update = rp1vec_pipe_update, ++ .disable = rp1vec_pipe_disable, ++ .enable_vblank = rp1vec_pipe_enable_vblank, ++ .disable_vblank = rp1vec_pipe_disable_vblank, ++}; ++ ++static void rp1vec_connector_destroy(struct drm_connector *connector) ++{ ++ drm_connector_unregister(connector); ++ drm_connector_cleanup(connector); ++} ++ ++static const struct drm_display_mode rp1vec_modes4 = { ++ { /* Full size 525/60i with Rec.601 pixel rate */ ++ DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, ++ 720, 720 + 16, 720 + 16 + 64, 858, 0, ++ 480, 480 + 6, 480 + 6 + 6, 525, 0, ++ DRM_MODE_FLAG_INTERLACE) ++ }, ++ { /* Cropped and horizontally squashed to be TV-safe */ ++ DRM_MODE("704x432i", DRM_MODE_TYPE_DRIVER, 15429, ++ 704, 704 + 76, 704 + 76 + 72, 980, 0, ++ 432, 432 + 30, 432 + 30 + 6, 525, 0, ++ DRM_MODE_FLAG_INTERLACE) ++ }, ++ { /* Full size 625/50i with Rec.601 pixel rate */ ++ DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, ++ 720, 720 + 12, 720 + 12 + 64, 864, 0, ++ 576, 576 + 5, 576 + 5 + 5, 625, 0, ++ DRM_MODE_FLAG_INTERLACE) ++ }, ++ { /* Cropped and squashed, for square(ish) pixels */ ++ DRM_MODE("704x512i", DRM_MODE_TYPE_DRIVER, 15429, ++ 704, 704 + 72, 704 + 72 + 72, 987, 0, ++ 512, 512 + 37, 512 + 37 + 5, 625, 0, ++ DRM_MODE_FLAG_INTERLACE) ++ } ++}; ++ ++/* ++ * Advertise standard and preferred video modes. ++ * ++ * From each interlaced mode in the table above, derive a progressive one. ++ * ++ * This driver always supports all 50Hz and 60Hz video modes, regardless ++ * of connector's tv_mode; nonstandard combinations generally default ++ * to PAL-BDGHIKL or NTSC-M depending on resolution and field-rate ++ * (except that "PAL" with 525/60 will be implemented as "PAL60"). ++ * However, the preferred mode will depend on the default TV mode. ++ */ ++ ++static int rp1vec_connector_get_modes(struct drm_connector *connector) ++{ ++ u64 val; ++ int i, prog, n = 0; ++ bool prefer625 = false; ++ ++ if (!drm_object_property_get_default_value(&connector->base, ++ connector->dev->mode_config.tv_mode_property, ++ &val)) ++ prefer625 = (val == DRM_MODE_TV_MODE_PAL || ++ val == DRM_MODE_TV_MODE_PAL_N || ++ val == DRM_MODE_TV_MODE_SECAM); ++ ++ for (i = 0; i < ARRAY_SIZE(rp1vec_modes); i++) { ++ for (prog = 0; prog < 2; prog++) { ++ struct drm_display_mode *mode = ++ drm_mode_duplicate(connector->dev, ++ &rp1vec_modesi); ++ ++ if (prog) { ++ mode->flags &= ~DRM_MODE_FLAG_INTERLACE; ++ mode->vdisplay >>= 1; ++ mode->vsync_start >>= 1; ++ mode->vsync_end >>= 1; ++ mode->vtotal >>= 1; ++ } ++ ++ if (mode->hdisplay == 704 && ++ mode->vtotal == (prefer625 ? 625 : 525)) ++ mode->type |= DRM_MODE_TYPE_PREFERRED; ++ ++ drm_mode_set_name(mode); ++ drm_mode_probed_add(connector, mode); ++ n++; ++ } ++ } ++ ++ return n; ++} ++ ++static void rp1vec_connector_reset(struct drm_connector *connector) ++{ ++ drm_atomic_helper_connector_reset(connector); ++ drm_atomic_helper_connector_tv_reset(connector); ++} ++ ++static int rp1vec_connector_atomic_check(struct drm_connector *conn, ++ struct drm_atomic_state *state) ++{ struct drm_connector_state *old_state = ++ drm_atomic_get_old_connector_state(state, conn); ++ struct drm_connector_state *new_state = ++ drm_atomic_get_new_connector_state(state, conn); ++ ++ if (new_state->crtc && old_state->tv.mode != new_state->tv.mode) { ++ struct drm_crtc_state *crtc_state = ++ drm_atomic_get_new_crtc_state(state, new_state->crtc); ++ ++ crtc_state->mode_changed = true; ++ } ++ ++ return 0; ++} ++ ++static enum drm_mode_status rp1vec_mode_valid(struct drm_device *dev, ++ const struct drm_display_mode *mode) ++{ ++ /* ++ * Check the mode roughly matches something we can generate. ++ * The hardware driver is very prescriptive about pixel clocks, ++ * line and frame durations, but we'll tolerate rounding errors. ++ * Within each hardware mode, allow image size and position to vary ++ * (to fine-tune overscan correction or emulate retro devices). ++ * Don't check sync timings here: the HW driver will sanitize them. ++ */ ++ ++ int prog = !(mode->flags & DRM_MODE_FLAG_INTERLACE); ++ int vtotal_full = mode->vtotal << prog; ++ int vdisplay_full = mode->vdisplay << prog; ++ ++ /* Reject very small frames */ ++ if (vtotal_full < 256 || mode->hdisplay < 256) ++ return MODE_BAD; ++ ++ /* Check lines, frame period (ms) and vertical size limit */ ++ if (vtotal_full >= 524 && vtotal_full <= 526 && ++ mode->htotal * vtotal_full > 33 * mode->clock && ++ mode->htotal * vtotal_full < 34 * mode->clock && ++ vdisplay_full <= 480) ++ goto vgood; ++ if (vtotal_full >= 624 && vtotal_full <= 626 && ++ mode->htotal * vtotal_full > 39 * mode->clock && ++ mode->htotal * vtotal_full < 41 * mode->clock && ++ vdisplay_full <= 576) ++ goto vgood; ++ return MODE_BAD; ++ ++vgood: ++ /* Check pixel rate (kHz) and horizontal size limit */ ++ if (mode->clock == 13500 && mode->hdisplay <= 720) ++ return MODE_OK; ++ if (mode->clock >= 15428 && mode->clock <= 15429 && ++ mode->hdisplay <= 800) ++ return MODE_OK; ++ return MODE_BAD; ++} ++ ++static const struct drm_connector_helper_funcs rp1vec_connector_helper_funcs = { ++ .get_modes = rp1vec_connector_get_modes, ++ .atomic_check = rp1vec_connector_atomic_check, ++}; ++ ++static const struct drm_connector_funcs rp1vec_connector_funcs = { ++ .fill_modes = drm_helper_probe_single_connector_modes, ++ .destroy = rp1vec_connector_destroy, ++ .reset = rp1vec_connector_reset, ++ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, ++}; ++ ++static const struct drm_mode_config_funcs rp1vec_mode_funcs = { ++ .fb_create = drm_gem_fb_create, ++ .atomic_check = drm_atomic_helper_check, ++ .atomic_commit = drm_atomic_helper_commit, ++ .mode_valid = rp1vec_mode_valid, ++}; ++ ++static const u32 rp1vec_formats = { ++ DRM_FORMAT_XRGB8888, ++ DRM_FORMAT_XBGR8888, ++ DRM_FORMAT_RGB888, ++ DRM_FORMAT_BGR888, ++ DRM_FORMAT_RGB565 ++}; ++ ++static void rp1vec_stopall(struct drm_device *drm) ++{ ++ if (drm->dev_private) { ++ struct rp1_vec *vec = drm->dev_private; ++ ++ if (vec->vec_running || rp1vec_hw_busy(vec)) { ++ rp1vec_hw_stop(vec); ++ vec->vec_running = false; + } ++ rp1vec_vidout_poweroff(vec); ++ } ++} ++ ++DEFINE_DRM_GEM_DMA_FOPS(rp1vec_fops); ++ ++static struct drm_driver rp1vec_driver = { ++ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, ++ .fops = &rp1vec_fops, ++ .name = "drm-rp1-vec", ++ .desc = "drm-rp1-vec", ++ .date = "0", ++ .major = 1, ++ .minor = 0, ++ DRM_GEM_DMA_DRIVER_OPS, ++ .release = rp1vec_stopall, ++}; ++ ++static int rp1vec_platform_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct rp1_vec *vec; ++ int i, ret; ++ ++ dev_info(dev, __func__); ++ vec = devm_drm_dev_alloc(dev, &rp1vec_driver, struct rp1_vec, drm); ++ if (IS_ERR(vec)) { ++ ret = PTR_ERR(vec); ++ dev_err(dev, "%s devm_drm_dev_alloc %d", __func__, ret); ++ return ret; ++ } ++ vec->pdev = pdev; ++ ++ for (i = 0; i < RP1VEC_NUM_HW_BLOCKS; i++) { ++ vec->hw_basei = ++ devm_ioremap_resource(dev, ++ platform_get_resource(vec->pdev, IORESOURCE_MEM, i)); ++ if (IS_ERR(vec->hw_basei)) { ++ ret = PTR_ERR(vec->hw_basei); ++ dev_err(dev, "Error memory mapping regs%d\n", i); ++ goto done_err; ++ } ++ } ++ ret = platform_get_irq(vec->pdev, 0); ++ if (ret > 0) ++ ret = devm_request_irq(dev, ret, rp1vec_hw_isr, ++ IRQF_SHARED, "rp1-vec", vec); ++ if (ret) { ++ dev_err(dev, "Unable to request interrupt\n"); ++ ret = -EINVAL; ++ goto done_err; ++ } ++ ++ vec->vec_clock = devm_clk_get(dev, NULL); ++ if (IS_ERR(vec->vec_clock)) { ++ ret = PTR_ERR(vec->vec_clock); ++ goto done_err; ++ } ++ ret = clk_prepare_enable(vec->vec_clock); ++ ++ ret = drmm_mode_config_init(&vec->drm); ++ if (ret) ++ goto done_err; ++ ++ /* Now we have all our resources, finish driver initialization */ ++ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); ++ init_completion(&vec->finished); ++ vec->drm.dev_private = vec; ++ platform_set_drvdata(pdev, &vec->drm); ++ ++ vec->drm.mode_config.max_width = 800; ++ vec->drm.mode_config.max_height = 576; ++ vec->drm.mode_config.preferred_depth = 32; ++ vec->drm.mode_config.prefer_shadow = 0; ++ vec->drm.mode_config.quirk_addfb_prefer_host_byte_order = true; ++ vec->drm.mode_config.funcs = &rp1vec_mode_funcs; ++ drm_vblank_init(&vec->drm, 1); ++ ++ ret = drm_mode_create_tv_properties(&vec->drm, RP1VEC_SUPPORTED_TV_MODES); ++ if (ret) ++ goto done_err; ++ ++ drm_connector_init(&vec->drm, &vec->connector, &rp1vec_connector_funcs, ++ DRM_MODE_CONNECTOR_Composite); ++ if (ret) ++ goto done_err; ++ ++ vec->connector.interlace_allowed = true; ++ drm_connector_helper_add(&vec->connector, &rp1vec_connector_helper_funcs); ++ ++ drm_object_attach_property(&vec->connector.base, ++ vec->drm.mode_config.tv_mode_property, ++ (vec->connector.cmdline_mode.tv_mode_specified) ? ++ vec->connector.cmdline_mode.tv_mode : ++ DRM_MODE_TV_MODE_NTSC); ++ ++ ret = drm_simple_display_pipe_init(&vec->drm, ++ &vec->pipe, ++ &rp1vec_pipe_funcs, ++ rp1vec_formats, ++ ARRAY_SIZE(rp1vec_formats), ++ NULL, ++ &vec->connector); ++ if (ret) ++ goto done_err; ++ ++ drm_mode_config_reset(&vec->drm); ++ ++ ret = drm_dev_register(&vec->drm, 0); ++ if (ret) ++ goto done_err; ++ ++ drm_fbdev_generic_setup(&vec->drm, 32); ++ return ret; ++ ++done_err: ++ dev_err(dev, "%s fail %d", __func__, ret); ++ return ret; ++} ++ ++static int rp1vec_platform_remove(struct platform_device *pdev) ++{ ++ struct drm_device *drm = platform_get_drvdata(pdev); ++ ++ rp1vec_stopall(drm); ++ drm_dev_unregister(drm); ++ drm_atomic_helper_shutdown(drm); ++ drm_dev_put(drm); ++ ++ return 0; ++} ++ ++static void rp1vec_platform_shutdown(struct platform_device *pdev) ++{ ++ struct drm_device *drm = platform_get_drvdata(pdev); ++ ++ rp1vec_stopall(drm); ++} ++ ++static const struct of_device_id rp1vec_of_match = { ++ { ++ .compatible = "raspberrypi,rp1vec", ++ }, ++ { /* sentinel */ }, ++}; ++ ++MODULE_DEVICE_TABLE(of, rp1vec_of_match); ++ ++static struct platform_driver rp1vec_platform_driver = { ++ .probe = rp1vec_platform_probe, ++ .remove = rp1vec_platform_remove, ++ .shutdown = rp1vec_platform_shutdown, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = rp1vec_of_match, ++ }, ++}; ++ ++module_platform_driver(rp1vec_platform_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("DRM driver for Composite Video on Raspberry Pi RP1"); ++MODULE_AUTHOR("Nick Hollinghurst"); +diff --git a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.h b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.h +new file mode 100644 +index 000000000000..16ee80f18c9b +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.h +@@ -0,0 +1,69 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * DRM Driver for DSI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include <linux/types.h> ++#include <linux/io.h> ++#include <linux/clk.h> ++#include <drm/drm_device.h> ++#include <drm/drm_simple_kms_helper.h> ++ ++#define MODULE_NAME "drm-rp1-vec" ++#define DRIVER_NAME "drm-rp1-vec" ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define RP1VEC_HW_BLOCK_VEC 0 ++#define RP1VEC_HW_BLOCK_CFG 1 ++#define RP1VEC_NUM_HW_BLOCKS 2 ++ ++#define RP1VEC_SUPPORTED_TV_MODES \ ++ (BIT(DRM_MODE_TV_MODE_NTSC) | \ ++ BIT(DRM_MODE_TV_MODE_NTSC_443) | \ ++ BIT(DRM_MODE_TV_MODE_NTSC_J) | \ ++ BIT(DRM_MODE_TV_MODE_PAL) | \ ++ BIT(DRM_MODE_TV_MODE_PAL_M) | \ ++ BIT(DRM_MODE_TV_MODE_PAL_N)) ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct rp1_vec { ++ /* DRM base and platform device pointer */ ++ struct drm_device drm; ++ struct platform_device *pdev; ++ ++ /* Framework and helper objects */ ++ struct drm_simple_display_pipe pipe; ++ struct drm_connector connector; ++ ++ /* Clock. We assume this is always at 108 MHz. */ ++ struct clk *vec_clock; ++ ++ /* Block (VCC, CFG) base addresses, and current state */ ++ void __iomem *hw_baseRP1VEC_NUM_HW_BLOCKS; ++ u32 cur_fmt; ++ bool vec_running, pipe_enabled; ++ struct completion finished; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++/* Functions to control the VEC/DMA block */ ++ ++void rp1vec_hw_setup(struct rp1_vec *vec, ++ u32 in_format, ++ struct drm_display_mode const *mode, ++ int tvstd); ++void rp1vec_hw_update(struct rp1_vec *vec, dma_addr_t addr, u32 offset, u32 stride); ++void rp1vec_hw_stop(struct rp1_vec *vec); ++int rp1vec_hw_busy(struct rp1_vec *vec); ++irqreturn_t rp1vec_hw_isr(int irq, void *dev); ++void rp1vec_hw_vblank_ctrl(struct rp1_vec *vec, int enable); ++ ++/* ---------------------------------------------------------------------- */ ++/* Functions to control the VIDEO OUT CFG block and check RP1 platform */ ++ ++void rp1vec_vidout_setup(struct rp1_vec *vec); ++void rp1vec_vidout_poweroff(struct rp1_vec *vec); +diff --git a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_cfg.c b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_cfg.c +new file mode 100644 +index 000000000000..241dedee5889 +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_cfg.c +@@ -0,0 +1,508 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for DSI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/mm.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/platform_device.h> ++#include <linux/printk.h> ++#include <linux/rp1_platform.h> ++ ++#include "rp1_vec.h" ++ ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_SEL ++// JTAG access : synchronous ++// Description : Selects source: VEC or DPI ++#define VIDEO_OUT_CFG_SEL_OFFSET 0x00000000 ++#define VIDEO_OUT_CFG_SEL_BITS 0x00000013 ++#define VIDEO_OUT_CFG_SEL_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_SEL_PCLK_INV ++// Description : Select dpi_pclk output port polarity inversion. ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_RESET 0x0 ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_BITS 0x00000010 ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_MSB 4 ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_LSB 4 ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_SEL_PAD_MUX ++// Description : VEC 1 DPI 0 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_RESET 0x0 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_BITS 0x00000002 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_MSB 1 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_LSB 1 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_SEL_VDAC_MUX ++// Description : VEC 1 DPI 0 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_RESET 0x0 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_BITS 0x00000001 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_MSB 0 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_LSB 0 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_VDAC_CFG ++// JTAG access : synchronous ++// Description : Configure SNPS VDAC ++#define VIDEO_OUT_CFG_VDAC_CFG_OFFSET 0x00000004 ++#define VIDEO_OUT_CFG_VDAC_CFG_BITS 0x1fffffff ++#define VIDEO_OUT_CFG_VDAC_CFG_RESET 0x0003ffff ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENCTR ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_BITS 0x1c000000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_MSB 28 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_LSB 26 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENSC ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_BITS 0x03800000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_MSB 25 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_LSB 23 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENDAC ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_BITS 0x00700000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_MSB 22 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_LSB 20 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENVBG ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_BITS 0x00080000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_MSB 19 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_LSB 19 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_BITS 0x00040000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_MSB 18 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_LSB 18 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_DAC2GC ++// Description : dac2 gain control ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_RESET 0x3f ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_BITS 0x0003f000 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_MSB 17 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_LSB 12 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_DAC1GC ++// Description : dac1 gain control ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_RESET 0x3f ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_BITS 0x00000fc0 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_MSB 11 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_LSB 6 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_DAC0GC ++// Description : dac0 gain control ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_RESET 0x3f ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_BITS 0x0000003f ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_MSB 5 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_LSB 0 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_VDAC_STATUS ++// JTAG access : synchronous ++// Description : Read VDAC status ++#define VIDEO_OUT_CFG_VDAC_STATUS_OFFSET 0x00000008 ++#define VIDEO_OUT_CFG_VDAC_STATUS_BITS 0x00000017 ++#define VIDEO_OUT_CFG_VDAC_STATUS_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3 ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_BITS 0x00000010 ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_MSB 4 ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_LSB 4 ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_RESET "-" ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_BITS 0x00000007 ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_MSB 2 ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_LSB 0 ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_MEM_PD ++// JTAG access : synchronous ++// Description : Control memory power down ++#define VIDEO_OUT_CFG_MEM_PD_OFFSET 0x0000000c ++#define VIDEO_OUT_CFG_MEM_PD_BITS 0x00000003 ++#define VIDEO_OUT_CFG_MEM_PD_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_MEM_PD_VEC ++// Description : None ++#define VIDEO_OUT_CFG_MEM_PD_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_MEM_PD_VEC_BITS 0x00000002 ++#define VIDEO_OUT_CFG_MEM_PD_VEC_MSB 1 ++#define VIDEO_OUT_CFG_MEM_PD_VEC_LSB 1 ++#define VIDEO_OUT_CFG_MEM_PD_VEC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_MEM_PD_DPI ++// Description : None ++#define VIDEO_OUT_CFG_MEM_PD_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_MEM_PD_DPI_BITS 0x00000001 ++#define VIDEO_OUT_CFG_MEM_PD_DPI_MSB 0 ++#define VIDEO_OUT_CFG_MEM_PD_DPI_LSB 0 ++#define VIDEO_OUT_CFG_MEM_PD_DPI_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_TEST_OVERRIDE ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_OFFSET 0x00000010 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_BITS 0xffffffff ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_TEST_OVERRIDE_PAD ++// Description : None ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_RESET 0x0 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_BITS 0x80000000 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_MSB 31 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_LSB 31 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC ++// Description : None ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_RESET 0x0 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_BITS 0x40000000 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_MSB 30 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_LSB 30 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL ++// Description : None ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_RESET 0x00000000 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_BITS 0x3fffffff ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_MSB 29 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_LSB 0 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INTR ++// JTAG access : synchronous ++// Description : Raw Interrupts ++#define VIDEO_OUT_CFG_INTR_OFFSET 0x00000014 ++#define VIDEO_OUT_CFG_INTR_BITS 0x00000003 ++#define VIDEO_OUT_CFG_INTR_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTR_DPI ++// Description : None ++#define VIDEO_OUT_CFG_INTR_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_INTR_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_INTR_DPI_MSB 1 ++#define VIDEO_OUT_CFG_INTR_DPI_LSB 1 ++#define VIDEO_OUT_CFG_INTR_DPI_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTR_VEC ++// Description : None ++#define VIDEO_OUT_CFG_INTR_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_INTR_VEC_BITS 0x00000001 ++#define VIDEO_OUT_CFG_INTR_VEC_MSB 0 ++#define VIDEO_OUT_CFG_INTR_VEC_LSB 0 ++#define VIDEO_OUT_CFG_INTR_VEC_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INTE ++// JTAG access : synchronous ++// Description : Interrupt Enable ++#define VIDEO_OUT_CFG_INTE_OFFSET 0x00000018 ++#define VIDEO_OUT_CFG_INTE_BITS 0x00000003 ++#define VIDEO_OUT_CFG_INTE_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTE_DPI ++// Description : None ++#define VIDEO_OUT_CFG_INTE_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_INTE_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_INTE_DPI_MSB 1 ++#define VIDEO_OUT_CFG_INTE_DPI_LSB 1 ++#define VIDEO_OUT_CFG_INTE_DPI_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTE_VEC ++// Description : None ++#define VIDEO_OUT_CFG_INTE_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_INTE_VEC_BITS 0x00000001 ++#define VIDEO_OUT_CFG_INTE_VEC_MSB 0 ++#define VIDEO_OUT_CFG_INTE_VEC_LSB 0 ++#define VIDEO_OUT_CFG_INTE_VEC_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INTF ++// JTAG access : synchronous ++// Description : Interrupt Force ++#define VIDEO_OUT_CFG_INTF_OFFSET 0x0000001c ++#define VIDEO_OUT_CFG_INTF_BITS 0x00000003 ++#define VIDEO_OUT_CFG_INTF_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTF_DPI ++// Description : None ++#define VIDEO_OUT_CFG_INTF_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_INTF_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_INTF_DPI_MSB 1 ++#define VIDEO_OUT_CFG_INTF_DPI_LSB 1 ++#define VIDEO_OUT_CFG_INTF_DPI_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTF_VEC ++// Description : None ++#define VIDEO_OUT_CFG_INTF_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_INTF_VEC_BITS 0x00000001 ++#define VIDEO_OUT_CFG_INTF_VEC_MSB 0 ++#define VIDEO_OUT_CFG_INTF_VEC_LSB 0 ++#define VIDEO_OUT_CFG_INTF_VEC_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INTS ++// JTAG access : synchronous ++// Description : Interrupt status after masking & forcing ++#define VIDEO_OUT_CFG_INTS_OFFSET 0x00000020 ++#define VIDEO_OUT_CFG_INTS_BITS 0x00000003 ++#define VIDEO_OUT_CFG_INTS_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTS_DPI ++// Description : None ++#define VIDEO_OUT_CFG_INTS_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_INTS_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_INTS_DPI_MSB 1 ++#define VIDEO_OUT_CFG_INTS_DPI_LSB 1 ++#define VIDEO_OUT_CFG_INTS_DPI_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTS_VEC ++// Description : None ++#define VIDEO_OUT_CFG_INTS_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_INTS_VEC_BITS 0x00000001 ++#define VIDEO_OUT_CFG_INTS_VEC_MSB 0 ++#define VIDEO_OUT_CFG_INTS_VEC_LSB 0 ++#define VIDEO_OUT_CFG_INTS_VEC_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_BLOCK_ID ++// JTAG access : synchronous ++// Description : Block Identifier ++// Hexadecimal representation of "VOCF" ++#define VIDEO_OUT_CFG_BLOCK_ID_OFFSET 0x00000024 ++#define VIDEO_OUT_CFG_BLOCK_ID_BITS 0xffffffff ++#define VIDEO_OUT_CFG_BLOCK_ID_RESET 0x564f4346 ++#define VIDEO_OUT_CFG_BLOCK_ID_MSB 31 ++#define VIDEO_OUT_CFG_BLOCK_ID_LSB 0 ++#define VIDEO_OUT_CFG_BLOCK_ID_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INSTANCE_ID ++// JTAG access : synchronous ++// Description : Block Instance Identifier ++#define VIDEO_OUT_CFG_INSTANCE_ID_OFFSET 0x00000028 ++#define VIDEO_OUT_CFG_INSTANCE_ID_BITS 0x0000000f ++#define VIDEO_OUT_CFG_INSTANCE_ID_RESET 0x00000000 ++#define VIDEO_OUT_CFG_INSTANCE_ID_MSB 3 ++#define VIDEO_OUT_CFG_INSTANCE_ID_LSB 0 ++#define VIDEO_OUT_CFG_INSTANCE_ID_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_AUTO ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_OFFSET 0x0000002c ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_RESET 0x00000007 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_PARALLEL ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_OFFSET 0x00000030 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_RESET 0x00000006 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_CTRL ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_OFFSET 0x00000034 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_TRIG ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_OFFSET 0x00000038 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC ++// Description : Pulses the reset output ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_ACCESS "SC" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI ++// Description : Pulses the reset output ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_ACCESS "SC" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER ++// Description : Pulses the reset output ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_ACCESS "SC" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_DONE ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_OFFSET 0x0000003c ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_DONE_VEC ++// Description : Indicates the current state of the reset ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_DONE_DPI ++// Description : Indicates the current state of the reset ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER ++// Description : Indicates the current state of the reset ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_ACCESS "RO" ++// ============================================================================= ++ ++#define CFG_WRITE(reg, val) writel((val), vec->hw_baseRP1VEC_HW_BLOCK_CFG + (reg ## _OFFSET)) ++#define CFG_READ(reg) readl(vec->hw_baseRP1VEC_HW_BLOCK_CFG + (reg ## _OFFSET)) ++ ++void rp1vec_vidout_setup(struct rp1_vec *vec) ++{ ++ /* ++ * We assume DPI and VEC can't be used at the same time (due to ++ * clashing requirements for PLL_VIDEO, and potentially for VDAC). ++ * We therefore leave DPI memories powered down. ++ */ ++ CFG_WRITE(VIDEO_OUT_CFG_MEM_PD, VIDEO_OUT_CFG_MEM_PD_DPI_BITS); ++ CFG_WRITE(VIDEO_OUT_CFG_TEST_OVERRIDE, 0x00000000); ++ ++ /* DPI->Pads; VEC->VDAC */ ++ CFG_WRITE(VIDEO_OUT_CFG_SEL, VIDEO_OUT_CFG_SEL_VDAC_MUX_BITS); ++ ++ /* configure VDAC for 1 channel, bandgap on, 1.28V swing */ ++ CFG_WRITE(VIDEO_OUT_CFG_VDAC_CFG, 0x0019ffff); ++ ++ /* enable VEC interrupt */ ++ CFG_WRITE(VIDEO_OUT_CFG_INTE, VIDEO_OUT_CFG_INTE_VEC_BITS); ++} ++ ++void rp1vec_vidout_poweroff(struct rp1_vec *vec) ++{ ++ /* disable VEC interrupt */ ++ CFG_WRITE(VIDEO_OUT_CFG_INTE, 0); ++ ++ /* Ensure VDAC is turned off; power down DPI,VEC memories */ ++ CFG_WRITE(VIDEO_OUT_CFG_VDAC_CFG, 0); ++ CFG_WRITE(VIDEO_OUT_CFG_MEM_PD, VIDEO_OUT_CFG_MEM_PD_BITS); ++} +diff --git a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c +new file mode 100644 +index 000000000000..b9a67a8a330c +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c +@@ -0,0 +1,508 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for VEC output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/mm.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/platform_device.h> ++#include <drm/drm_fourcc.h> ++#include <drm/drm_print.h> ++#include <drm/drm_vblank.h> ++ ++#include "rp1_vec.h" ++#include "vec_regs.h" ++ ++#define BITS(field, val) (((val) << (field ## _LSB)) & (field ## _BITS)) ++ ++#define VEC_WRITE(reg, val) writel((val), vec->hw_baseRP1VEC_HW_BLOCK_VEC + (reg ## _OFFSET)) ++#define VEC_READ(reg) readl(vec->hw_baseRP1VEC_HW_BLOCK_VEC + (reg ## _OFFSET)) ++ ++int rp1vec_hw_busy(struct rp1_vec *vec) ++{ ++ /* Read the undocumented "pline_busy" flag */ ++ return VEC_READ(VEC_STATUS) & 1; ++} ++ ++/* Table of supported input (in-memory/DMA) pixel formats. */ ++struct rp1vec_ipixfmt { ++ u32 format; /* DRM format code */ ++ u32 mask; /* RGB masks (10 bits each, left justified) */ ++ u32 shift; /* RGB MSB positions in the memory word */ ++ u32 rgbsz; /* Shifts used for scaling; also (BPP/8-1) */ ++}; ++ ++#define MASK_RGB(r, g, b) \ ++ (BITS(VEC_IMASK_MASK_R, r) | BITS(VEC_IMASK_MASK_G, g) | BITS(VEC_IMASK_MASK_B, b)) ++#define SHIFT_RGB(r, g, b) \ ++ (BITS(VEC_SHIFT_SHIFT_R, r) | BITS(VEC_SHIFT_SHIFT_G, g) | BITS(VEC_SHIFT_SHIFT_B, b)) ++ ++static const struct rp1vec_ipixfmt my_formats = { ++ { ++ .format = DRM_FORMAT_XRGB8888, ++ .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = SHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 3), ++ }, ++ { ++ .format = DRM_FORMAT_XBGR8888, ++ .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = SHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 3), ++ }, ++ { ++ .format = DRM_FORMAT_RGB888, ++ .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = SHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 2), ++ }, ++ { ++ .format = DRM_FORMAT_BGR888, ++ .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = SHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 2), ++ }, ++ { ++ .format = DRM_FORMAT_RGB565, ++ .mask = MASK_RGB(0x3e0, 0x3f0, 0x3e0), ++ .shift = SHIFT_RGB(15, 10, 4), ++ .rgbsz = BITS(VEC_RGBSZ_SCALE_R, 5) | ++ BITS(VEC_RGBSZ_SCALE_G, 6) | ++ BITS(VEC_RGBSZ_SCALE_B, 5) | ++ BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 1), ++ } ++}; ++ ++/* ++ * Hardware mode descriptions (@ 108 MHz clock rate). ++ * These rely largely on "canned" register settings. ++ */ ++ ++struct rp1vec_hwmode { ++ u16 total_cols; /* max active columns incl. padding and windowing */ ++ u16 rows_per_field; /* active lines per field (including partial ones) */ ++ u16 ref_hfp; /* nominal (hsync_start - hdisplay) when max width */ ++ u16 ref_vfp; /* nominal (vsync_start - vdisplay) when max height */ ++ bool interlaced; /* set for interlaced */ ++ bool first_field_odd; /* set for interlaced and 30fps */ ++ u32 yuv_scaling; /* three 10-bit fields {Y, U, V} in 2.8 format */ ++ u32 back_end_regs28; /* All registers 0x80 .. 0xEC */ ++}; ++ ++/* { NTSC, PAL, PAL-M } x { progressive, interlaced } x { 13.5 MHz, 15.428571 MHz } */ ++static const struct rp1vec_hwmode rp1vec_hwmodes322 = { ++ { ++ /* NTSC */ ++ { ++ { ++ .total_cols = 724, ++ .rows_per_field = 240, ++ .ref_hfp = 12, ++ .ref_vfp = 2, ++ .interlaced = false, ++ .first_field_odd = false, ++ .yuv_scaling = 0x1071d0cf, ++ .back_end_regs = { ++ 0x039f1a3f, 0x03e10cc6, 0x0d6801fb, 0x023d034c, ++ 0x00f80b6d, 0x00000005, 0x0006000b, 0x000c0011, ++ 0x000a0106, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00170106, 0x00000000, 0x004c020e, ++ 0x00000000, 0x007bffff, 0x38518c9a, 0x11195561, ++ 0x02000200, 0xc1f07c1f, 0x087c1f07, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ec, ++ }, ++ }, { ++ .total_cols = 815, ++ .rows_per_field = 240, ++ .ref_hfp = 16, ++ .ref_vfp = 2, ++ .interlaced = false, ++ .first_field_odd = false, ++ .yuv_scaling = 0x1c131962, ++ .back_end_regs = { ++ 0x03ce1a17, 0x03e10cc6, 0x0d6801fb, 0x023d034c, ++ 0x00f80b6d, 0x00000005, 0x0006000b, 0x000c0011, ++ 0x000a0106, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00170106, 0x00000000, 0x004c020e, ++ 0x00000000, 0x007bffff, 0x38518c9a, 0x11195561, ++ 0x02000200, 0xc1f07c1f, 0x087c1f07, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ac, ++ }, ++ }, ++ }, { ++ { ++ .total_cols = 724, ++ .rows_per_field = 243, ++ .ref_hfp = 12, ++ .ref_vfp = 3, ++ .interlaced = true, ++ .first_field_odd = true, ++ .yuv_scaling = 0x1071d0cf, ++ .back_end_regs = { ++ 0x039f1a3f, 0x03e10cc6, 0x0d6801fb, 0x023d034c, ++ 0x00f80b6d, 0x00000005, 0x0006000b, 0x000c0011, ++ 0x000a0107, 0x0111020d, 0x00000000, 0x00000000, ++ 0x011c020d, 0x00150106, 0x0107011b, 0x004c020d, ++ 0x00000000, 0x007bffff, 0x38518c9a, 0x11195561, ++ 0x02000200, 0xc1f07c1f, 0x087c1f07, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x00094dee, ++ }, ++ }, { ++ .total_cols = 815, ++ .rows_per_field = 243, ++ .ref_hfp = 16, ++ .ref_vfp = 3, ++ .interlaced = true, ++ .first_field_odd = true, ++ .yuv_scaling = 0x1c131962, ++ .back_end_regs = { ++ 0x03ce1a17, 0x03e10cc6, 0x0d6801fb, 0x023d034c, ++ 0x00f80b6d, 0x00000005, 0x0006000b, 0x000c0011, ++ 0x000a0107, 0x0111020d, 0x00000000, 0x00000000, ++ 0x011c020d, 0x00150106, 0x0107011b, 0x004c020d, ++ 0x00000000, 0x007bffff, 0x38518c9a, 0x11195561, ++ 0x02000200, 0xc1f07c1f, 0x087c1f07, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x00094dae, ++ }, ++ }, ++ }, ++ }, { ++ /* PAL */ ++ { ++ { ++ .total_cols = 724, ++ .rows_per_field = 288, ++ .ref_hfp = 16, ++ .ref_vfp = 2, ++ .interlaced = false, ++ .first_field_odd = false, ++ .yuv_scaling = 0x11c1f8e0, ++ .back_end_regs = { ++ 0x04061aa6, 0x046e0cee, 0x0d8001fb, 0x025c034f, ++ 0x00fd0b84, 0x026c0270, 0x00000004, 0x00050009, ++ 0x00070135, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00170136, 0x00000000, 0x000a0270, ++ 0x00000000, 0x007bffff, 0x3b1389d8, 0x0caf53b5, ++ 0x02000200, 0xcc48c1d1, 0x0a8262b2, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ed, ++ }, ++ }, { ++ .total_cols = 804, ++ .rows_per_field = 288, ++ .ref_hfp = 24, ++ .ref_vfp = 2, ++ .interlaced = false, ++ .first_field_odd = false, ++ .yuv_scaling = 0x1e635d7f, ++ .back_end_regs = { ++ 0x045b1a57, 0x046e0cee, 0x0d8001fb, 0x025c034f, ++ 0x00fd0b84, 0x026c0270, 0x00000004, 0x00050009, ++ 0x00070135, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00170136, 0x00000000, 0x000a0270, ++ 0x00000000, 0x007bffff, 0x3b1389d8, 0x0caf53b5, ++ 0x02000200, 0xcc48c1d1, 0x0a8262b2, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ad, ++ }, ++ }, ++ }, { ++ { ++ .total_cols = 724, ++ .rows_per_field = 288, ++ .ref_hfp = 16, ++ .ref_vfp = 5, ++ .interlaced = true, ++ .first_field_odd = false, ++ .yuv_scaling = 0x11c1f8e0, ++ .back_end_regs = { ++ 0x04061aa6, 0x046e0cee, 0x0d8001fb, 0x025c034f, ++ 0x00fd0b84, 0x026c0270, 0x00000004, 0x00050009, ++ 0x00070135, 0x013f026d, 0x00060136, 0x0140026e, ++ 0x0150026e, 0x00180136, 0x026f0017, 0x000a0271, ++ 0x00000000, 0x007bffff, 0x3b1389d8, 0x0caf53b5, ++ 0x02000200, 0xcc48c1d1, 0x0a8262b2, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x0009ddef, ++ }, ++ }, { ++ .total_cols = 804, ++ .rows_per_field = 288, ++ .ref_hfp = 24, ++ .ref_vfp = 5, ++ .interlaced = true, ++ .first_field_odd = false, ++ .yuv_scaling = 0x1e635d7f, ++ .back_end_regs = { ++ 0x045b1a57, 0x046e0cee, 0x0d8001fb, 0x025c034f, ++ 0x00fd0b84, 0x026c0270, 0x00000004, 0x00050009, ++ 0x00070135, 0x013f026d, 0x00060136, 0x0140026e, ++ 0x0150026e, 0x00180136, 0x026f0017, 0x000a0271, ++ 0x00000000, 0x007bffff, 0x3b1389d8, 0x0caf53b5, ++ 0x02000200, 0xcc48c1d1, 0x0a8262b2, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x0009ddaf, ++ }, ++ }, ++ }, ++ }, { ++ /* PAL-M */ ++ { ++ { ++ .total_cols = 724, ++ .rows_per_field = 240, ++ .ref_hfp = 12, ++ .ref_vfp = 2, ++ .interlaced = false, ++ .first_field_odd = false, ++ .yuv_scaling = 0x11c1f8e0, ++ .back_end_regs = { ++ 0x039f1a3f, 0x03e10cc6, 0x0d6801fb, 0x023c034c, ++ 0x00f80b6e, 0x00000005, 0x0006000b, 0x000c0011, ++ 0x000a0106, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00170106, 0x00000000, 0x000a020c, ++ 0x00000000, 0x007bffff, 0x385189d8, 0x0d5c53b5, ++ 0x02000200, 0xd6d33ea8, 0x0879bbf8, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ed, ++ }, ++ }, { ++ .total_cols = 815, ++ .rows_per_field = 240, ++ .ref_hfp = 16, ++ .ref_vfp = 2, ++ .interlaced = false, ++ .first_field_odd = false, ++ .yuv_scaling = 0x1e635d7f, ++ .back_end_regs = { ++ 0x03ce1a17, 0x03e10cc6, 0x0d6801fb, 0x023c034c, ++ 0x00f80b6e, 0x00000005, 0x0006000b, 0x000c0011, ++ 0x000a0106, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00170106, 0x00000000, 0x000a020c, ++ 0x00000000, 0x007bffff, 0x385189d8, 0x0d5c53b5, ++ 0x02000200, 0xd6d33ea8, 0x0879bbf8, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ad, ++ }, ++ }, ++ }, { ++ { ++ .total_cols = 724, ++ .rows_per_field = 243, ++ .ref_hfp = 12, ++ .ref_vfp = 3, ++ .interlaced = true, ++ .first_field_odd = true, ++ .yuv_scaling = 0x11c1f8e0, ++ .back_end_regs = { ++ 0x039f1a3f, 0x03e10cc6, 0x0d6801fb, 0x023c034c, ++ 0x00f80b6e, 0x00140019, 0x00000005, 0x0006000b, ++ 0x00090103, 0x010f0209, 0x00080102, 0x010e020a, ++ 0x0119020a, 0x00120103, 0x01040118, 0x000a020d, ++ 0x00000000, 0x007bffff, 0x385189d8, 0x0d5c53b5, ++ 0x02000200, 0xd6d33ea8, 0x0879bbf8, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x0009ddef, ++ }, ++ }, { ++ .total_cols = 815, ++ .rows_per_field = 243, ++ .ref_hfp = 16, ++ .ref_vfp = 3, ++ .interlaced = true, ++ .first_field_odd = true, ++ .yuv_scaling = 0x1e635d7f, ++ .back_end_regs = { ++ 0x03ce1a17, 0x03e10cc6, 0x0d6801fb, 0x023c034c, ++ 0x00f80b6e, 0x00140019, 0x00000005, 0x0006000b, ++ 0x00090103, 0x010f0209, 0x00080102, 0x010e020a, ++ 0x0119020a, 0x00120103, 0x01040118, 0x000a020d, ++ 0x00000000, 0x007bffff, 0x385189d8, 0x0d5c53b5, ++ 0x02000200, 0xd6d33ea8, 0x0879bbf8, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x0009ddaf, ++ }, ++ }, ++ }, ++ }, ++}; ++ ++void rp1vec_hw_setup(struct rp1_vec *vec, ++ u32 in_format, ++ struct drm_display_mode const *mode, ++ int tvstd) ++{ ++ unsigned int i, mode_family, mode_ilaced, mode_narrow; ++ const struct rp1vec_hwmode *hwm; ++ int w, h, hpad, vpad; ++ ++ /* Pick the appropriate "base" mode, which we may modify */ ++ mode_ilaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); ++ if (mode->vtotal >= 272 * (1 + mode_ilaced)) ++ mode_family = 1; ++ else if (tvstd == DRM_MODE_TV_MODE_PAL_M || tvstd == DRM_MODE_TV_MODE_PAL) ++ mode_family = 2; ++ else ++ mode_family = 0; ++ mode_narrow = (mode->clock >= 14336); ++ hwm = &rp1vec_hwmodesmode_familymode_ilacedmode_narrow; ++ dev_info(&vec->pdev->dev, ++ "%s: in_fmt=\'%c%c%c%c\' mode=%dx%d%s %d%d%d tvstd=%d", ++ __func__, in_format, in_format >> 8, in_format >> 16, in_format >> 24, ++ mode->hdisplay, mode->vdisplay, (mode_ilaced) ? "i" : "", ++ mode_family, mode_ilaced, mode_narrow, tvstd); ++ ++ w = mode->hdisplay; ++ h = mode->vdisplay >> mode_ilaced; ++ if (w > hwm->total_cols) ++ w = hwm->total_cols; ++ if (h > hwm->rows_per_field) ++ h = hwm->rows_per_field; ++ ++ /* ++ * Add padding so a framebuffer with the given dimensions and ++ * hvsync_start can be displayed in the chosen hardware mode. ++ * ++ * |<----- mode->hsync_start ----->| ++ * |<------ w ------>| | ++ * | | >|--|< ref_hfp ++ * |<- hpad ->| ++ * |<------------ total_cols ----------->| ++ * ________FRAMEBUFFERCONTENTS__________ ++ * ' `--\____/-<\/\/\>-' ++ */ ++ hpad = max(0, mode->hsync_start - hwm->ref_hfp - w); ++ hpad = min(hpad, hwm->total_cols - w); ++ vpad = max(0, ((mode->vsync_start - hwm->ref_vfp) >> mode_ilaced) - h); ++ vpad = min(vpad, hwm->rows_per_field - h); ++ ++ /* Configure the hardware */ ++ VEC_WRITE(VEC_APB_TIMEOUT, 0x38); ++ VEC_WRITE(VEC_QOS, ++ BITS(VEC_QOS_DQOS, 0x0) | ++ BITS(VEC_QOS_ULEV, 0x8) | ++ BITS(VEC_QOS_UQOS, 0x2) | ++ BITS(VEC_QOS_LLEV, 0x4) | ++ BITS(VEC_QOS_LQOS, 0x7)); ++ VEC_WRITE(VEC_DMA_AREA, ++ BITS(VEC_DMA_AREA_COLS_MINUS1, w - 1) | ++ BITS(VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1, h - 1)); ++ VEC_WRITE(VEC_YUV_SCALING, hwm->yuv_scaling); ++ VEC_WRITE(VEC_BACK_PORCH, ++ BITS(VEC_BACK_PORCH_HBP_MINUS1, hwm->total_cols - w - hpad - 1) | ++ BITS(VEC_BACK_PORCH_VBP_MINUS1, hwm->rows_per_field - h - vpad - 1)); ++ VEC_WRITE(VEC_FRONT_PORCH, ++ BITS(VEC_FRONT_PORCH_HFP_MINUS1, hpad - 1) | ++ BITS(VEC_FRONT_PORCH_VFP_MINUS1, vpad - 1)); ++ VEC_WRITE(VEC_MODE, ++ BITS(VEC_MODE_HIGH_WATER, 0xE0) | ++ BITS(VEC_MODE_ALIGN16, !((w | mode->hdisplay) & 15)) | ++ BITS(VEC_MODE_VFP_EN, (vpad > 0)) | ++ BITS(VEC_MODE_VBP_EN, (hwm->rows_per_field > h + vpad)) | ++ BITS(VEC_MODE_HFP_EN, (hpad > 0)) | ++ BITS(VEC_MODE_HBP_EN, (hwm->total_cols > w + hpad)) | ++ BITS(VEC_MODE_FIELDS_PER_FRAME_MINUS1, hwm->interlaced) | ++ BITS(VEC_MODE_FIRST_FIELD_ODD, hwm->first_field_odd)); ++ for (i = 0; i < ARRAY_SIZE(hwm->back_end_regs); ++i) { ++ writel(hwm->back_end_regsi, ++ vec->hw_baseRP1VEC_HW_BLOCK_VEC + 0x80 + 4 * i); ++ } ++ ++ /* Apply modifications */ ++ if (tvstd == DRM_MODE_TV_MODE_NTSC_J && mode_family == 0) { ++ /* Reduce pedestal (not quite to zero, for FIR overshoot); increase gain */ ++ VEC_WRITE(VEC_DAC_BC, ++ BITS(VEC_DAC_BC_S11_PEDESTAL, 10) | ++ (hwm->back_end_regs(0xBC - 0x80) / 4 & ~VEC_DAC_BC_S11_PEDESTAL_BITS)); ++ VEC_WRITE(VEC_DAC_C8, ++ BITS(VEC_DAC_C8_U16_SCALE_LUMA, 0x9400) | ++ (hwm->back_end_regs(0xC8 - 0x80) / 4 & ++ ~VEC_DAC_C8_U16_SCALE_LUMA_BITS)); ++ } else if ((tvstd == DRM_MODE_TV_MODE_NTSC_443 || tvstd == DRM_MODE_TV_MODE_PAL) && ++ mode_family != 1) { ++ /* Change colour carrier frequency to 4433618.75 Hz; disable hard sync */ ++ VEC_WRITE(VEC_DAC_D4, 0xcc48c1d1); ++ VEC_WRITE(VEC_DAC_D8, 0x0a8262b2); ++ VEC_WRITE(VEC_DAC_EC, ++ hwm->back_end_regs(0xEC - 0x80) / 4 & ~VEC_DAC_EC_SEQ_EN_BITS); ++ } else if (tvstd == DRM_MODE_TV_MODE_PAL_N && mode_family == 1) { ++ /* Change colour carrier frequency to 3582056.25 Hz */ ++ VEC_WRITE(VEC_DAC_D4, 0x9ce075f7); ++ VEC_WRITE(VEC_DAC_D8, 0x087da511); ++ } ++ ++ /* Input pixel format conversion */ ++ for (i = 0; i < ARRAY_SIZE(my_formats); ++i) { ++ if (my_formatsi.format == in_format) ++ break; ++ } ++ if (i >= ARRAY_SIZE(my_formats)) { ++ dev_err(&vec->pdev->dev, "%s: bad input format\n", __func__); ++ i = 0; ++ } ++ VEC_WRITE(VEC_IMASK, my_formatsi.mask); ++ VEC_WRITE(VEC_SHIFT, my_formatsi.shift); ++ VEC_WRITE(VEC_RGBSZ, my_formatsi.rgbsz); ++ ++ VEC_WRITE(VEC_IRQ_FLAGS, 0xffffffff); ++ rp1vec_hw_vblank_ctrl(vec, 1); ++ ++ i = rp1vec_hw_busy(vec); ++ if (i) ++ dev_warn(&vec->pdev->dev, ++ "%s: VEC unexpectedly busy at start (0x%08x)", ++ __func__, VEC_READ(VEC_STATUS)); ++ ++ VEC_WRITE(VEC_CONTROL, ++ BITS(VEC_CONTROL_START_ARM, (!i)) | ++ BITS(VEC_CONTROL_AUTO_REPEAT, 1)); ++} ++ ++void rp1vec_hw_update(struct rp1_vec *vec, dma_addr_t addr, u32 offset, u32 stride) ++{ ++ /* ++ * Update STRIDE, DMAH and DMAL only. When called after rp1vec_hw_setup(), ++ * DMA starts immediately; if already running, the buffer will flip at ++ * the next vertical sync event. ++ */ ++ u64 a = addr + offset; ++ ++ VEC_WRITE(VEC_DMA_STRIDE, stride); ++ VEC_WRITE(VEC_DMA_ADDR_H, a >> 32); ++ VEC_WRITE(VEC_DMA_ADDR_L, a & 0xFFFFFFFFu); ++} ++ ++void rp1vec_hw_stop(struct rp1_vec *vec) ++{ ++ /* ++ * Stop DMA by turning off the Auto-Repeat flag, and wait up to 100ms for ++ * the current and any queued frame to end. "Force drain" flags are not used, ++ * as they seem to prevent DMA from re-starting properly; it's safer to wait. ++ */ ++ ++ reinit_completion(&vec->finished); ++ VEC_WRITE(VEC_CONTROL, 0); ++ if (!wait_for_completion_timeout(&vec->finished, HZ / 10)) ++ drm_err(&vec->drm, "%s: timed out waiting for idle\n", __func__); ++ VEC_WRITE(VEC_IRQ_ENABLES, 0); ++} ++ ++void rp1vec_hw_vblank_ctrl(struct rp1_vec *vec, int enable) ++{ ++ VEC_WRITE(VEC_IRQ_ENABLES, ++ BITS(VEC_IRQ_ENABLES_DONE, 1) | ++ BITS(VEC_IRQ_ENABLES_DMA, (enable ? 1 : 0)) | ++ BITS(VEC_IRQ_ENABLES_MATCH_ROW, 1023)); ++} ++ ++irqreturn_t rp1vec_hw_isr(int irq, void *dev) ++{ ++ struct rp1_vec *vec = dev; ++ u32 u = VEC_READ(VEC_IRQ_FLAGS); ++ ++ if (u) { ++ VEC_WRITE(VEC_IRQ_FLAGS, u); ++ if (u & VEC_IRQ_FLAGS_DMA_BITS) ++ drm_crtc_handle_vblank(&vec->pipe.crtc); ++ if (u & VEC_IRQ_FLAGS_DONE_BITS) ++ complete(&vec->finished); ++ } ++ return u ? IRQ_HANDLED : IRQ_NONE; ++} +diff --git a/drivers/gpu/drm/rp1/rp1-vec/vec_regs.h b/drivers/gpu/drm/rp1/rp1-vec/vec_regs.h +new file mode 100644 +index 000000000000..03632f2e8d4b +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-vec/vec_regs.h +@@ -0,0 +1,1420 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++// ============================================================================= ++// Copyright Raspberry Pi Ltd. 2023 ++// vrbuild version: 56aac1a23c016cbbd229108f3b6efc1343842156-clean ++// THIS FILE IS GENERATED BY VRBUILD - DO NOT EDIT ++// ============================================================================= ++// Register block : VEC ++// Version : 1 ++// Bus type : apb ++// Description : None ++// ============================================================================= ++#ifndef VEC_REGS_DEFINED ++#define VEC_REGS_DEFINED ++#define VEC_REGS_RWTYPE_MSB 13 ++#define VEC_REGS_RWTYPE_LSB 12 ++// ============================================================================= ++// Register : VEC_CONTROL ++// JTAG access : synchronous ++// Description : None ++#define VEC_CONTROL_OFFSET 0x00000000 ++#define VEC_CONTROL_BITS 0x00000007 ++#define VEC_CONTROL_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_CONTROL_BARS ++// Description : Write '1' to display colour bar test pattern ++#define VEC_CONTROL_BARS_RESET 0x0 ++#define VEC_CONTROL_BARS_BITS 0x00000004 ++#define VEC_CONTROL_BARS_MSB 2 ++#define VEC_CONTROL_BARS_LSB 2 ++#define VEC_CONTROL_BARS_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_CONTROL_AUTO_REPEAT ++// Description : Write '1' to re-display same frame continuously ++#define VEC_CONTROL_AUTO_REPEAT_RESET 0x0 ++#define VEC_CONTROL_AUTO_REPEAT_BITS 0x00000002 ++#define VEC_CONTROL_AUTO_REPEAT_MSB 1 ++#define VEC_CONTROL_AUTO_REPEAT_LSB 1 ++#define VEC_CONTROL_AUTO_REPEAT_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_CONTROL_START_ARM ++// Description : Write '1' before first DMA address is written This bit always ++// reads back as '0' ++#define VEC_CONTROL_START_ARM_RESET 0x0 ++#define VEC_CONTROL_START_ARM_BITS 0x00000001 ++#define VEC_CONTROL_START_ARM_MSB 0 ++#define VEC_CONTROL_START_ARM_LSB 0 ++#define VEC_CONTROL_START_ARM_ACCESS "SC" ++// ============================================================================= ++// Register : VEC_IRQ_ENABLES ++// JTAG access : synchronous ++// Description : None ++#define VEC_IRQ_ENABLES_OFFSET 0x00000004 ++#define VEC_IRQ_ENABLES_BITS 0x03ff003f ++#define VEC_IRQ_ENABLES_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_ENABLES_MATCH_ROW ++// Description : Raster line at which MATCH interrupt is signalled ++#define VEC_IRQ_ENABLES_MATCH_ROW_RESET 0x000 ++#define VEC_IRQ_ENABLES_MATCH_ROW_BITS 0x03ff0000 ++#define VEC_IRQ_ENABLES_MATCH_ROW_MSB 25 ++#define VEC_IRQ_ENABLES_MATCH_ROW_LSB 16 ++#define VEC_IRQ_ENABLES_MATCH_ROW_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_ENABLES_MATCH ++// Description : Output raster == match_row reached ++#define VEC_IRQ_ENABLES_MATCH_RESET 0x0 ++#define VEC_IRQ_ENABLES_MATCH_BITS 0x00000020 ++#define VEC_IRQ_ENABLES_MATCH_MSB 5 ++#define VEC_IRQ_ENABLES_MATCH_LSB 5 ++#define VEC_IRQ_ENABLES_MATCH_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_ENABLES_ERROR ++// Description : DMA address overwritten before it was taken ++#define VEC_IRQ_ENABLES_ERROR_RESET 0x0 ++#define VEC_IRQ_ENABLES_ERROR_BITS 0x00000010 ++#define VEC_IRQ_ENABLES_ERROR_MSB 4 ++#define VEC_IRQ_ENABLES_ERROR_LSB 4 ++#define VEC_IRQ_ENABLES_ERROR_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_ENABLES_DONE ++// Description : Last word sent to DAC after end of video (= all clear) ++#define VEC_IRQ_ENABLES_DONE_RESET 0x0 ++#define VEC_IRQ_ENABLES_DONE_BITS 0x00000008 ++#define VEC_IRQ_ENABLES_DONE_MSB 3 ++#define VEC_IRQ_ENABLES_DONE_LSB 3 ++#define VEC_IRQ_ENABLES_DONE_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_ENABLES_FRAME ++// Description : Start of frame ++#define VEC_IRQ_ENABLES_FRAME_RESET 0x0 ++#define VEC_IRQ_ENABLES_FRAME_BITS 0x00000004 ++#define VEC_IRQ_ENABLES_FRAME_MSB 2 ++#define VEC_IRQ_ENABLES_FRAME_LSB 2 ++#define VEC_IRQ_ENABLES_FRAME_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_ENABLES_UNDERFLOW ++// Description : Underflow has occurred ++#define VEC_IRQ_ENABLES_UNDERFLOW_RESET 0x0 ++#define VEC_IRQ_ENABLES_UNDERFLOW_BITS 0x00000002 ++#define VEC_IRQ_ENABLES_UNDERFLOW_MSB 1 ++#define VEC_IRQ_ENABLES_UNDERFLOW_LSB 1 ++#define VEC_IRQ_ENABLES_UNDERFLOW_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_ENABLES_DMA ++// Description : DMA ready to accept next frame start address ++#define VEC_IRQ_ENABLES_DMA_RESET 0x0 ++#define VEC_IRQ_ENABLES_DMA_BITS 0x00000001 ++#define VEC_IRQ_ENABLES_DMA_MSB 0 ++#define VEC_IRQ_ENABLES_DMA_LSB 0 ++#define VEC_IRQ_ENABLES_DMA_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_IRQ_FLAGS ++// JTAG access : synchronous ++// Description : None ++#define VEC_IRQ_FLAGS_OFFSET 0x00000008 ++#define VEC_IRQ_FLAGS_BITS 0x0000003f ++#define VEC_IRQ_FLAGS_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_FLAGS_MATCH ++// Description : Output raster == match_row reached ++#define VEC_IRQ_FLAGS_MATCH_RESET 0x0 ++#define VEC_IRQ_FLAGS_MATCH_BITS 0x00000020 ++#define VEC_IRQ_FLAGS_MATCH_MSB 5 ++#define VEC_IRQ_FLAGS_MATCH_LSB 5 ++#define VEC_IRQ_FLAGS_MATCH_ACCESS "WC" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_FLAGS_ERROR ++// Description : DMA address overwritten before it was taken ++#define VEC_IRQ_FLAGS_ERROR_RESET 0x0 ++#define VEC_IRQ_FLAGS_ERROR_BITS 0x00000010 ++#define VEC_IRQ_FLAGS_ERROR_MSB 4 ++#define VEC_IRQ_FLAGS_ERROR_LSB 4 ++#define VEC_IRQ_FLAGS_ERROR_ACCESS "WC" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_FLAGS_DONE ++// Description : Last word sent to DAC after end of video (= all clear) ++#define VEC_IRQ_FLAGS_DONE_RESET 0x0 ++#define VEC_IRQ_FLAGS_DONE_BITS 0x00000008 ++#define VEC_IRQ_FLAGS_DONE_MSB 3 ++#define VEC_IRQ_FLAGS_DONE_LSB 3 ++#define VEC_IRQ_FLAGS_DONE_ACCESS "WC" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_FLAGS_FRAME ++// Description : Start of frame ++#define VEC_IRQ_FLAGS_FRAME_RESET 0x0 ++#define VEC_IRQ_FLAGS_FRAME_BITS 0x00000004 ++#define VEC_IRQ_FLAGS_FRAME_MSB 2 ++#define VEC_IRQ_FLAGS_FRAME_LSB 2 ++#define VEC_IRQ_FLAGS_FRAME_ACCESS "WC" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_FLAGS_UNDERFLOW ++// Description : Underflow has occurred ++#define VEC_IRQ_FLAGS_UNDERFLOW_RESET 0x0 ++#define VEC_IRQ_FLAGS_UNDERFLOW_BITS 0x00000002 ++#define VEC_IRQ_FLAGS_UNDERFLOW_MSB 1 ++#define VEC_IRQ_FLAGS_UNDERFLOW_LSB 1 ++#define VEC_IRQ_FLAGS_UNDERFLOW_ACCESS "WC" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_FLAGS_DMA ++// Description : DMA ready to accept next frame start address ++#define VEC_IRQ_FLAGS_DMA_RESET 0x0 ++#define VEC_IRQ_FLAGS_DMA_BITS 0x00000001 ++#define VEC_IRQ_FLAGS_DMA_MSB 0 ++#define VEC_IRQ_FLAGS_DMA_LSB 0 ++#define VEC_IRQ_FLAGS_DMA_ACCESS "WC" ++// ============================================================================= ++// Register : VEC_QOS ++// JTAG access : synchronous ++// Description : This register configures panic levels for the AXI ar_qos ++// quality of service field. Panic status is driven by the number ++// of rows held in the SRAM cache: ++#define VEC_QOS_OFFSET 0x0000000c ++#define VEC_QOS_BITS 0x000fffff ++#define VEC_QOS_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_QOS_UQOS ++// Description : Upper AXI QOS ++#define VEC_QOS_UQOS_RESET 0x0 ++#define VEC_QOS_UQOS_BITS 0x000f0000 ++#define VEC_QOS_UQOS_MSB 19 ++#define VEC_QOS_UQOS_LSB 16 ++#define VEC_QOS_UQOS_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_QOS_ULEV ++// Description : Upper trip level (resolution = 1 / 16 of cache size) ++#define VEC_QOS_ULEV_RESET 0x0 ++#define VEC_QOS_ULEV_BITS 0x0000f000 ++#define VEC_QOS_ULEV_MSB 15 ++#define VEC_QOS_ULEV_LSB 12 ++#define VEC_QOS_ULEV_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_QOS_LQOS ++// Description : Lower AXI QOS ++#define VEC_QOS_LQOS_RESET 0x0 ++#define VEC_QOS_LQOS_BITS 0x00000f00 ++#define VEC_QOS_LQOS_MSB 11 ++#define VEC_QOS_LQOS_LSB 8 ++#define VEC_QOS_LQOS_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_QOS_LLEV ++// Description : Lower trip level (resolution = 1 / 16 of cache size) ++#define VEC_QOS_LLEV_RESET 0x0 ++#define VEC_QOS_LLEV_BITS 0x000000f0 ++#define VEC_QOS_LLEV_MSB 7 ++#define VEC_QOS_LLEV_LSB 4 ++#define VEC_QOS_LLEV_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_QOS_DQOS ++// Description : Default QOS ++#define VEC_QOS_DQOS_RESET 0x0 ++#define VEC_QOS_DQOS_BITS 0x0000000f ++#define VEC_QOS_DQOS_MSB 3 ++#define VEC_QOS_DQOS_LSB 0 ++#define VEC_QOS_DQOS_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DMA_ADDR_L ++// JTAG access : synchronous ++// Description : Lower 32-bits ++#define VEC_DMA_ADDR_L_OFFSET 0x00000010 ++#define VEC_DMA_ADDR_L_BITS 0xffffffff ++#define VEC_DMA_ADDR_L_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DMA_ADDR_L_AXI_ADDR ++// Description : Byte address of DMA transfer frame buffer. ++#define VEC_DMA_ADDR_L_AXI_ADDR_RESET 0x00000000 ++#define VEC_DMA_ADDR_L_AXI_ADDR_BITS 0xffffffff ++#define VEC_DMA_ADDR_L_AXI_ADDR_MSB 31 ++#define VEC_DMA_ADDR_L_AXI_ADDR_LSB 0 ++#define VEC_DMA_ADDR_L_AXI_ADDR_ACCESS "RWF" ++// ============================================================================= ++// Register : VEC_DMA_STRIDE ++// JTAG access : synchronous ++// Description : This register sets the line byte stride. ++#define VEC_DMA_STRIDE_OFFSET 0x00000014 ++#define VEC_DMA_STRIDE_BITS 0xffffffff ++#define VEC_DMA_STRIDE_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DMA_STRIDE_STRIDE ++// Description : Byte stride ++#define VEC_DMA_STRIDE_STRIDE_RESET 0x00000000 ++#define VEC_DMA_STRIDE_STRIDE_BITS 0xffffffff ++#define VEC_DMA_STRIDE_STRIDE_MSB 31 ++#define VEC_DMA_STRIDE_STRIDE_LSB 0 ++#define VEC_DMA_STRIDE_STRIDE_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DMA_AREA ++// JTAG access : synchronous ++// Description : Interlaced pixel area. See example driver code. ++#define VEC_DMA_AREA_OFFSET 0x00000018 ++#define VEC_DMA_AREA_BITS 0x03ff03ff ++#define VEC_DMA_AREA_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DMA_AREA_COLS_MINUS1 ++// Description : Width ++#define VEC_DMA_AREA_COLS_MINUS1_RESET 0x000 ++#define VEC_DMA_AREA_COLS_MINUS1_BITS 0x03ff0000 ++#define VEC_DMA_AREA_COLS_MINUS1_MSB 25 ++#define VEC_DMA_AREA_COLS_MINUS1_LSB 16 ++#define VEC_DMA_AREA_COLS_MINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1 ++// Description : Lines per field = half of lines per interlaced frame ++#define VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1_RESET 0x000 ++#define VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1_BITS 0x000003ff ++#define VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1_MSB 9 ++#define VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1_LSB 0 ++#define VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_YUV_SCALING ++// JTAG access : synchronous ++// Description : None ++#define VEC_YUV_SCALING_OFFSET 0x0000001c ++#define VEC_YUV_SCALING_BITS 0x3fffffff ++#define VEC_YUV_SCALING_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_YUV_SCALING_U10_SCALE_Y ++// Description : Y unsigned scaling factor - 8 binary places ++#define VEC_YUV_SCALING_U10_SCALE_Y_RESET 0x000 ++#define VEC_YUV_SCALING_U10_SCALE_Y_BITS 0x3ff00000 ++#define VEC_YUV_SCALING_U10_SCALE_Y_MSB 29 ++#define VEC_YUV_SCALING_U10_SCALE_Y_LSB 20 ++#define VEC_YUV_SCALING_U10_SCALE_Y_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_YUV_SCALING_S10_SCALE_U ++// Description : U signed scaling factor - 8 binary places ++#define VEC_YUV_SCALING_S10_SCALE_U_RESET 0x000 ++#define VEC_YUV_SCALING_S10_SCALE_U_BITS 0x000ffc00 ++#define VEC_YUV_SCALING_S10_SCALE_U_MSB 19 ++#define VEC_YUV_SCALING_S10_SCALE_U_LSB 10 ++#define VEC_YUV_SCALING_S10_SCALE_U_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_YUV_SCALING_S10_SCALE_V ++// Description : V signed scaling factor - 8 binary please ++#define VEC_YUV_SCALING_S10_SCALE_V_RESET 0x000 ++#define VEC_YUV_SCALING_S10_SCALE_V_BITS 0x000003ff ++#define VEC_YUV_SCALING_S10_SCALE_V_MSB 9 ++#define VEC_YUV_SCALING_S10_SCALE_V_LSB 0 ++#define VEC_YUV_SCALING_S10_SCALE_V_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_BACK_PORCH ++// JTAG access : synchronous ++// Description : None ++#define VEC_BACK_PORCH_OFFSET 0x00000020 ++#define VEC_BACK_PORCH_BITS 0x03ff03ff ++#define VEC_BACK_PORCH_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_BACK_PORCH_HBP_MINUS1 ++// Description : Horizontal back porch ++#define VEC_BACK_PORCH_HBP_MINUS1_RESET 0x000 ++#define VEC_BACK_PORCH_HBP_MINUS1_BITS 0x03ff0000 ++#define VEC_BACK_PORCH_HBP_MINUS1_MSB 25 ++#define VEC_BACK_PORCH_HBP_MINUS1_LSB 16 ++#define VEC_BACK_PORCH_HBP_MINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_BACK_PORCH_VBP_MINUS1 ++// Description : Vertical back porch ++#define VEC_BACK_PORCH_VBP_MINUS1_RESET 0x000 ++#define VEC_BACK_PORCH_VBP_MINUS1_BITS 0x000003ff ++#define VEC_BACK_PORCH_VBP_MINUS1_MSB 9 ++#define VEC_BACK_PORCH_VBP_MINUS1_LSB 0 ++#define VEC_BACK_PORCH_VBP_MINUS1_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_FRONT_PORCH ++// JTAG access : synchronous ++// Description : None ++#define VEC_FRONT_PORCH_OFFSET 0x00000024 ++#define VEC_FRONT_PORCH_BITS 0x03ff03ff ++#define VEC_FRONT_PORCH_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_FRONT_PORCH_HFP_MINUS1 ++// Description : Horizontal front porch ++#define VEC_FRONT_PORCH_HFP_MINUS1_RESET 0x000 ++#define VEC_FRONT_PORCH_HFP_MINUS1_BITS 0x03ff0000 ++#define VEC_FRONT_PORCH_HFP_MINUS1_MSB 25 ++#define VEC_FRONT_PORCH_HFP_MINUS1_LSB 16 ++#define VEC_FRONT_PORCH_HFP_MINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_FRONT_PORCH_VFP_MINUS1 ++// Description : Vertical front porch ++#define VEC_FRONT_PORCH_VFP_MINUS1_RESET 0x000 ++#define VEC_FRONT_PORCH_VFP_MINUS1_BITS 0x000003ff ++#define VEC_FRONT_PORCH_VFP_MINUS1_MSB 9 ++#define VEC_FRONT_PORCH_VFP_MINUS1_LSB 0 ++#define VEC_FRONT_PORCH_VFP_MINUS1_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_SHIFT ++// JTAG access : synchronous ++// Description : Positions of R,G,B MS bits in the memory word. Note: due to an ++// unintended red/blue swap, these fields have been renamed since ++// a previous version. There is no functional change. ++#define VEC_SHIFT_OFFSET 0x00000028 ++#define VEC_SHIFT_BITS 0x00007fff ++#define VEC_SHIFT_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_SHIFT_SHIFT_R ++// Description : Red MSB ++#define VEC_SHIFT_SHIFT_R_RESET 0x00 ++#define VEC_SHIFT_SHIFT_R_BITS 0x00007c00 ++#define VEC_SHIFT_SHIFT_R_MSB 14 ++#define VEC_SHIFT_SHIFT_R_LSB 10 ++#define VEC_SHIFT_SHIFT_R_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_SHIFT_SHIFT_G ++// Description : Green MSB ++#define VEC_SHIFT_SHIFT_G_RESET 0x00 ++#define VEC_SHIFT_SHIFT_G_BITS 0x000003e0 ++#define VEC_SHIFT_SHIFT_G_MSB 9 ++#define VEC_SHIFT_SHIFT_G_LSB 5 ++#define VEC_SHIFT_SHIFT_G_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_SHIFT_SHIFT_B ++// Description : Blue MSB ++#define VEC_SHIFT_SHIFT_B_RESET 0x00 ++#define VEC_SHIFT_SHIFT_B_BITS 0x0000001f ++#define VEC_SHIFT_SHIFT_B_MSB 4 ++#define VEC_SHIFT_SHIFT_B_LSB 0 ++#define VEC_SHIFT_SHIFT_B_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_IMASK ++// JTAG access : synchronous ++// Description : Masks for R,G,B significant bits, left-justified within 10-bit ++// fields. ++#define VEC_IMASK_OFFSET 0x0000002c ++#define VEC_IMASK_BITS 0x3fffffff ++#define VEC_IMASK_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_IMASK_MASK_R ++// Description : Red mask ++#define VEC_IMASK_MASK_R_RESET 0x000 ++#define VEC_IMASK_MASK_R_BITS 0x3ff00000 ++#define VEC_IMASK_MASK_R_MSB 29 ++#define VEC_IMASK_MASK_R_LSB 20 ++#define VEC_IMASK_MASK_R_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IMASK_MASK_G ++// Description : Green mask ++#define VEC_IMASK_MASK_G_RESET 0x000 ++#define VEC_IMASK_MASK_G_BITS 0x000ffc00 ++#define VEC_IMASK_MASK_G_MSB 19 ++#define VEC_IMASK_MASK_G_LSB 10 ++#define VEC_IMASK_MASK_G_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IMASK_MASK_B ++// Description : Blue mask ++#define VEC_IMASK_MASK_B_RESET 0x000 ++#define VEC_IMASK_MASK_B_BITS 0x000003ff ++#define VEC_IMASK_MASK_B_MSB 9 ++#define VEC_IMASK_MASK_B_LSB 0 ++#define VEC_IMASK_MASK_B_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_MODE ++// JTAG access : synchronous ++// Description : None ++#define VEC_MODE_OFFSET 0x00000030 ++#define VEC_MODE_BITS 0x01ff003f ++#define VEC_MODE_RESET 0x01c00000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_MODE_HIGH_WATER ++// Description : ALWAYS WRITE 8'hE0 ++#define VEC_MODE_HIGH_WATER_RESET 0xe0 ++#define VEC_MODE_HIGH_WATER_BITS 0x01fe0000 ++#define VEC_MODE_HIGH_WATER_MSB 24 ++#define VEC_MODE_HIGH_WATER_LSB 17 ++#define VEC_MODE_HIGH_WATER_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_MODE_ALIGN16 ++// Description : Data: 0=BYTE aligned; 1=BEAT aligned ++#define VEC_MODE_ALIGN16_RESET 0x0 ++#define VEC_MODE_ALIGN16_BITS 0x00010000 ++#define VEC_MODE_ALIGN16_MSB 16 ++#define VEC_MODE_ALIGN16_LSB 16 ++#define VEC_MODE_ALIGN16_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_MODE_VFP_EN ++// Description : Enable vertical front porch ++#define VEC_MODE_VFP_EN_RESET 0x0 ++#define VEC_MODE_VFP_EN_BITS 0x00000020 ++#define VEC_MODE_VFP_EN_MSB 5 ++#define VEC_MODE_VFP_EN_LSB 5 ++#define VEC_MODE_VFP_EN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_MODE_VBP_EN ++// Description : Enable vertical back porch ++#define VEC_MODE_VBP_EN_RESET 0x0 ++#define VEC_MODE_VBP_EN_BITS 0x00000010 ++#define VEC_MODE_VBP_EN_MSB 4 ++#define VEC_MODE_VBP_EN_LSB 4 ++#define VEC_MODE_VBP_EN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_MODE_HFP_EN ++// Description : Enable horizontal front porch ++#define VEC_MODE_HFP_EN_RESET 0x0 ++#define VEC_MODE_HFP_EN_BITS 0x00000008 ++#define VEC_MODE_HFP_EN_MSB 3 ++#define VEC_MODE_HFP_EN_LSB 3 ++#define VEC_MODE_HFP_EN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_MODE_HBP_EN ++// Description : Enable horizontal back porch ++#define VEC_MODE_HBP_EN_RESET 0x0 ++#define VEC_MODE_HBP_EN_BITS 0x00000004 ++#define VEC_MODE_HBP_EN_MSB 2 ++#define VEC_MODE_HBP_EN_LSB 2 ++#define VEC_MODE_HBP_EN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_MODE_FIELDS_PER_FRAME_MINUS1 ++// Description : Interlaced / progressive ++#define VEC_MODE_FIELDS_PER_FRAME_MINUS1_RESET 0x0 ++#define VEC_MODE_FIELDS_PER_FRAME_MINUS1_BITS 0x00000002 ++#define VEC_MODE_FIELDS_PER_FRAME_MINUS1_MSB 1 ++#define VEC_MODE_FIELDS_PER_FRAME_MINUS1_LSB 1 ++#define VEC_MODE_FIELDS_PER_FRAME_MINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_MODE_FIRST_FIELD_ODD ++// Description : Interlacing order: odd/even or even/odd ++#define VEC_MODE_FIRST_FIELD_ODD_RESET 0x0 ++#define VEC_MODE_FIRST_FIELD_ODD_BITS 0x00000001 ++#define VEC_MODE_FIRST_FIELD_ODD_MSB 0 ++#define VEC_MODE_FIRST_FIELD_ODD_LSB 0 ++#define VEC_MODE_FIRST_FIELD_ODD_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_RGBSZ ++// JTAG access : synchronous ++// Description : None ++#define VEC_RGBSZ_OFFSET 0x00000034 ++#define VEC_RGBSZ_BITS 0x00030fff ++#define VEC_RGBSZ_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1 ++// Description : Pixel stride ++#define VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1_RESET 0x0 ++#define VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1_BITS 0x00030000 ++#define VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1_MSB 17 ++#define VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1_LSB 16 ++#define VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_RGBSZ_SCALE_R ++// Description : Red number of bits for shift-and-OR scaling ++#define VEC_RGBSZ_SCALE_R_RESET 0x0 ++#define VEC_RGBSZ_SCALE_R_BITS 0x00000f00 ++#define VEC_RGBSZ_SCALE_R_MSB 11 ++#define VEC_RGBSZ_SCALE_R_LSB 8 ++#define VEC_RGBSZ_SCALE_R_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_RGBSZ_SCALE_G ++// Description : Green number of bits for shift-and-OR scaling ++#define VEC_RGBSZ_SCALE_G_RESET 0x0 ++#define VEC_RGBSZ_SCALE_G_BITS 0x000000f0 ++#define VEC_RGBSZ_SCALE_G_MSB 7 ++#define VEC_RGBSZ_SCALE_G_LSB 4 ++#define VEC_RGBSZ_SCALE_G_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_RGBSZ_SCALE_B ++// Description : Blue number of bits for shift-and-OR scaling ++#define VEC_RGBSZ_SCALE_B_RESET 0x0 ++#define VEC_RGBSZ_SCALE_B_BITS 0x0000000f ++#define VEC_RGBSZ_SCALE_B_MSB 3 ++#define VEC_RGBSZ_SCALE_B_LSB 0 ++#define VEC_RGBSZ_SCALE_B_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_PANICS ++// JTAG access : synchronous ++// Description : None ++#define VEC_PANICS_OFFSET 0x00000038 ++#define VEC_PANICS_BITS 0xffffffff ++#define VEC_PANICS_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_PANICS_UCOUNT ++// Description : Upper panic count ++#define VEC_PANICS_UCOUNT_RESET 0x0000 ++#define VEC_PANICS_UCOUNT_BITS 0xffff0000 ++#define VEC_PANICS_UCOUNT_MSB 31 ++#define VEC_PANICS_UCOUNT_LSB 16 ++#define VEC_PANICS_UCOUNT_ACCESS "WC" ++// ----------------------------------------------------------------------------- ++// Field : VEC_PANICS_LCOUNT ++// Description : Lower panic count ++#define VEC_PANICS_LCOUNT_RESET 0x0000 ++#define VEC_PANICS_LCOUNT_BITS 0x0000ffff ++#define VEC_PANICS_LCOUNT_MSB 15 ++#define VEC_PANICS_LCOUNT_LSB 0 ++#define VEC_PANICS_LCOUNT_ACCESS "WC" ++// ============================================================================= ++// Register : VEC_STATUS ++// JTAG access : synchronous ++// Description : None ++#define VEC_STATUS_OFFSET 0x0000003c ++#define VEC_STATUS_BITS 0xff000000 ++#define VEC_STATUS_RESET 0x0d000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_STATUS_VERSION ++// Description : VEC module version code ++#define VEC_STATUS_VERSION_RESET 0x0d ++#define VEC_STATUS_VERSION_BITS 0xff000000 ++#define VEC_STATUS_VERSION_MSB 31 ++#define VEC_STATUS_VERSION_LSB 24 ++#define VEC_STATUS_VERSION_ACCESS "RO" ++// ============================================================================= ++// Register : VEC_DMA_ADDR_H ++// JTAG access : synchronous ++// Description : Upper 32-bits ++#define VEC_DMA_ADDR_H_OFFSET 0x00000040 ++#define VEC_DMA_ADDR_H_BITS 0xffffffff ++#define VEC_DMA_ADDR_H_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DMA_ADDR_H_AXI_ADDR ++// Description : Byte address of DMA transfer frame buffer. ++#define VEC_DMA_ADDR_H_AXI_ADDR_RESET 0x00000000 ++#define VEC_DMA_ADDR_H_AXI_ADDR_BITS 0xffffffff ++#define VEC_DMA_ADDR_H_AXI_ADDR_MSB 31 ++#define VEC_DMA_ADDR_H_AXI_ADDR_LSB 0 ++#define VEC_DMA_ADDR_H_AXI_ADDR_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_BURST_ADDR_L ++// JTAG access : synchronous ++// Description : None ++#define VEC_BURST_ADDR_L_OFFSET 0x00000044 ++#define VEC_BURST_ADDR_L_BITS 0xffffffff ++#define VEC_BURST_ADDR_L_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_BURST_ADDR_L_BURST_ADDR ++// Description : the lower 32-bits of the most recent read request sent to AXI ++// memory. ++#define VEC_BURST_ADDR_L_BURST_ADDR_RESET 0x00000000 ++#define VEC_BURST_ADDR_L_BURST_ADDR_BITS 0xffffffff ++#define VEC_BURST_ADDR_L_BURST_ADDR_MSB 31 ++#define VEC_BURST_ADDR_L_BURST_ADDR_LSB 0 ++#define VEC_BURST_ADDR_L_BURST_ADDR_ACCESS "RO" ++// ============================================================================= ++// Register : VEC_APB_TIMEOUT ++// JTAG access : synchronous ++// Description : None ++#define VEC_APB_TIMEOUT_OFFSET 0x00000048 ++#define VEC_APB_TIMEOUT_BITS 0x000103ff ++#define VEC_APB_TIMEOUT_RESET 0x00000014 ++// ----------------------------------------------------------------------------- ++// Field : VEC_APB_TIMEOUT_SLVERR_EN ++// Description : 1 = Assert PREADY and PSLVERR on timeout 0 = Assert PREADY only ++#define VEC_APB_TIMEOUT_SLVERR_EN_RESET 0x0 ++#define VEC_APB_TIMEOUT_SLVERR_EN_BITS 0x00010000 ++#define VEC_APB_TIMEOUT_SLVERR_EN_MSB 16 ++#define VEC_APB_TIMEOUT_SLVERR_EN_LSB 16 ++#define VEC_APB_TIMEOUT_SLVERR_EN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_APB_TIMEOUT_TIMEOUT ++// Description : Maximum AXI clock cycles to wait for responses from DAC clock ++// domain APB block ++#define VEC_APB_TIMEOUT_TIMEOUT_RESET 0x014 ++#define VEC_APB_TIMEOUT_TIMEOUT_BITS 0x000003ff ++#define VEC_APB_TIMEOUT_TIMEOUT_MSB 9 ++#define VEC_APB_TIMEOUT_TIMEOUT_LSB 0 ++#define VEC_APB_TIMEOUT_TIMEOUT_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_80 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_80_OFFSET 0x00000080 ++#define VEC_DAC_80_BITS 0x3fff3fff ++#define VEC_DAC_80_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_80_U14_DE_BGN ++// Description : Beginning of active data enable within each visible line ++#define VEC_DAC_80_U14_DE_BGN_RESET 0x0000 ++#define VEC_DAC_80_U14_DE_BGN_BITS 0x3fff0000 ++#define VEC_DAC_80_U14_DE_BGN_MSB 29 ++#define VEC_DAC_80_U14_DE_BGN_LSB 16 ++#define VEC_DAC_80_U14_DE_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_80_U14_DE_END ++// Description : End of active data enable within each visible line ++#define VEC_DAC_80_U14_DE_END_RESET 0x0000 ++#define VEC_DAC_80_U14_DE_END_BITS 0x00003fff ++#define VEC_DAC_80_U14_DE_END_MSB 13 ++#define VEC_DAC_80_U14_DE_END_LSB 0 ++#define VEC_DAC_80_U14_DE_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_84 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_84_OFFSET 0x00000084 ++#define VEC_DAC_84_BITS 0x1fff1fff ++#define VEC_DAC_84_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_84_U13_ACTIVE_RISE ++// Description : Horizontal blanking interval ++#define VEC_DAC_84_U13_ACTIVE_RISE_RESET 0x0000 ++#define VEC_DAC_84_U13_ACTIVE_RISE_BITS 0x1fff0000 ++#define VEC_DAC_84_U13_ACTIVE_RISE_MSB 28 ++#define VEC_DAC_84_U13_ACTIVE_RISE_LSB 16 ++#define VEC_DAC_84_U13_ACTIVE_RISE_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_84_U13_ACTIVE_FALL ++// Description : Horizontal blanking interval ++#define VEC_DAC_84_U13_ACTIVE_FALL_RESET 0x0000 ++#define VEC_DAC_84_U13_ACTIVE_FALL_BITS 0x00001fff ++#define VEC_DAC_84_U13_ACTIVE_FALL_MSB 12 ++#define VEC_DAC_84_U13_ACTIVE_FALL_LSB 0 ++#define VEC_DAC_84_U13_ACTIVE_FALL_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_88 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_88_OFFSET 0x00000088 ++#define VEC_DAC_88_BITS 0x1fff1fff ++#define VEC_DAC_88_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_88_U13_HALF_LINE_PERIOD ++// Description : Ratio of DAC clock to horizontal line rate, halved ++#define VEC_DAC_88_U13_HALF_LINE_PERIOD_RESET 0x0000 ++#define VEC_DAC_88_U13_HALF_LINE_PERIOD_BITS 0x1fff0000 ++#define VEC_DAC_88_U13_HALF_LINE_PERIOD_MSB 28 ++#define VEC_DAC_88_U13_HALF_LINE_PERIOD_LSB 16 ++#define VEC_DAC_88_U13_HALF_LINE_PERIOD_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_88_U13_HORZ_SYNC ++// Description : Width of horizontal sync pulses ++#define VEC_DAC_88_U13_HORZ_SYNC_RESET 0x0000 ++#define VEC_DAC_88_U13_HORZ_SYNC_BITS 0x00001fff ++#define VEC_DAC_88_U13_HORZ_SYNC_MSB 12 ++#define VEC_DAC_88_U13_HORZ_SYNC_LSB 0 ++#define VEC_DAC_88_U13_HORZ_SYNC_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_8C ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_8C_OFFSET 0x0000008c ++#define VEC_DAC_8C_BITS 0x1fff1fff ++#define VEC_DAC_8C_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_8C_U13_BURST_RISE ++// Description : Start of raised-cosine colour burst envelope ++#define VEC_DAC_8C_U13_BURST_RISE_RESET 0x0000 ++#define VEC_DAC_8C_U13_BURST_RISE_BITS 0x1fff0000 ++#define VEC_DAC_8C_U13_BURST_RISE_MSB 28 ++#define VEC_DAC_8C_U13_BURST_RISE_LSB 16 ++#define VEC_DAC_8C_U13_BURST_RISE_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_8C_U13_BURST_FALL ++// Description : End of raised-cosine colour burst envelope ++#define VEC_DAC_8C_U13_BURST_FALL_RESET 0x0000 ++#define VEC_DAC_8C_U13_BURST_FALL_BITS 0x00001fff ++#define VEC_DAC_8C_U13_BURST_FALL_MSB 12 ++#define VEC_DAC_8C_U13_BURST_FALL_LSB 0 ++#define VEC_DAC_8C_U13_BURST_FALL_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_90 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_90_OFFSET 0x00000090 ++#define VEC_DAC_90_BITS 0x1fff3fff ++#define VEC_DAC_90_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_90_U13_VERT_EQ ++// Description : Width of vertical equalisation pulses (= half line minus ++// serration) ++#define VEC_DAC_90_U13_VERT_EQ_RESET 0x0000 ++#define VEC_DAC_90_U13_VERT_EQ_BITS 0x1fff0000 ++#define VEC_DAC_90_U13_VERT_EQ_MSB 28 ++#define VEC_DAC_90_U13_VERT_EQ_LSB 16 ++#define VEC_DAC_90_U13_VERT_EQ_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_90_U14_VERT_SYNC ++// Description : Width of vertical sync pulses ++#define VEC_DAC_90_U14_VERT_SYNC_RESET 0x0000 ++#define VEC_DAC_90_U14_VERT_SYNC_BITS 0x00003fff ++#define VEC_DAC_90_U14_VERT_SYNC_MSB 13 ++#define VEC_DAC_90_U14_VERT_SYNC_LSB 0 ++#define VEC_DAC_90_U14_VERT_SYNC_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_94 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_94_OFFSET 0x00000094 ++#define VEC_DAC_94_BITS 0x03ff03ff ++#define VEC_DAC_94_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_94_U10_PRE_EQ_BGN ++// Description : Half-lines, inclusive, relative to field datum, where vertical ++// pre-equalisation pulses start ++#define VEC_DAC_94_U10_PRE_EQ_BGN_RESET 0x000 ++#define VEC_DAC_94_U10_PRE_EQ_BGN_BITS 0x03ff0000 ++#define VEC_DAC_94_U10_PRE_EQ_BGN_MSB 25 ++#define VEC_DAC_94_U10_PRE_EQ_BGN_LSB 16 ++#define VEC_DAC_94_U10_PRE_EQ_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_94_U10_PRE_EQ_END ++// Description : Half-lines, inclusive, relative to field datum, where vertical ++// pre-equalisation pulses end ++#define VEC_DAC_94_U10_PRE_EQ_END_RESET 0x000 ++#define VEC_DAC_94_U10_PRE_EQ_END_BITS 0x000003ff ++#define VEC_DAC_94_U10_PRE_EQ_END_MSB 9 ++#define VEC_DAC_94_U10_PRE_EQ_END_LSB 0 ++#define VEC_DAC_94_U10_PRE_EQ_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_98 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_98_OFFSET 0x00000098 ++#define VEC_DAC_98_BITS 0x03ff03ff ++#define VEC_DAC_98_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_98_U10_FIELD_SYNC_BGN ++// Description : Half-lines containing vertical sync pulses (inclusive) ++#define VEC_DAC_98_U10_FIELD_SYNC_BGN_RESET 0x000 ++#define VEC_DAC_98_U10_FIELD_SYNC_BGN_BITS 0x03ff0000 ++#define VEC_DAC_98_U10_FIELD_SYNC_BGN_MSB 25 ++#define VEC_DAC_98_U10_FIELD_SYNC_BGN_LSB 16 ++#define VEC_DAC_98_U10_FIELD_SYNC_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_98_U10_FIELD_SYNC_END ++// Description : Half-lines containing vertical sync pulses (inclusive) ++#define VEC_DAC_98_U10_FIELD_SYNC_END_RESET 0x000 ++#define VEC_DAC_98_U10_FIELD_SYNC_END_BITS 0x000003ff ++#define VEC_DAC_98_U10_FIELD_SYNC_END_MSB 9 ++#define VEC_DAC_98_U10_FIELD_SYNC_END_LSB 0 ++#define VEC_DAC_98_U10_FIELD_SYNC_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_9C ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_9C_OFFSET 0x0000009c ++#define VEC_DAC_9C_BITS 0x03ff03ff ++#define VEC_DAC_9C_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_9C_U10_POST_EQ_BGN ++// Description : Half-lines containing vertical post-equalisation pulses ++#define VEC_DAC_9C_U10_POST_EQ_BGN_RESET 0x000 ++#define VEC_DAC_9C_U10_POST_EQ_BGN_BITS 0x03ff0000 ++#define VEC_DAC_9C_U10_POST_EQ_BGN_MSB 25 ++#define VEC_DAC_9C_U10_POST_EQ_BGN_LSB 16 ++#define VEC_DAC_9C_U10_POST_EQ_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_9C_U10_POST_EQ_END ++// Description : Half-lines containing vertical post-equalisation pulses ++#define VEC_DAC_9C_U10_POST_EQ_END_RESET 0x000 ++#define VEC_DAC_9C_U10_POST_EQ_END_BITS 0x000003ff ++#define VEC_DAC_9C_U10_POST_EQ_END_MSB 9 ++#define VEC_DAC_9C_U10_POST_EQ_END_LSB 0 ++#define VEC_DAC_9C_U10_POST_EQ_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_A0 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_A0_OFFSET 0x000000a0 ++#define VEC_DAC_A0_BITS 0x03ff03ff ++#define VEC_DAC_A0_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_A0_U10_FLD1_BURST_BGN ++// Description : First and last full frame lines (1-based numbering) within the ++// PAL/NTSC four field sequence which require a colour burst ++#define VEC_DAC_A0_U10_FLD1_BURST_BGN_RESET 0x000 ++#define VEC_DAC_A0_U10_FLD1_BURST_BGN_BITS 0x03ff0000 ++#define VEC_DAC_A0_U10_FLD1_BURST_BGN_MSB 25 ++#define VEC_DAC_A0_U10_FLD1_BURST_BGN_LSB 16 ++#define VEC_DAC_A0_U10_FLD1_BURST_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_A0_U10_FLD1_BURST_END ++// Description : First and last full frame lines (1-based numbering) within the ++// PAL/NTSC four field sequence which require a colour burst ++#define VEC_DAC_A0_U10_FLD1_BURST_END_RESET 0x000 ++#define VEC_DAC_A0_U10_FLD1_BURST_END_BITS 0x000003ff ++#define VEC_DAC_A0_U10_FLD1_BURST_END_MSB 9 ++#define VEC_DAC_A0_U10_FLD1_BURST_END_LSB 0 ++#define VEC_DAC_A0_U10_FLD1_BURST_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_A4 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_A4_OFFSET 0x000000a4 ++#define VEC_DAC_A4_BITS 0x03ff03ff ++#define VEC_DAC_A4_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_A4_U10_FLD2_BURST_BGN ++// Description : First and last full frame lines (1-based numbering) within the ++// PAL/NTSC four field sequence which require a colour burst ++#define VEC_DAC_A4_U10_FLD2_BURST_BGN_RESET 0x000 ++#define VEC_DAC_A4_U10_FLD2_BURST_BGN_BITS 0x03ff0000 ++#define VEC_DAC_A4_U10_FLD2_BURST_BGN_MSB 25 ++#define VEC_DAC_A4_U10_FLD2_BURST_BGN_LSB 16 ++#define VEC_DAC_A4_U10_FLD2_BURST_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_A4_U10_FLD2_BURST_END ++// Description : First and last full frame lines (1-based numbering) within the ++// PAL/NTSC four field sequence which require a colour burst ++#define VEC_DAC_A4_U10_FLD2_BURST_END_RESET 0x000 ++#define VEC_DAC_A4_U10_FLD2_BURST_END_BITS 0x000003ff ++#define VEC_DAC_A4_U10_FLD2_BURST_END_MSB 9 ++#define VEC_DAC_A4_U10_FLD2_BURST_END_LSB 0 ++#define VEC_DAC_A4_U10_FLD2_BURST_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_A8 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_A8_OFFSET 0x000000a8 ++#define VEC_DAC_A8_BITS 0x03ff03ff ++#define VEC_DAC_A8_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_A8_U10_FLD3_BURST_BGN ++// Description : First and last full frame lines (1-based numbering) within the ++// PAL/NTSC four field sequence which require a colour burst ++#define VEC_DAC_A8_U10_FLD3_BURST_BGN_RESET 0x000 ++#define VEC_DAC_A8_U10_FLD3_BURST_BGN_BITS 0x03ff0000 ++#define VEC_DAC_A8_U10_FLD3_BURST_BGN_MSB 25 ++#define VEC_DAC_A8_U10_FLD3_BURST_BGN_LSB 16 ++#define VEC_DAC_A8_U10_FLD3_BURST_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_A8_U10_FLD3_BURST_END ++// Description : First and last full frame lines (1-based numbering) within the ++// PAL/NTSC four field sequence which require a colour burst ++#define VEC_DAC_A8_U10_FLD3_BURST_END_RESET 0x000 ++#define VEC_DAC_A8_U10_FLD3_BURST_END_BITS 0x000003ff ++#define VEC_DAC_A8_U10_FLD3_BURST_END_MSB 9 ++#define VEC_DAC_A8_U10_FLD3_BURST_END_LSB 0 ++#define VEC_DAC_A8_U10_FLD3_BURST_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_AC ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_AC_OFFSET 0x000000ac ++#define VEC_DAC_AC_BITS 0x03ff03ff ++#define VEC_DAC_AC_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_AC_U10_FLD4_BURST_BGN ++// Description : First and last full frame lines (1-based numbering) within the ++// PAL/NTSC four field sequence which require a colour burst ++#define VEC_DAC_AC_U10_FLD4_BURST_BGN_RESET 0x000 ++#define VEC_DAC_AC_U10_FLD4_BURST_BGN_BITS 0x03ff0000 ++#define VEC_DAC_AC_U10_FLD4_BURST_BGN_MSB 25 ++#define VEC_DAC_AC_U10_FLD4_BURST_BGN_LSB 16 ++#define VEC_DAC_AC_U10_FLD4_BURST_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_AC_U10_FLD4_BURST_END ++// Description : First and last full frame lines (1-based numbering) within the ++// PAL/NTSC four field sequence which require a colour burst ++#define VEC_DAC_AC_U10_FLD4_BURST_END_RESET 0x000 ++#define VEC_DAC_AC_U10_FLD4_BURST_END_BITS 0x000003ff ++#define VEC_DAC_AC_U10_FLD4_BURST_END_MSB 9 ++#define VEC_DAC_AC_U10_FLD4_BURST_END_LSB 0 ++#define VEC_DAC_AC_U10_FLD4_BURST_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_B0 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_B0_OFFSET 0x000000b0 ++#define VEC_DAC_B0_BITS 0x03ff03ff ++#define VEC_DAC_B0_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_B0_U10_FLD24_FULL_LINE_BGN ++// Description : First and last full visible lines (1-based numbering) in the ++// PAL/NTSC four field sequence ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_BGN_RESET 0x000 ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_BGN_BITS 0x03ff0000 ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_BGN_MSB 25 ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_BGN_LSB 16 ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_B0_U10_FLD24_FULL_LINE_END ++// Description : First and last full visible lines (1-based numbering) in the ++// PAL/NTSC four field sequence ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_END_RESET 0x000 ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_END_BITS 0x000003ff ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_END_MSB 9 ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_END_LSB 0 ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_B4 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_B4_OFFSET 0x000000b4 ++#define VEC_DAC_B4_BITS 0x03ff03ff ++#define VEC_DAC_B4_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_B4_U10_FLD13_FULL_LINE_BGN ++// Description : First and last full visible lines (1-based numbering) in the ++// PAL/NTSC four field sequence ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_BGN_RESET 0x000 ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_BGN_BITS 0x03ff0000 ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_BGN_MSB 25 ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_BGN_LSB 16 ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_B4_U10_FLD13_FULL_LINE_END ++// Description : First and last full visible lines (1-based numbering) in the ++// PAL/NTSC four field sequence ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_END_RESET 0x000 ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_END_BITS 0x000003ff ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_END_MSB 9 ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_END_LSB 0 ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_B8 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_B8_OFFSET 0x000000b8 ++#define VEC_DAC_B8_BITS 0x03ff03ff ++#define VEC_DAC_B8_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_B8_U10_BOT_HALF_LINE ++// Description : Top and bottom visible half-lines in 1-based standard full ++// frame numbering, for interlaced modes. Set to zero to disable. ++#define VEC_DAC_B8_U10_BOT_HALF_LINE_RESET 0x000 ++#define VEC_DAC_B8_U10_BOT_HALF_LINE_BITS 0x03ff0000 ++#define VEC_DAC_B8_U10_BOT_HALF_LINE_MSB 25 ++#define VEC_DAC_B8_U10_BOT_HALF_LINE_LSB 16 ++#define VEC_DAC_B8_U10_BOT_HALF_LINE_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_B8_U10_TOP_HALF_LINE ++// Description : Top and bottom visible half-lines in 1-based standard full ++// frame numbering, for interlaced modes. Set to zero to disable. ++#define VEC_DAC_B8_U10_TOP_HALF_LINE_RESET 0x000 ++#define VEC_DAC_B8_U10_TOP_HALF_LINE_BITS 0x000003ff ++#define VEC_DAC_B8_U10_TOP_HALF_LINE_MSB 9 ++#define VEC_DAC_B8_U10_TOP_HALF_LINE_LSB 0 ++#define VEC_DAC_B8_U10_TOP_HALF_LINE_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_BC ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_BC_OFFSET 0x000000bc ++#define VEC_DAC_BC_BITS 0x07ff07ff ++#define VEC_DAC_BC_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_BC_S11_PEDESTAL ++// Description : NTSC pedestal. For 7.5 IRE, this field is 1024 * 7.5/100. For ++// PAL, or Japanese NTSC, this field should be zero. ++#define VEC_DAC_BC_S11_PEDESTAL_RESET 0x000 ++#define VEC_DAC_BC_S11_PEDESTAL_BITS 0x07ff0000 ++#define VEC_DAC_BC_S11_PEDESTAL_MSB 26 ++#define VEC_DAC_BC_S11_PEDESTAL_LSB 16 ++#define VEC_DAC_BC_S11_PEDESTAL_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_BC_U11_HALF_LINES_PER_FIELD ++// Description : Mode = 625 PAL, Lines per field = 312.5, ++// u11_half_lines_per_field = 1+2*312 Mode = 525 NTSC, Lines per ++// field = 262.5, u11_half_lines_per_field = 1+2*262 ++#define VEC_DAC_BC_U11_HALF_LINES_PER_FIELD_RESET 0x000 ++#define VEC_DAC_BC_U11_HALF_LINES_PER_FIELD_BITS 0x000007ff ++#define VEC_DAC_BC_U11_HALF_LINES_PER_FIELD_MSB 10 ++#define VEC_DAC_BC_U11_HALF_LINES_PER_FIELD_LSB 0 ++#define VEC_DAC_BC_U11_HALF_LINES_PER_FIELD_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_C0 ++// JTAG access : synchronous ++// Description : Synopsis DesignWare control ++#define VEC_DAC_C0_OFFSET 0x000000c0 ++#define VEC_DAC_C0_BITS 0x000fffff ++#define VEC_DAC_C0_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C0_DWC_CABLE_ENCTR3 ++// Description : Synopsis test input ++#define VEC_DAC_C0_DWC_CABLE_ENCTR3_RESET 0x0 ++#define VEC_DAC_C0_DWC_CABLE_ENCTR3_BITS 0x00080000 ++#define VEC_DAC_C0_DWC_CABLE_ENCTR3_MSB 19 ++#define VEC_DAC_C0_DWC_CABLE_ENCTR3_LSB 19 ++#define VEC_DAC_C0_DWC_CABLE_ENCTR3_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C0_DWC_CABLE_CABLEOUT ++// Description : cable detect state ++#define VEC_DAC_C0_DWC_CABLE_CABLEOUT_RESET 0x0 ++#define VEC_DAC_C0_DWC_CABLE_CABLEOUT_BITS 0x00070000 ++#define VEC_DAC_C0_DWC_CABLE_CABLEOUT_MSB 18 ++#define VEC_DAC_C0_DWC_CABLE_CABLEOUT_LSB 16 ++#define VEC_DAC_C0_DWC_CABLE_CABLEOUT_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C0_DWC_MUX_2 ++// Description : Select DAC channel 2 output ++#define VEC_DAC_C0_DWC_MUX_2_RESET 0x0 ++#define VEC_DAC_C0_DWC_MUX_2_BITS 0x0000c000 ++#define VEC_DAC_C0_DWC_MUX_2_MSB 15 ++#define VEC_DAC_C0_DWC_MUX_2_LSB 14 ++#define VEC_DAC_C0_DWC_MUX_2_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C0_DWC_MUX_1 ++// Description : Select DAC channel 1 output ++#define VEC_DAC_C0_DWC_MUX_1_RESET 0x0 ++#define VEC_DAC_C0_DWC_MUX_1_BITS 0x00003000 ++#define VEC_DAC_C0_DWC_MUX_1_MSB 13 ++#define VEC_DAC_C0_DWC_MUX_1_LSB 12 ++#define VEC_DAC_C0_DWC_MUX_1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C0_DWC_MUX_0 ++// Description : Select DAC channel 0 output ++#define VEC_DAC_C0_DWC_MUX_0_RESET 0x0 ++#define VEC_DAC_C0_DWC_MUX_0_BITS 0x00000c00 ++#define VEC_DAC_C0_DWC_MUX_0_MSB 11 ++#define VEC_DAC_C0_DWC_MUX_0_LSB 10 ++#define VEC_DAC_C0_DWC_MUX_0_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C0_DWC_TEST ++// Description : Fixed DAC command word ++#define VEC_DAC_C0_DWC_TEST_RESET 0x000 ++#define VEC_DAC_C0_DWC_TEST_BITS 0x000003ff ++#define VEC_DAC_C0_DWC_TEST_MSB 9 ++#define VEC_DAC_C0_DWC_TEST_LSB 0 ++#define VEC_DAC_C0_DWC_TEST_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_C4 ++// JTAG access : synchronous ++// Description : Synopsis DAC control ++#define VEC_DAC_C4_OFFSET 0x000000c4 ++#define VEC_DAC_C4_BITS 0x1fffffff ++#define VEC_DAC_C4_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C4_ENCTR ++// Description : Always write3'b000 ++#define VEC_DAC_C4_ENCTR_RESET 0x0 ++#define VEC_DAC_C4_ENCTR_BITS 0x1c000000 ++#define VEC_DAC_C4_ENCTR_MSB 28 ++#define VEC_DAC_C4_ENCTR_LSB 26 ++#define VEC_DAC_C4_ENCTR_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C4_ENSC ++// Description : Enable cable detect - write 3'b000 ++#define VEC_DAC_C4_ENSC_RESET 0x0 ++#define VEC_DAC_C4_ENSC_BITS 0x03800000 ++#define VEC_DAC_C4_ENSC_MSB 25 ++#define VEC_DAC_C4_ENSC_LSB 23 ++#define VEC_DAC_C4_ENSC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C4_ENDAC ++// Description : Enable DAC channel ++#define VEC_DAC_C4_ENDAC_RESET 0x0 ++#define VEC_DAC_C4_ENDAC_BITS 0x00700000 ++#define VEC_DAC_C4_ENDAC_MSB 22 ++#define VEC_DAC_C4_ENDAC_LSB 20 ++#define VEC_DAC_C4_ENDAC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C4_ENVBG ++// Description : Enable internal bandgap reference - write '1' ++#define VEC_DAC_C4_ENVBG_RESET 0x0 ++#define VEC_DAC_C4_ENVBG_BITS 0x00080000 ++#define VEC_DAC_C4_ENVBG_MSB 19 ++#define VEC_DAC_C4_ENVBG_LSB 19 ++#define VEC_DAC_C4_ENVBG_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C4_ENEXTREF ++// Description : Enable external reference - write '0' ++#define VEC_DAC_C4_ENEXTREF_RESET 0x0 ++#define VEC_DAC_C4_ENEXTREF_BITS 0x00040000 ++#define VEC_DAC_C4_ENEXTREF_MSB 18 ++#define VEC_DAC_C4_ENEXTREF_LSB 18 ++#define VEC_DAC_C4_ENEXTREF_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C4_DAC2GC ++// Description : DAC channel 2 gain control - write 6'd63 ++#define VEC_DAC_C4_DAC2GC_RESET 0x00 ++#define VEC_DAC_C4_DAC2GC_BITS 0x0003f000 ++#define VEC_DAC_C4_DAC2GC_MSB 17 ++#define VEC_DAC_C4_DAC2GC_LSB 12 ++#define VEC_DAC_C4_DAC2GC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C4_DAC1GC ++// Description : DAC channel 1 gain control - write 6'd63 ++#define VEC_DAC_C4_DAC1GC_RESET 0x00 ++#define VEC_DAC_C4_DAC1GC_BITS 0x00000fc0 ++#define VEC_DAC_C4_DAC1GC_MSB 11 ++#define VEC_DAC_C4_DAC1GC_LSB 6 ++#define VEC_DAC_C4_DAC1GC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C4_DAC0GC ++// Description : DAC channel 0 gain control - write 6'd63 ++#define VEC_DAC_C4_DAC0GC_RESET 0x00 ++#define VEC_DAC_C4_DAC0GC_BITS 0x0000003f ++#define VEC_DAC_C4_DAC0GC_MSB 5 ++#define VEC_DAC_C4_DAC0GC_LSB 0 ++#define VEC_DAC_C4_DAC0GC_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_C8 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_C8_OFFSET 0x000000c8 ++#define VEC_DAC_C8_BITS 0xffffffff ++#define VEC_DAC_C8_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C8_U16_SCALE_SYNC ++// Description : Scaling applied prior to final summation to form the DAC ++// command word(s) ++#define VEC_DAC_C8_U16_SCALE_SYNC_RESET 0x0000 ++#define VEC_DAC_C8_U16_SCALE_SYNC_BITS 0xffff0000 ++#define VEC_DAC_C8_U16_SCALE_SYNC_MSB 31 ++#define VEC_DAC_C8_U16_SCALE_SYNC_LSB 16 ++#define VEC_DAC_C8_U16_SCALE_SYNC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C8_U16_SCALE_LUMA ++// Description : Scaling applied prior to final summation to form the DAC ++// command word(s) ++#define VEC_DAC_C8_U16_SCALE_LUMA_RESET 0x0000 ++#define VEC_DAC_C8_U16_SCALE_LUMA_BITS 0x0000ffff ++#define VEC_DAC_C8_U16_SCALE_LUMA_MSB 15 ++#define VEC_DAC_C8_U16_SCALE_LUMA_LSB 0 ++#define VEC_DAC_C8_U16_SCALE_LUMA_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_CC ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_CC_OFFSET 0x000000cc ++#define VEC_DAC_CC_BITS 0xffffffff ++#define VEC_DAC_CC_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_CC_S16_SCALE_BURST ++// Description : Scaling applied prior to final summation to form the DAC ++// command word(s) ++#define VEC_DAC_CC_S16_SCALE_BURST_RESET 0x0000 ++#define VEC_DAC_CC_S16_SCALE_BURST_BITS 0xffff0000 ++#define VEC_DAC_CC_S16_SCALE_BURST_MSB 31 ++#define VEC_DAC_CC_S16_SCALE_BURST_LSB 16 ++#define VEC_DAC_CC_S16_SCALE_BURST_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_CC_S16_SCALE_CHROMA ++// Description : Scaling applied prior to final summation to form the DAC ++// command word(s) ++#define VEC_DAC_CC_S16_SCALE_CHROMA_RESET 0x0000 ++#define VEC_DAC_CC_S16_SCALE_CHROMA_BITS 0x0000ffff ++#define VEC_DAC_CC_S16_SCALE_CHROMA_MSB 15 ++#define VEC_DAC_CC_S16_SCALE_CHROMA_LSB 0 ++#define VEC_DAC_CC_S16_SCALE_CHROMA_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_D0 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_D0_OFFSET 0x000000d0 ++#define VEC_DAC_D0_BITS 0xffffffff ++#define VEC_DAC_D0_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_D0_S16_OFFSET_LUMA ++// Description : These offsets are applied to the chroma and luma channels ++// before the final MUX ++#define VEC_DAC_D0_S16_OFFSET_LUMA_RESET 0x0000 ++#define VEC_DAC_D0_S16_OFFSET_LUMA_BITS 0xffff0000 ++#define VEC_DAC_D0_S16_OFFSET_LUMA_MSB 31 ++#define VEC_DAC_D0_S16_OFFSET_LUMA_LSB 16 ++#define VEC_DAC_D0_S16_OFFSET_LUMA_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_D0_S16_OFFSET_CHRO ++// Description : These offsets are applied to the chroma and luma channels ++// before the final MUX ++#define VEC_DAC_D0_S16_OFFSET_CHRO_RESET 0x0000 ++#define VEC_DAC_D0_S16_OFFSET_CHRO_BITS 0x0000ffff ++#define VEC_DAC_D0_S16_OFFSET_CHRO_MSB 15 ++#define VEC_DAC_D0_S16_OFFSET_CHRO_LSB 0 ++#define VEC_DAC_D0_S16_OFFSET_CHRO_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_D4 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_D4_OFFSET 0x000000d4 ++#define VEC_DAC_D4_BITS 0xffffffff ++#define VEC_DAC_D4_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_D4_NCO_FREQ ++// Description : This 64-bit frequency command is applied to the phase ++// accumulator of the NCO (numerically controlled oscillator) ++// which generates the colour sub-carrier. This value is computed ++// as ratio of sub-carrier frequency to DAC clock multiplied by ++// 2^64. ++#define VEC_DAC_D4_NCO_FREQ_RESET 0x00000000 ++#define VEC_DAC_D4_NCO_FREQ_BITS 0xffffffff ++#define VEC_DAC_D4_NCO_FREQ_MSB 31 ++#define VEC_DAC_D4_NCO_FREQ_LSB 0 ++#define VEC_DAC_D4_NCO_FREQ_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_D8 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_D8_OFFSET 0x000000d8 ++#define VEC_DAC_D8_BITS 0xffffffff ++#define VEC_DAC_D8_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_D8_NCO_FREQ ++// Description : This 64-bit frequency command is applied to the phase ++// accumulator of the NCO (numerically controlled oscillator) ++// which generates the colour sub-carrier. This value is computed ++// as ratio of sub-carrier frequency to DAC clock multiplied by ++// 2^64. ++#define VEC_DAC_D8_NCO_FREQ_RESET 0x00000000 ++#define VEC_DAC_D8_NCO_FREQ_BITS 0xffffffff ++#define VEC_DAC_D8_NCO_FREQ_MSB 31 ++#define VEC_DAC_D8_NCO_FREQ_LSB 0 ++#define VEC_DAC_D8_NCO_FREQ_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_DC ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_DC_OFFSET 0x000000dc ++#define VEC_DAC_DC_BITS 0xffffffff ++#define VEC_DAC_DC_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_DC_FIR_COEFF_CHROMA_0_6 ++// Description : FIR filter coefficients ++#define VEC_DAC_DC_FIR_COEFF_CHROMA_0_6_RESET 0x0000 ++#define VEC_DAC_DC_FIR_COEFF_CHROMA_0_6_BITS 0xffff0000 ++#define VEC_DAC_DC_FIR_COEFF_CHROMA_0_6_MSB 31 ++#define VEC_DAC_DC_FIR_COEFF_CHROMA_0_6_LSB 16 ++#define VEC_DAC_DC_FIR_COEFF_CHROMA_0_6_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_DC_FIR_COEFF_LUMA_0_6 ++// Description : FIR filter coefficients ++#define VEC_DAC_DC_FIR_COEFF_LUMA_0_6_RESET 0x0000 ++#define VEC_DAC_DC_FIR_COEFF_LUMA_0_6_BITS 0x0000ffff ++#define VEC_DAC_DC_FIR_COEFF_LUMA_0_6_MSB 15 ++#define VEC_DAC_DC_FIR_COEFF_LUMA_0_6_LSB 0 ++#define VEC_DAC_DC_FIR_COEFF_LUMA_0_6_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_E0 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_E0_OFFSET 0x000000e0 ++#define VEC_DAC_E0_BITS 0xffffffff ++#define VEC_DAC_E0_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_E0_FIR_COEFF_CHROMA_1_5 ++// Description : FIR filter coefficients ++#define VEC_DAC_E0_FIR_COEFF_CHROMA_1_5_RESET 0x0000 ++#define VEC_DAC_E0_FIR_COEFF_CHROMA_1_5_BITS 0xffff0000 ++#define VEC_DAC_E0_FIR_COEFF_CHROMA_1_5_MSB 31 ++#define VEC_DAC_E0_FIR_COEFF_CHROMA_1_5_LSB 16 ++#define VEC_DAC_E0_FIR_COEFF_CHROMA_1_5_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_E0_FIR_COEFF_LUMA_1_5 ++// Description : FIR filter coefficients ++#define VEC_DAC_E0_FIR_COEFF_LUMA_1_5_RESET 0x0000 ++#define VEC_DAC_E0_FIR_COEFF_LUMA_1_5_BITS 0x0000ffff ++#define VEC_DAC_E0_FIR_COEFF_LUMA_1_5_MSB 15 ++#define VEC_DAC_E0_FIR_COEFF_LUMA_1_5_LSB 0 ++#define VEC_DAC_E0_FIR_COEFF_LUMA_1_5_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_E4 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_E4_OFFSET 0x000000e4 ++#define VEC_DAC_E4_BITS 0xffffffff ++#define VEC_DAC_E4_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_E4_FIR_COEFF_CHROMA_2_4 ++// Description : FIR filter coefficients ++#define VEC_DAC_E4_FIR_COEFF_CHROMA_2_4_RESET 0x0000 ++#define VEC_DAC_E4_FIR_COEFF_CHROMA_2_4_BITS 0xffff0000 ++#define VEC_DAC_E4_FIR_COEFF_CHROMA_2_4_MSB 31 ++#define VEC_DAC_E4_FIR_COEFF_CHROMA_2_4_LSB 16 ++#define VEC_DAC_E4_FIR_COEFF_CHROMA_2_4_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_E4_FIR_COEFF_LUMA_2_4 ++// Description : FIR filter coefficients ++#define VEC_DAC_E4_FIR_COEFF_LUMA_2_4_RESET 0x0000 ++#define VEC_DAC_E4_FIR_COEFF_LUMA_2_4_BITS 0x0000ffff ++#define VEC_DAC_E4_FIR_COEFF_LUMA_2_4_MSB 15 ++#define VEC_DAC_E4_FIR_COEFF_LUMA_2_4_LSB 0 ++#define VEC_DAC_E4_FIR_COEFF_LUMA_2_4_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_E8 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_E8_OFFSET 0x000000e8 ++#define VEC_DAC_E8_BITS 0xffffffff ++#define VEC_DAC_E8_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_E8_FIR_COEFF_CHROMA_3 ++// Description : FIR filter coefficients ++#define VEC_DAC_E8_FIR_COEFF_CHROMA_3_RESET 0x0000 ++#define VEC_DAC_E8_FIR_COEFF_CHROMA_3_BITS 0xffff0000 ++#define VEC_DAC_E8_FIR_COEFF_CHROMA_3_MSB 31 ++#define VEC_DAC_E8_FIR_COEFF_CHROMA_3_LSB 16 ++#define VEC_DAC_E8_FIR_COEFF_CHROMA_3_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_E8_FIR_COEFF_LUMA_3 ++// Description : FIR filter coefficients ++#define VEC_DAC_E8_FIR_COEFF_LUMA_3_RESET 0x0000 ++#define VEC_DAC_E8_FIR_COEFF_LUMA_3_BITS 0x0000ffff ++#define VEC_DAC_E8_FIR_COEFF_LUMA_3_MSB 15 ++#define VEC_DAC_E8_FIR_COEFF_LUMA_3_LSB 0 ++#define VEC_DAC_E8_FIR_COEFF_LUMA_3_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_EC ++// JTAG access : synchronous ++// Description : Misc. control ++#define VEC_DAC_EC_OFFSET 0x000000ec ++#define VEC_DAC_EC_BITS 0x001fffff ++#define VEC_DAC_EC_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_SLOW_CLOCK ++// Description : Doubles the raised-cosine rate ++#define VEC_DAC_EC_SLOW_CLOCK_RESET 0x0 ++#define VEC_DAC_EC_SLOW_CLOCK_BITS 0x00100000 ++#define VEC_DAC_EC_SLOW_CLOCK_MSB 20 ++#define VEC_DAC_EC_SLOW_CLOCK_LSB 20 ++#define VEC_DAC_EC_SLOW_CLOCK_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_FIR_RMINUS1 ++// Description : Select 1, 3, 5 or 7 FIR taps ++#define VEC_DAC_EC_FIR_RMINUS1_RESET 0x0 ++#define VEC_DAC_EC_FIR_RMINUS1_BITS 0x000c0000 ++#define VEC_DAC_EC_FIR_RMINUS1_MSB 19 ++#define VEC_DAC_EC_FIR_RMINUS1_LSB 18 ++#define VEC_DAC_EC_FIR_RMINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_VERT_FULL_NOT_HALF ++// Description : Disable half-line pulses during VBI ++#define VEC_DAC_EC_VERT_FULL_NOT_HALF_RESET 0x0 ++#define VEC_DAC_EC_VERT_FULL_NOT_HALF_BITS 0x00020000 ++#define VEC_DAC_EC_VERT_FULL_NOT_HALF_MSB 17 ++#define VEC_DAC_EC_VERT_FULL_NOT_HALF_LSB 17 ++#define VEC_DAC_EC_VERT_FULL_NOT_HALF_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_SEQ_EN ++// Description : Enable NCO reset ++#define VEC_DAC_EC_SEQ_EN_RESET 0x0 ++#define VEC_DAC_EC_SEQ_EN_BITS 0x00010000 ++#define VEC_DAC_EC_SEQ_EN_MSB 16 ++#define VEC_DAC_EC_SEQ_EN_LSB 16 ++#define VEC_DAC_EC_SEQ_EN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_U2_FLD_MASK ++// Description : Field sequence ++#define VEC_DAC_EC_U2_FLD_MASK_RESET 0x0 ++#define VEC_DAC_EC_U2_FLD_MASK_BITS 0x0000c000 ++#define VEC_DAC_EC_U2_FLD_MASK_MSB 15 ++#define VEC_DAC_EC_U2_FLD_MASK_LSB 14 ++#define VEC_DAC_EC_U2_FLD_MASK_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_U4_SEQ_MASK ++// Description : NCO reset sequence ++#define VEC_DAC_EC_U4_SEQ_MASK_RESET 0x0 ++#define VEC_DAC_EC_U4_SEQ_MASK_BITS 0x00003c00 ++#define VEC_DAC_EC_U4_SEQ_MASK_MSB 13 ++#define VEC_DAC_EC_U4_SEQ_MASK_LSB 10 ++#define VEC_DAC_EC_U4_SEQ_MASK_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_INTERP_RATE_MINUS1 ++// Description : Interpolation rate 2<=R<=16 ++#define VEC_DAC_EC_INTERP_RATE_MINUS1_RESET 0x0 ++#define VEC_DAC_EC_INTERP_RATE_MINUS1_BITS 0x000003c0 ++#define VEC_DAC_EC_INTERP_RATE_MINUS1_MSB 9 ++#define VEC_DAC_EC_INTERP_RATE_MINUS1_LSB 6 ++#define VEC_DAC_EC_INTERP_RATE_MINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_INTERP_SHIFT_MINUS1 ++// Description : Power-of-2 scaling after interpolation ++#define VEC_DAC_EC_INTERP_SHIFT_MINUS1_RESET 0x0 ++#define VEC_DAC_EC_INTERP_SHIFT_MINUS1_BITS 0x0000003c ++#define VEC_DAC_EC_INTERP_SHIFT_MINUS1_MSB 5 ++#define VEC_DAC_EC_INTERP_SHIFT_MINUS1_LSB 2 ++#define VEC_DAC_EC_INTERP_SHIFT_MINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_FIELDS_PER_FRAME_MINUS1 ++// Description : Interlaced / progressive ++#define VEC_DAC_EC_FIELDS_PER_FRAME_MINUS1_RESET 0x0 ++#define VEC_DAC_EC_FIELDS_PER_FRAME_MINUS1_BITS 0x00000002 ++#define VEC_DAC_EC_FIELDS_PER_FRAME_MINUS1_MSB 1 ++#define VEC_DAC_EC_FIELDS_PER_FRAME_MINUS1_LSB 1 ++#define VEC_DAC_EC_FIELDS_PER_FRAME_MINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_PAL_EN ++// Description : Enable phase alternate line (PAL) mode ++#define VEC_DAC_EC_PAL_EN_RESET 0x0 ++#define VEC_DAC_EC_PAL_EN_BITS 0x00000001 ++#define VEC_DAC_EC_PAL_EN_MSB 0 ++#define VEC_DAC_EC_PAL_EN_LSB 0 ++#define VEC_DAC_EC_PAL_EN_ACCESS "RW" ++// ============================================================================= ++#endif // VEC_REGS_DEFINED +diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c +index 78272b1f9d5b..deec6acdcf64 100644 +--- a/drivers/gpu/drm/solomon/ssd130x.c ++++ b/drivers/gpu/drm/solomon/ssd130x.c +@@ -267,7 +267,7 @@ static int ssd130x_pwm_enable(struct ssd130x_device *ssd130x) + + pwm_init_state(ssd130x->pwm, &pwmstate); + pwm_set_relative_duty_cycle(&pwmstate, 50, 100); +- pwm_apply_state(ssd130x->pwm, &pwmstate); ++ pwm_apply_might_sleep(ssd130x->pwm, &pwmstate); + + /* Enable the PWM */ + pwm_enable(ssd130x->pwm); +diff --git a/drivers/gpu/drm/tiny/ili9486.c b/drivers/gpu/drm/tiny/ili9486.c +index 938bceed5999..a6bc9df206a8 100644 +--- a/drivers/gpu/drm/tiny/ili9486.c ++++ b/drivers/gpu/drm/tiny/ili9486.c +@@ -188,7 +188,6 @@ static const struct of_device_id ili9486_of_match = { + MODULE_DEVICE_TABLE(of, ili9486_of_match); + + static const struct spi_device_id ili9486_id = { +- { "ili9486", 0 }, + { "rpi-lcd-35", 0 }, + { "piscreen", 0 }, + { } +diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c +index 8b3229a37c6d..99aac01e2bbb 100644 +--- a/drivers/gpu/drm/v3d/v3d_bo.c ++++ b/drivers/gpu/drm/v3d/v3d_bo.c +@@ -37,7 +37,7 @@ void v3d_free_object(struct drm_gem_object *obj) + + mutex_lock(&v3d->bo_lock); + v3d->bo_stats.num_allocated--; +- v3d->bo_stats.pages_allocated -= obj->size >> PAGE_SHIFT; ++ v3d->bo_stats.pages_allocated -= obj->size >> V3D_MMU_PAGE_SHIFT; + mutex_unlock(&v3d->bo_lock); + + spin_lock(&v3d->mm_lock); +@@ -106,8 +106,8 @@ v3d_bo_create_finish(struct drm_gem_object *obj) + * lifetime of the BO. + */ + ret = drm_mm_insert_node_generic(&v3d->mm, &bo->node, +- obj->size >> PAGE_SHIFT, +- GMP_GRANULARITY >> PAGE_SHIFT, 0, 0); ++ obj->size >> V3D_MMU_PAGE_SHIFT, ++ GMP_GRANULARITY >> V3D_MMU_PAGE_SHIFT, 0, 0); + spin_unlock(&v3d->mm_lock); + if (ret) + return ret; +@@ -115,7 +115,7 @@ v3d_bo_create_finish(struct drm_gem_object *obj) + /* Track stats for /debug/dri/n/bo_stats. */ + mutex_lock(&v3d->bo_lock); + v3d->bo_stats.num_allocated++; +- v3d->bo_stats.pages_allocated += obj->size >> PAGE_SHIFT; ++ v3d->bo_stats.pages_allocated += obj->size >> V3D_MMU_PAGE_SHIFT; + mutex_unlock(&v3d->bo_lock); + + v3d_mmu_insert_ptes(bo); +@@ -183,7 +183,7 @@ int v3d_create_bo_ioctl(struct drm_device *dev, void *data, + if (IS_ERR(bo)) + return PTR_ERR(bo); + +- args->offset = bo->node.start << PAGE_SHIFT; ++ args->offset = bo->node.start << V3D_MMU_PAGE_SHIFT; + + ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle); + drm_gem_object_put(&bo->base.base); +@@ -228,7 +228,7 @@ int v3d_get_bo_offset_ioctl(struct drm_device *dev, void *data, } + bo = to_v3d_bo(gem_obj); +- args->offset = bo->node.start << PAGE_SHIFT; ++ args->offset = bo->node.start << V3D_MMU_PAGE_SHIFT; + + drm_gem_object_put(gem_obj); return 0; -diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c -index 4fbbf980a299..a95d88fea8d2 100644 ---- a/drivers/gpu/drm/vc4/vc4_debugfs.c -+++ b/drivers/gpu/drm/vc4/vc4_debugfs.c -@@ -7,6 +7,7 @@ - #include <linux/circ_buf.h> - #include <linux/ctype.h> +diff --git a/drivers/gpu/drm/v3d/v3d_debugfs.c b/drivers/gpu/drm/v3d/v3d_debugfs.c +index 330669f51fa7..b338dec2b68c 100644 +--- a/drivers/gpu/drm/v3d/v3d_debugfs.c ++++ b/drivers/gpu/drm/v3d/v3d_debugfs.c +@@ -6,75 +6,90 @@ #include <linux/debugfs.h> -+#include <linux/platform_device.h> + #include <linux/seq_file.h> + #include <linux/string_helpers.h> ++#include <linux/sched/clock.h> - #include "vc4_drv.h" - #include "vc4_regs.h" -@@ -26,8 +27,10 @@ vc4_debugfs_init(struct drm_minor *minor) - struct vc4_dev *vc4 = to_vc4_dev(minor->dev); - struct vc4_debugfs_info_entry *entry; + #include <drm/drm_debugfs.h> + + #include "v3d_drv.h" + #include "v3d_regs.h" + +-#define REGDEF(reg) { reg, #reg } ++#define REGDEF(min_ver, max_ver, reg) { min_ver, max_ver, reg, #reg } + struct v3d_reg_def { ++ u32 min_ver; ++ u32 max_ver; + u32 reg; + const char *name; + }; + + static const struct v3d_reg_def v3d_hub_reg_defs = { +- REGDEF(V3D_HUB_AXICFG), +- REGDEF(V3D_HUB_UIFCFG), +- REGDEF(V3D_HUB_IDENT0), +- REGDEF(V3D_HUB_IDENT1), +- REGDEF(V3D_HUB_IDENT2), +- REGDEF(V3D_HUB_IDENT3), +- REGDEF(V3D_HUB_INT_STS), +- REGDEF(V3D_HUB_INT_MSK_STS), +- +- REGDEF(V3D_MMU_CTL), +- REGDEF(V3D_MMU_VIO_ADDR), +- REGDEF(V3D_MMU_VIO_ID), +- REGDEF(V3D_MMU_DEBUG_INFO), ++ REGDEF(33, 42, V3D_HUB_AXICFG), ++ REGDEF(33, 71, V3D_HUB_UIFCFG), ++ REGDEF(33, 71, V3D_HUB_IDENT0), ++ REGDEF(33, 71, V3D_HUB_IDENT1), ++ REGDEF(33, 71, V3D_HUB_IDENT2), ++ REGDEF(33, 71, V3D_HUB_IDENT3), ++ REGDEF(33, 71, V3D_HUB_INT_STS), ++ REGDEF(33, 71, V3D_HUB_INT_MSK_STS), ++ ++ REGDEF(33, 71, V3D_MMU_CTL), ++ REGDEF(33, 71, V3D_MMU_VIO_ADDR), ++ REGDEF(33, 71, V3D_MMU_VIO_ID), ++ REGDEF(33, 71, V3D_MMU_DEBUG_INFO), ++ ++ REGDEF(71, 71, V3D_V7_GMP_STATUS), ++ REGDEF(71, 71, V3D_V7_GMP_CFG), ++ REGDEF(71, 71, V3D_V7_GMP_VIO_ADDR), + }; + + static const struct v3d_reg_def v3d_gca_reg_defs = { +- REGDEF(V3D_GCA_SAFE_SHUTDOWN), +- REGDEF(V3D_GCA_SAFE_SHUTDOWN_ACK), ++ REGDEF(33, 33, V3D_GCA_SAFE_SHUTDOWN), ++ REGDEF(33, 33, V3D_GCA_SAFE_SHUTDOWN_ACK), + }; + + static const struct v3d_reg_def v3d_core_reg_defs = { +- REGDEF(V3D_CTL_IDENT0), +- REGDEF(V3D_CTL_IDENT1), +- REGDEF(V3D_CTL_IDENT2), +- REGDEF(V3D_CTL_MISCCFG), +- REGDEF(V3D_CTL_INT_STS), +- REGDEF(V3D_CTL_INT_MSK_STS), +- REGDEF(V3D_CLE_CT0CS), +- REGDEF(V3D_CLE_CT0CA), +- REGDEF(V3D_CLE_CT0EA), +- REGDEF(V3D_CLE_CT1CS), +- REGDEF(V3D_CLE_CT1CA), +- REGDEF(V3D_CLE_CT1EA), +- +- REGDEF(V3D_PTB_BPCA), +- REGDEF(V3D_PTB_BPCS), +- +- REGDEF(V3D_GMP_STATUS), +- REGDEF(V3D_GMP_CFG), +- REGDEF(V3D_GMP_VIO_ADDR), +- +- REGDEF(V3D_ERR_FDBGO), +- REGDEF(V3D_ERR_FDBGB), +- REGDEF(V3D_ERR_FDBGS), +- REGDEF(V3D_ERR_STAT), ++ REGDEF(33, 71, V3D_CTL_IDENT0), ++ REGDEF(33, 71, V3D_CTL_IDENT1), ++ REGDEF(33, 71, V3D_CTL_IDENT2), ++ REGDEF(33, 71, V3D_CTL_MISCCFG), ++ REGDEF(33, 71, V3D_CTL_INT_STS), ++ REGDEF(33, 71, V3D_CTL_INT_MSK_STS), ++ REGDEF(33, 71, V3D_CLE_CT0CS), ++ REGDEF(33, 71, V3D_CLE_CT0CA), ++ REGDEF(33, 71, V3D_CLE_CT0EA), ++ REGDEF(33, 71, V3D_CLE_CT1CS), ++ REGDEF(33, 71, V3D_CLE_CT1CA), ++ REGDEF(33, 71, V3D_CLE_CT1EA), ++ ++ REGDEF(33, 71, V3D_PTB_BPCA), ++ REGDEF(33, 71, V3D_PTB_BPCS), ++ ++ REGDEF(33, 41, V3D_GMP_STATUS), ++ REGDEF(33, 41, V3D_GMP_CFG), ++ REGDEF(33, 41, V3D_GMP_VIO_ADDR), ++ ++ REGDEF(33, 71, V3D_ERR_FDBGO), ++ REGDEF(33, 71, V3D_ERR_FDBGB), ++ REGDEF(33, 71, V3D_ERR_FDBGS), ++ REGDEF(33, 71, V3D_ERR_STAT), + }; + + static const struct v3d_reg_def v3d_csd_reg_defs = { +- REGDEF(V3D_CSD_STATUS), +- REGDEF(V3D_CSD_CURRENT_CFG0), +- REGDEF(V3D_CSD_CURRENT_CFG1), +- REGDEF(V3D_CSD_CURRENT_CFG2), +- REGDEF(V3D_CSD_CURRENT_CFG3), +- REGDEF(V3D_CSD_CURRENT_CFG4), +- REGDEF(V3D_CSD_CURRENT_CFG5), +- REGDEF(V3D_CSD_CURRENT_CFG6), ++ REGDEF(41, 71, V3D_CSD_STATUS), ++ REGDEF(41, 41, V3D_CSD_CURRENT_CFG0), ++ REGDEF(41, 41, V3D_CSD_CURRENT_CFG1), ++ REGDEF(41, 41, V3D_CSD_CURRENT_CFG2), ++ REGDEF(41, 41, V3D_CSD_CURRENT_CFG3), ++ REGDEF(41, 41, V3D_CSD_CURRENT_CFG4), ++ REGDEF(41, 41, V3D_CSD_CURRENT_CFG5), ++ REGDEF(41, 41, V3D_CSD_CURRENT_CFG6), ++ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG0), ++ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG1), ++ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG2), ++ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG3), ++ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG4), ++ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG5), ++ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG6), ++ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG7), + }; + + static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused) +@@ -85,38 +100,41 @@ static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused) + int i, core; + + for (i = 0; i < ARRAY_SIZE(v3d_hub_reg_defs); i++) { +- seq_printf(m, "%s (0x%04x): 0x%08x\n", +- v3d_hub_reg_defsi.name, v3d_hub_reg_defsi.reg, +- V3D_READ(v3d_hub_reg_defsi.reg)); ++ const struct v3d_reg_def *def = &v3d_hub_reg_defsi; ++ ++ if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) { ++ seq_printf(m, "%s (0x%04x): 0x%08x\n", ++ def->name, def->reg, V3D_READ(def->reg)); ++ } + } + +- if (v3d->ver < 41) { +- for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) { ++ for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) { ++ const struct v3d_reg_def *def = &v3d_gca_reg_defsi; ++ ++ if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) { + seq_printf(m, "%s (0x%04x): 0x%08x\n", +- v3d_gca_reg_defsi.name, +- v3d_gca_reg_defsi.reg, +- V3D_GCA_READ(v3d_gca_reg_defsi.reg)); ++ def->name, def->reg, V3D_GCA_READ(def->reg)); + } + } + + for (core = 0; core < v3d->cores; core++) { + for (i = 0; i < ARRAY_SIZE(v3d_core_reg_defs); i++) { +- seq_printf(m, "core %d %s (0x%04x): 0x%08x\n", +- core, +- v3d_core_reg_defsi.name, +- v3d_core_reg_defsi.reg, +- V3D_CORE_READ(core, +- v3d_core_reg_defsi.reg)); ++ const struct v3d_reg_def *def = &v3d_core_reg_defsi; ++ ++ if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) { ++ seq_printf(m, "core %d %s (0x%04x): 0x%08x\n", ++ core, def->name, def->reg, ++ V3D_CORE_READ(core, def->reg)); ++ } + } -- 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 --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c -index a90f2545baee..0d4fb6818d51 100644 ---- a/drivers/gpu/drm/vc4/vc4_dpi.c -+++ b/drivers/gpu/drm/vc4/vc4_dpi.c -@@ -131,7 +131,7 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder) - struct vc4_dpi *dpi = vc4_encoder->dpi; - struct drm_connector_list_iter conn_iter; - struct drm_connector *connector = NULL, *connector_scan; -- u32 dpi_c = DPI_ENABLE | DPI_OUTPUT_ENABLE_MODE; -+ u32 dpi_c = DPI_ENABLE; +- if (v3d_has_csd(v3d)) { +- for (i = 0; i < ARRAY_SIZE(v3d_csd_reg_defs); i++) { ++ for (i = 0; i < ARRAY_SIZE(v3d_csd_reg_defs); i++) { ++ const struct v3d_reg_def *def = &v3d_csd_reg_defsi; ++ ++ if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) { + seq_printf(m, "core %d %s (0x%04x): 0x%08x\n", +- core, +- v3d_csd_reg_defsi.name, +- v3d_csd_reg_defsi.reg, +- V3D_CORE_READ(core, +- v3d_csd_reg_defsi.reg)); ++ core, def->name, def->reg, ++ V3D_CORE_READ(core, def->reg)); + } + } + } +@@ -147,8 +165,10 @@ static int v3d_v3d_debugfs_ident(struct seq_file *m, void *unused) + str_yes_no(ident2 & V3D_HUB_IDENT2_WITH_MMU)); + seq_printf(m, "TFU: %s\n", + str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TFU)); +- seq_printf(m, "TSY: %s\n", +- str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TSY)); ++ if (v3d->ver <= 42) { ++ seq_printf(m, "TSY: %s\n", ++ str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TSY)); ++ } + seq_printf(m, "MSO: %s\n", + str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_MSO)); + seq_printf(m, "L3C: %s (%dkb)\n", +@@ -177,10 +197,14 @@ static int v3d_v3d_debugfs_ident(struct seq_file *m, void *unused) + seq_printf(m, " QPUs: %d\n", nslc * qups); + seq_printf(m, " Semaphores: %d\n", + V3D_GET_FIELD(ident1, V3D_IDENT1_NSEM)); +- seq_printf(m, " BCG int: %d\n", +- (ident2 & V3D_IDENT2_BCG_INT) != 0); +- seq_printf(m, " Override TMU: %d\n", +- (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0); ++ if (v3d->ver <= 42) { ++ seq_printf(m, " BCG int: %d\n", ++ (ident2 & V3D_IDENT2_BCG_INT) != 0); ++ } ++ if (v3d->ver < 40) { ++ seq_printf(m, " Override TMU: %d\n", ++ (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0); ++ } + } + + return 0; +@@ -196,12 +220,88 @@ static int v3d_debugfs_bo_stats(struct seq_file *m, void *unused) + seq_printf(m, "allocated bos: %d\n", + v3d->bo_stats.num_allocated); + seq_printf(m, "allocated bo size (kb): %ld\n", +- (long)v3d->bo_stats.pages_allocated << (PAGE_SHIFT - 10)); ++ (long)v3d->bo_stats.pages_allocated << (V3D_MMU_PAGE_SHIFT - 10)); + mutex_unlock(&v3d->bo_lock); + + return 0; + } + ++static int v3d_debugfs_gpu_usage(struct seq_file *m, void *unused) ++{ ++ struct drm_debugfs_entry *entry = m->private; ++ struct drm_device *dev = entry->dev; ++ struct v3d_dev *v3d = to_v3d_dev(dev); ++ struct v3d_queue_stats *queue_stats; ++ enum v3d_queue queue; ++ u64 timestamp = local_clock(); ++ u64 active_runtime; ++ ++ seq_printf(m, "timestamp;%llu;\n", local_clock()); ++ seq_printf(m, "\"QUEUE\";\"JOBS\";\"RUNTIME\";\"ACTIVE\";\n"); ++ for (queue = 0; queue < V3D_MAX_QUEUES; queue++) { ++ if (!v3d->queuequeue.sched.ready) ++ continue; ++ ++ queue_stats = &v3d->gpu_queue_statsqueue; ++ mutex_lock(&queue_stats->lock); ++ v3d_sched_stats_update(queue_stats); ++ if (queue_stats->last_pid) ++ active_runtime = timestamp - queue_stats->last_exec_start; ++ else ++ active_runtime = 0; ++ ++ seq_printf(m, "%s;%d;%llu;%c;\n", ++ v3d_queue_to_string(queue), ++ queue_stats->jobs_sent, ++ queue_stats->runtime + active_runtime, ++ queue_stats->last_pid?'1':'0'); ++ mutex_unlock(&queue_stats->lock); ++ } ++ ++ return 0; ++} ++ ++static int v3d_debugfs_gpu_pid_usage(struct seq_file *m, void *unused) ++{ ++ struct drm_debugfs_entry *entry = m->private; ++ struct drm_device *dev = entry->dev; ++ struct v3d_dev *v3d = to_v3d_dev(dev); ++ struct v3d_queue_stats *queue_stats; ++ struct v3d_queue_pid_stats *cur; ++ enum v3d_queue queue; ++ u64 active_runtime; ++ u64 timestamp = local_clock(); ++ ++ seq_printf(m, "timestamp;%llu;\n", timestamp); ++ seq_printf(m, "\"QUEUE\";\"PID\",\"JOBS\";\"RUNTIME\";\"ACTIVE\";\n"); ++ for (queue = 0; queue < V3D_MAX_QUEUES; queue++) { ++ ++ if (!v3d->queuequeue.sched.ready) ++ continue; ++ ++ queue_stats = &v3d->gpu_queue_statsqueue; ++ mutex_lock(&queue_stats->lock); ++ queue_stats->gpu_pid_stats_timeout = jiffies + V3D_QUEUE_STATS_TIMEOUT; ++ v3d_sched_stats_update(queue_stats); ++ list_for_each_entry(cur, &queue_stats->pid_stats_list, list) { ++ ++ if (cur->pid == queue_stats->last_pid) ++ active_runtime = timestamp - queue_stats->last_exec_start; ++ else ++ active_runtime = 0; ++ ++ seq_printf(m, "%s;%d;%d;%llu;%c;\n", ++ v3d_queue_to_string(queue), ++ cur->pid, cur->jobs_sent, ++ cur->runtime + active_runtime, ++ cur->pid == queue_stats->last_pid ? '1' : '0'); ++ } ++ mutex_unlock(&queue_stats->lock); ++ } ++ ++ return 0; ++} ++ + static int v3d_measure_clock(struct seq_file *m, void *unused) + { + struct drm_debugfs_entry *entry = m->private; +@@ -212,8 +312,10 @@ static int v3d_measure_clock(struct seq_file *m, void *unused) + int measure_ms = 1000; + + if (v3d->ver >= 40) { ++ int cycle_count_reg = v3d->ver < 71 ? ++ V3D_PCTR_CYCLE_COUNT : V3D_V7_PCTR_CYCLE_COUNT; + V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3, +- V3D_SET_FIELD(V3D_PCTR_CYCLE_COUNT, ++ V3D_SET_FIELD(cycle_count_reg, + V3D_PCTR_S0)); + V3D_CORE_WRITE(core, V3D_V4_PCTR_0_CLR, 1); + V3D_CORE_WRITE(core, V3D_V4_PCTR_0_EN, 1); +@@ -241,6 +343,8 @@ static const struct drm_debugfs_info v3d_debugfs_list = { + {"v3d_regs", v3d_v3d_debugfs_regs, 0}, + {"measure_clock", v3d_measure_clock, 0}, + {"bo_stats", v3d_debugfs_bo_stats, 0}, ++ {"gpu_usage", v3d_debugfs_gpu_usage, 0}, ++ {"gpu_pid_usage", v3d_debugfs_gpu_pid_usage, 0}, + }; + + void +diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c +index ffbbe9d527d3..1258a47cce34 100644 +--- a/drivers/gpu/drm/v3d/v3d_drv.c ++++ b/drivers/gpu/drm/v3d/v3d_drv.c +@@ -23,6 +23,9 @@ + + #include <drm/drm_drv.h> + #include <drm/drm_managed.h> ++ ++#include <soc/bcm2835/raspberrypi-firmware.h> ++ + #include <uapi/drm/v3d_drm.h> + + #include "v3d_drv.h" +@@ -186,6 +189,7 @@ static const struct drm_driver v3d_drm_driver = { + }; + + static const struct of_device_id v3d_of_match = { ++ { .compatible = "brcm,2712-v3d" }, + { .compatible = "brcm,2711-v3d" }, + { .compatible = "brcm,7268-v3d" }, + { .compatible = "brcm,7278-v3d" }, +@@ -203,6 +207,8 @@ map_regs(struct v3d_dev *v3d, void __iomem **regs, const char *name) + static int v3d_platform_drm_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; ++ struct rpi_firmware *firmware; ++ struct device_node *node; + struct drm_device *drm; + struct v3d_dev *v3d; int ret; +@@ -256,6 +262,34 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) + } + } + ++ 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); ++ } ++ ++ node = rpi_firmware_find_node(); ++ if (!node) ++ return -EINVAL; ++ ++ firmware = rpi_firmware_get(node); ++ of_node_put(node); ++ if (!firmware) ++ return -EPROBE_DEFER; ++ ++ v3d->clk_up_rate = rpi_firmware_clk_get_max_rate(firmware, ++ RPI_FIRMWARE_V3D_CLK_ID); ++ rpi_firmware_put(firmware); ++ ++ /* 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) +@@ -281,6 +315,9 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) + if (ret) + goto irq_disable; + ++ ret = clk_set_min_rate(v3d->clk, v3d->clk_down_rate); ++ WARN_ON_ONCE(ret != 0); ++ + return 0; + + irq_disable: +diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h +index 7f664a4b2a75..c59bc83bcfc0 100644 +--- a/drivers/gpu/drm/v3d/v3d_drv.h ++++ b/drivers/gpu/drm/v3d/v3d_drv.h +@@ -19,8 +19,23 @@ struct reset_control; + + #define GMP_GRANULARITY (128 * 1024) + ++#define V3D_MMU_PAGE_SHIFT 12 ++ + #define V3D_MAX_QUEUES (V3D_CACHE_CLEAN + 1) + ++static inline char * ++v3d_queue_to_string(enum v3d_queue queue) ++{ ++ switch (queue) { ++ case V3D_BIN: return "v3d_bin"; ++ case V3D_RENDER: return "v3d_render"; ++ case V3D_TFU: return "v3d_tfu"; ++ case V3D_CSD: return "v3d_csd"; ++ case V3D_CACHE_CLEAN: return "v3d_cache_clean"; ++ } ++ return "UNKNOWN"; ++} ++ + struct v3d_queue_state { + struct drm_gpu_scheduler sched; + +@@ -28,6 +43,44 @@ struct v3d_queue_state { + u64 emit_seqno; + }; + ++struct v3d_queue_pid_stats { ++ struct list_head list; ++ u64 runtime; ++ /* Time in jiffes.to purge the stats of this process. Every time a ++ * process sends a new job to the queue, this timeout is delayed by ++ * V3D_QUEUE_STATS_TIMEOUT while the gpu_pid_stats_timeout of the ++ * queue is not reached. ++ */ ++ unsigned long timeout_purge; ++ u32 jobs_sent; ++ pid_t pid; ++}; ++ ++struct v3d_queue_stats { ++ struct mutex lock; ++ u64 last_exec_start; ++ u64 last_exec_end; ++ u64 runtime; ++ u32 jobs_sent; ++ /* Time in jiffes to stop collecting gpu stats by process. This is ++ * increased by every access to*the debugfs interface gpu_pid_usage. ++ * If the debugfs is not used stats are not collected. ++ */ ++ unsigned long gpu_pid_stats_timeout; ++ pid_t last_pid; ++ struct list_head pid_stats_list; ++}; ++ ++/* pid_stats by process (v3d_queue_pid_stats) are recorded if there is an ++ * access to the gpu_pid_usageare debugfs interface for the last ++ * V3D_QUEUE_STATS_TIMEOUT (70s). ++ * ++ * The same timeout is used to purge the stats by process for those process ++ * that have not sent jobs this period. ++ */ ++#define V3D_QUEUE_STATS_TIMEOUT (70 * HZ) ++ ++ + /* Performance monitor object. The perform lifetime is controlled by userspace + * using perfmon related ioctls. A perfmon can be attached to a submit_cl + * request, and when this is the case, HW perf counters will be activated just +@@ -76,6 +129,12 @@ struct v3d_dev { + 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. */ +@@ -141,6 +200,8 @@ struct v3d_dev { + u32 num_allocated; + u32 pages_allocated; + } bo_stats; ++ ++ struct v3d_queue_stats gpu_queue_statsV3D_MAX_QUEUES; + }; + + static inline struct v3d_dev * +@@ -238,6 +299,11 @@ struct v3d_job { + */ + struct v3d_perfmon *perfmon; + ++ /* PID of the process that submitted the job that could be used to ++ * for collecting stats by process of gpu usage. ++ */ ++ pid_t client_pid; ++ + /* Callback for the freeing of the job on refcount going to 0. */ + void (*free)(struct kref *ref); + }; +@@ -402,6 +468,7 @@ void v3d_mmu_remove_ptes(struct v3d_bo *bo); + /* v3d_sched.c */ + int v3d_sched_init(struct v3d_dev *v3d); + void v3d_sched_fini(struct v3d_dev *v3d); ++void v3d_sched_stats_update(struct v3d_queue_stats *queue_stats); + + /* v3d_perfmon.c */ + void v3d_perfmon_get(struct v3d_perfmon *perfmon); +diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c +index 2e94ce788c71..cf9016a0f3ea 100644 +--- a/drivers/gpu/drm/v3d/v3d_gem.c ++++ b/drivers/gpu/drm/v3d/v3d_gem.c +@@ -4,6 +4,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/reset.h> +@@ -18,6 +19,47 @@ + #include "v3d_regs.h" + #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_min_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_min_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) + { +@@ -47,6 +89,9 @@ v3d_init_hw_state(struct v3d_dev *v3d) + static void + v3d_idle_axi(struct v3d_dev *v3d, int core) + { ++ if (v3d->ver >= 71) ++ return; ++ + V3D_CORE_WRITE(core, V3D_GMP_CFG, V3D_GMP_CFG_STOP_REQ); + + if (wait_for((V3D_CORE_READ(core, V3D_GMP_STATUS) & +@@ -318,6 +363,7 @@ static void + v3d_job_free(struct kref *ref) + { + struct v3d_job *job = container_of(ref, struct v3d_job, refcount); ++ struct v3d_dev *v3d = job->v3d; + int i; + + if (job->bo) { +@@ -329,6 +375,8 @@ v3d_job_free(struct kref *ref) + dma_fence_put(job->irq_fence); + dma_fence_put(job->done_fence); + ++ v3d_clock_up_put(v3d); ++ + if (job->perfmon) + v3d_perfmon_put(job->perfmon); + +@@ -415,6 +463,7 @@ v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, + job = *container; + job->v3d = v3d; + job->free = free; ++ job->client_pid = current->pid; + + ret = drm_sched_job_init(&job->base, &v3d_priv->sched_entityqueue, + v3d_priv); +@@ -448,6 +497,7 @@ v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, + goto fail_deps; + } + ++ v3d_clock_up_get(v3d); + kref_init(&job->refcount); + + return 0; +@@ -1031,6 +1081,13 @@ v3d_gem_init(struct drm_device *dev) + if (ret) + return ret; + ++ 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 --git a/drivers/gpu/drm/v3d/v3d_irq.c b/drivers/gpu/drm/v3d/v3d_irq.c +index e714d5318f30..ecdd79b31e72 100644 +--- a/drivers/gpu/drm/v3d/v3d_irq.c ++++ b/drivers/gpu/drm/v3d/v3d_irq.c +@@ -14,21 +14,23 @@ + */ + + #include <linux/platform_device.h> ++#include <linux/sched/clock.h> + + #include "v3d_drv.h" + #include "v3d_regs.h" + #include "v3d_trace.h" + +-#define V3D_CORE_IRQS ((u32)(V3D_INT_OUTOMEM | \ +- V3D_INT_FLDONE | \ +- V3D_INT_FRDONE | \ +- V3D_INT_CSDDONE | \ +- V3D_INT_GMPV)) ++#define V3D_CORE_IRQS(ver) ((u32)(V3D_INT_OUTOMEM | \ ++ V3D_INT_FLDONE | \ ++ V3D_INT_FRDONE | \ ++ (ver < 71 ? V3D_INT_CSDDONE : V3D_V7_INT_CSDDONE) | \ ++ (ver < 71 ? V3D_INT_GMPV : 0))) + +-#define V3D_HUB_IRQS ((u32)(V3D_HUB_INT_MMU_WRV | \ +- V3D_HUB_INT_MMU_PTI | \ +- V3D_HUB_INT_MMU_CAP | \ +- V3D_HUB_INT_TFUC)) ++#define V3D_HUB_IRQS(ver) ((u32)(V3D_HUB_INT_MMU_WRV | \ ++ V3D_HUB_INT_MMU_PTI | \ ++ V3D_HUB_INT_MMU_CAP | \ ++ V3D_HUB_INT_TFUC | \ ++ (ver >= 71 ? V3D_V7_HUB_INT_GMPV : 0))) + + static irqreturn_t + v3d_hub_irq(int irq, void *arg); +@@ -68,7 +70,7 @@ v3d_overflow_mem_work(struct work_struct *work) + list_add_tail(&bo->unref_head, &v3d->bin_job->render->unref_list); + spin_unlock_irqrestore(&v3d->job_lock, irqflags); + +- V3D_CORE_WRITE(0, V3D_PTB_BPOA, bo->node.start << PAGE_SHIFT); ++ V3D_CORE_WRITE(0, V3D_PTB_BPOA, bo->node.start << V3D_MMU_PAGE_SHIFT); + V3D_CORE_WRITE(0, V3D_PTB_BPOS, obj->size); + + out: +@@ -100,6 +102,7 @@ v3d_irq(int irq, void *arg) + if (intsts & V3D_INT_FLDONE) { + struct v3d_fence *fence = + to_v3d_fence(v3d->bin_job->base.irq_fence); ++ v3d->gpu_queue_statsV3D_BIN.last_exec_end = local_clock(); + + trace_v3d_bcl_irq(&v3d->drm, fence->seqno); + dma_fence_signal(&fence->base); +@@ -109,15 +112,18 @@ v3d_irq(int irq, void *arg) + if (intsts & V3D_INT_FRDONE) { + struct v3d_fence *fence = + to_v3d_fence(v3d->render_job->base.irq_fence); ++ v3d->gpu_queue_statsV3D_RENDER.last_exec_end = local_clock(); + + trace_v3d_rcl_irq(&v3d->drm, fence->seqno); + dma_fence_signal(&fence->base); + status = IRQ_HANDLED; + } + +- if (intsts & V3D_INT_CSDDONE) { ++ if ((v3d->ver < 71 && (intsts & V3D_INT_CSDDONE)) || ++ (v3d->ver >= 71 && (intsts & V3D_V7_INT_CSDDONE))) { + struct v3d_fence *fence = + to_v3d_fence(v3d->csd_job->base.irq_fence); ++ v3d->gpu_queue_statsV3D_CSD.last_exec_end = local_clock(); + + trace_v3d_csd_irq(&v3d->drm, fence->seqno); + dma_fence_signal(&fence->base); +@@ -127,7 +133,7 @@ v3d_irq(int irq, void *arg) + /* We shouldn't be triggering these if we have GMP in + * always-allowed mode. + */ +- if (intsts & V3D_INT_GMPV) ++ if (v3d->ver < 71 && (intsts & V3D_INT_GMPV)) + dev_err(v3d->drm.dev, "GMP violation\n"); + + /* V3D 4.2 wires the hub and core IRQs together, so if we & +@@ -154,6 +160,7 @@ v3d_hub_irq(int irq, void *arg) + if (intsts & V3D_HUB_INT_TFUC) { + struct v3d_fence *fence = + to_v3d_fence(v3d->tfu_job->base.irq_fence); ++ v3d->gpu_queue_statsV3D_TFU.last_exec_end = local_clock(); + + trace_v3d_tfu_irq(&v3d->drm, fence->seqno); + dma_fence_signal(&fence->base); +@@ -177,6 +184,7 @@ v3d_hub_irq(int irq, void *arg) + "GMP", + }; + const char *client = "?"; ++ static int logged_error; + + V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL)); + +@@ -186,6 +194,7 @@ v3d_hub_irq(int irq, void *arg) + client = v3d41_axi_idsaxi_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) ? +@@ -194,6 +203,12 @@ v3d_hub_irq(int irq, void *arg) + ", pte invalid" : ""), + ((intsts & V3D_HUB_INT_MMU_CAP) ? + ", cap exceeded" : "")); ++ logged_error = 1; ++ status = IRQ_HANDLED; ++ } ++ ++ if (v3d->ver >= 71 && intsts & V3D_V7_HUB_INT_GMPV) { ++ dev_err(v3d->drm.dev, "GMP Violation\n"); + status = IRQ_HANDLED; + } + +@@ -211,8 +226,8 @@ v3d_irq_init(struct v3d_dev *v3d) + * for us. + */ + for (core = 0; core < v3d->cores; core++) +- V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS); +- V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS); ++ V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS(v3d->ver)); ++ V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS(v3d->ver)); + + irq1 = platform_get_irq_optional(v3d_to_pdev(v3d), 1); + if (irq1 == -EPROBE_DEFER) +@@ -256,12 +271,12 @@ v3d_irq_enable(struct v3d_dev *v3d) - /* Look up the connector attached to DPI so we can get the -@@ -148,49 +148,88 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder) + /* Enable our set of interrupts, masking out any others. */ + for (core = 0; core < v3d->cores; core++) { +- V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_SET, ~V3D_CORE_IRQS); +- V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_CLR, V3D_CORE_IRQS); ++ V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_SET, ~V3D_CORE_IRQS(v3d->ver)); ++ V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_CLR, V3D_CORE_IRQS(v3d->ver)); } - drm_connector_list_iter_end(&conn_iter); -- if (connector && connector->display_info.num_bus_formats) { -- u32 bus_format = connector->display_info.bus_formats0; +- V3D_WRITE(V3D_HUB_INT_MSK_SET, ~V3D_HUB_IRQS); +- V3D_WRITE(V3D_HUB_INT_MSK_CLR, V3D_HUB_IRQS); ++ V3D_WRITE(V3D_HUB_INT_MSK_SET, ~V3D_HUB_IRQS(v3d->ver)); ++ V3D_WRITE(V3D_HUB_INT_MSK_CLR, V3D_HUB_IRQS(v3d->ver)); + } + + void +@@ -276,8 +291,8 @@ v3d_irq_disable(struct v3d_dev *v3d) + + /* Clear any pending interrupts we might have left. */ + for (core = 0; core < v3d->cores; core++) +- V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS); +- V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS); ++ V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS(v3d->ver)); ++ V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS(v3d->ver)); + + cancel_work_sync(&v3d->overflow_mem_work); + } +diff --git a/drivers/gpu/drm/v3d/v3d_mmu.c b/drivers/gpu/drm/v3d/v3d_mmu.c +index 5a453532901f..14f3af40d6f6 100644 +--- a/drivers/gpu/drm/v3d/v3d_mmu.c ++++ b/drivers/gpu/drm/v3d/v3d_mmu.c +@@ -21,8 +21,6 @@ + #include "v3d_drv.h" + #include "v3d_regs.h" + +-#define V3D_MMU_PAGE_SHIFT 12 - -- switch (bus_format) { -- case MEDIA_BUS_FMT_RGB888_1X24: -- dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, -- DPI_FORMAT); -- break; -- case MEDIA_BUS_FMT_BGR888_1X24: -- dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, -- DPI_FORMAT); -- dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, DPI_ORDER); -- break; -- case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: -- dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_2, -- DPI_FORMAT); -- break; -- case MEDIA_BUS_FMT_RGB666_1X18: -+ if (connector) { -+ if (connector->display_info.num_bus_formats) { -+ u32 bus_format = connector->display_info.bus_formats0; -+ -+ switch (bus_format) { -+ case MEDIA_BUS_FMT_RGB888_1X24: -+ dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, -+ DPI_FORMAT); -+ break; -+ case MEDIA_BUS_FMT_BGR888_1X24: -+ dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, -+ DPI_FORMAT); -+ dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, -+ DPI_ORDER); -+ break; -+ case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: -+ 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; -+ default: -+ DRM_ERROR("Unknown media bus format %d\n", -+ bus_format); -+ fallthrough; -+ 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); -+ break; -+ case MEDIA_BUS_FMT_RGB565_1X24_CPADHI: -+ dpi_c |= VC4_SET_FIELD(DPI_FORMAT_16BIT_565_RGB_2, -+ DPI_FORMAT); + /* Note: All PTEs for the 1MB superpage must be filled with the + * superpage bit set. + */ +diff --git a/drivers/gpu/drm/v3d/v3d_regs.h b/drivers/gpu/drm/v3d/v3d_regs.h +index 3663e0d6bf76..9fbcbfedaae1 100644 +--- a/drivers/gpu/drm/v3d/v3d_regs.h ++++ b/drivers/gpu/drm/v3d/v3d_regs.h +@@ -57,6 +57,7 @@ + #define V3D_HUB_INT_MSK_STS 0x0005c + #define V3D_HUB_INT_MSK_SET 0x00060 + #define V3D_HUB_INT_MSK_CLR 0x00064 ++# define V3D_V7_HUB_INT_GMPV BIT(6) + # define V3D_HUB_INT_MMU_WRV BIT(5) + # define V3D_HUB_INT_MMU_PTI BIT(4) + # define V3D_HUB_INT_MMU_CAP BIT(3) +@@ -64,6 +65,7 @@ + # define V3D_HUB_INT_TFUC BIT(1) + # define V3D_HUB_INT_TFUF BIT(0) + ++/* GCA registers only exist in V3D < 41 */ + #define V3D_GCA_CACHE_CTRL 0x0000c + # define V3D_GCA_CACHE_CTRL_FLUSH BIT(0) + +@@ -87,6 +89,7 @@ + # define V3D_TOP_GR_BRIDGE_SW_INIT_1_V3D_CLK_108_SW_INIT BIT(0) + + #define V3D_TFU_CS 0x00400 ++#define V3D_V7_TFU_CS 0x00700 + /* Stops current job, empties input fifo. */ + # define V3D_TFU_CS_TFURST BIT(31) + # define V3D_TFU_CS_CVTCT_MASK V3D_MASK(23, 16) +@@ -96,6 +99,7 @@ + # define V3D_TFU_CS_BUSY BIT(0) + + #define V3D_TFU_SU 0x00404 ++#define V3D_V7_TFU_SU 0x00704 + /* Interrupt when FINTTHR input slots are free (0 = disabled) */ + # define V3D_TFU_SU_FINTTHR_MASK V3D_MASK(13, 8) + # define V3D_TFU_SU_FINTTHR_SHIFT 8 +@@ -107,38 +111,53 @@ + # define V3D_TFU_SU_THROTTLE_SHIFT 0 + + #define V3D_TFU_ICFG 0x00408 ++#define V3D_V7_TFU_ICFG 0x00708 + /* Interrupt when the conversion is complete. */ + # define V3D_TFU_ICFG_IOC BIT(0) + + /* Input Image Address */ + #define V3D_TFU_IIA 0x0040c ++#define V3D_V7_TFU_IIA 0x0070c + /* Input Chroma Address */ + #define V3D_TFU_ICA 0x00410 ++#define V3D_V7_TFU_ICA 0x00710 + /* Input Image Stride */ + #define V3D_TFU_IIS 0x00414 ++#define V3D_V7_TFU_IIS 0x00714 + /* Input Image U-Plane Address */ + #define V3D_TFU_IUA 0x00418 ++#define V3D_V7_TFU_IUA 0x00718 ++/* Image output config (VD 7.x only) */ ++#define V3D_V7_TFU_IOC 0x0071c + /* Output Image Address */ + #define V3D_TFU_IOA 0x0041c ++#define V3D_V7_TFU_IOA 0x00720 + /* Image Output Size */ + #define V3D_TFU_IOS 0x00420 ++#define V3D_V7_TFU_IOS 0x00724 + /* TFU YUV Coefficient 0 */ + #define V3D_TFU_COEF0 0x00424 +-/* Use these regs instead of the defaults. */ ++#define V3D_V7_TFU_COEF0 0x00728 ++/* Use these regs instead of the defaults (V3D 4.x only) */ + # define V3D_TFU_COEF0_USECOEF BIT(31) + /* TFU YUV Coefficient 1 */ + #define V3D_TFU_COEF1 0x00428 ++#define V3D_V7_TFU_COEF1 0x0072c + /* TFU YUV Coefficient 2 */ + #define V3D_TFU_COEF2 0x0042c ++#define V3D_V7_TFU_COEF2 0x00730 + /* TFU YUV Coefficient 3 */ + #define V3D_TFU_COEF3 0x00430 ++#define V3D_V7_TFU_COEF3 0x00734 + ++/* V3D 4.x only */ + #define V3D_TFU_CRC 0x00434 + + /* Per-MMU registers. */ + + #define V3D_MMUC_CONTROL 0x01000 + # define V3D_MMUC_CONTROL_CLEAR BIT(3) ++# define V3D_V7_MMUC_CONTROL_CLEAR BIT(11) + # define V3D_MMUC_CONTROL_FLUSHING BIT(2) + # define V3D_MMUC_CONTROL_FLUSH BIT(1) + # define V3D_MMUC_CONTROL_ENABLE BIT(0) +@@ -246,7 +265,6 @@ + + #define V3D_CTL_L2TCACTL 0x00030 + # define V3D_L2TCACTL_TMUWCF BIT(8) +-# define V3D_L2TCACTL_L2T_NO_WM BIT(4) + /* Invalidates cache lines. */ + # define V3D_L2TCACTL_FLM_FLUSH 0 + /* Removes cachelines without writing dirty lines back. */ +@@ -268,7 +286,9 @@ + # define V3D_INT_QPU_MASK V3D_MASK(27, 16) + # define V3D_INT_QPU_SHIFT 16 + # define V3D_INT_CSDDONE BIT(7) ++# define V3D_V7_INT_CSDDONE BIT(6) + # define V3D_INT_PCTR BIT(6) ++# define V3D_V7_INT_PCTR BIT(5) + # define V3D_INT_GMPV BIT(5) + # define V3D_INT_TRFB BIT(4) + # define V3D_INT_SPILLUSE BIT(3) +@@ -350,14 +370,19 @@ + #define V3D_V4_PCTR_0_SRC_X(x) (V3D_V4_PCTR_0_SRC_0_3 + \ + 4 * (x)) + # define V3D_PCTR_S0_MASK V3D_MASK(6, 0) ++# define V3D_V7_PCTR_S0_MASK V3D_MASK(7, 0) + # define V3D_PCTR_S0_SHIFT 0 + # define V3D_PCTR_S1_MASK V3D_MASK(14, 8) ++# define V3D_V7_PCTR_S1_MASK V3D_MASK(15, 8) + # define V3D_PCTR_S1_SHIFT 8 + # define V3D_PCTR_S2_MASK V3D_MASK(22, 16) ++# define V3D_V7_PCTR_S2_MASK V3D_MASK(23, 16) + # define V3D_PCTR_S2_SHIFT 16 + # define V3D_PCTR_S3_MASK V3D_MASK(30, 24) ++# define V3D_V7_PCTR_S3_MASK V3D_MASK(31, 24) + # define V3D_PCTR_S3_SHIFT 24 + # define V3D_PCTR_CYCLE_COUNT 32 ++# define V3D_V7_PCTR_CYCLE_COUNT 0 + + /* Output values of the counters. */ + #define V3D_PCTR_0_PCTR0 0x00680 +@@ -365,6 +390,7 @@ + #define V3D_PCTR_0_PCTRX(x) (V3D_PCTR_0_PCTR0 + \ + 4 * (x)) + #define V3D_GMP_STATUS 0x00800 ++#define V3D_V7_GMP_STATUS 0x00600 + # define V3D_GMP_STATUS_GMPRST BIT(31) + # define V3D_GMP_STATUS_WR_COUNT_MASK V3D_MASK(30, 24) + # define V3D_GMP_STATUS_WR_COUNT_SHIFT 24 +@@ -378,12 +404,14 @@ + # define V3D_GMP_STATUS_VIO BIT(0) + + #define V3D_GMP_CFG 0x00804 ++#define V3D_V7_GMP_CFG 0x00604 + # define V3D_GMP_CFG_LBURSTEN BIT(3) + # define V3D_GMP_CFG_PGCRSEN BIT() + # define V3D_GMP_CFG_STOP_REQ BIT(1) + # define V3D_GMP_CFG_PROT_ENABLE BIT(0) + + #define V3D_GMP_VIO_ADDR 0x00808 ++#define V3D_V7_GMP_VIO_ADDR 0x00608 + #define V3D_GMP_VIO_TYPE 0x0080c + #define V3D_GMP_TABLE_ADDR 0x00810 + #define V3D_GMP_CLEAR_LOAD 0x00814 +@@ -399,24 +427,28 @@ + # define V3D_CSD_STATUS_HAVE_QUEUED_DISPATCH BIT(0) + + #define V3D_CSD_QUEUED_CFG0 0x00904 ++#define V3D_V7_CSD_QUEUED_CFG0 0x00930 + # define V3D_CSD_QUEUED_CFG0_NUM_WGS_X_MASK V3D_MASK(31, 16) + # define V3D_CSD_QUEUED_CFG0_NUM_WGS_X_SHIFT 16 + # define V3D_CSD_QUEUED_CFG0_WG_X_OFFSET_MASK V3D_MASK(15, 0) + # define V3D_CSD_QUEUED_CFG0_WG_X_OFFSET_SHIFT 0 + + #define V3D_CSD_QUEUED_CFG1 0x00908 ++#define V3D_V7_CSD_QUEUED_CFG1 0x00934 + # define V3D_CSD_QUEUED_CFG1_NUM_WGS_Y_MASK V3D_MASK(31, 16) + # define V3D_CSD_QUEUED_CFG1_NUM_WGS_Y_SHIFT 16 + # define V3D_CSD_QUEUED_CFG1_WG_Y_OFFSET_MASK V3D_MASK(15, 0) + # define V3D_CSD_QUEUED_CFG1_WG_Y_OFFSET_SHIFT 0 + + #define V3D_CSD_QUEUED_CFG2 0x0090c ++#define V3D_V7_CSD_QUEUED_CFG2 0x00938 + # define V3D_CSD_QUEUED_CFG2_NUM_WGS_Z_MASK V3D_MASK(31, 16) + # define V3D_CSD_QUEUED_CFG2_NUM_WGS_Z_SHIFT 16 + # define V3D_CSD_QUEUED_CFG2_WG_Z_OFFSET_MASK V3D_MASK(15, 0) + # define V3D_CSD_QUEUED_CFG2_WG_Z_OFFSET_SHIFT 0 + + #define V3D_CSD_QUEUED_CFG3 0x00910 ++#define V3D_V7_CSD_QUEUED_CFG3 0x0093c + # define V3D_CSD_QUEUED_CFG3_OVERLAP_WITH_PREV BIT(26) + # define V3D_CSD_QUEUED_CFG3_MAX_SG_ID_MASK V3D_MASK(25, 20) + # define V3D_CSD_QUEUED_CFG3_MAX_SG_ID_SHIFT 20 +@@ -429,22 +461,36 @@ + + /* Number of batches, minus 1 */ + #define V3D_CSD_QUEUED_CFG4 0x00914 ++#define V3D_V7_CSD_QUEUED_CFG4 0x00940 + + /* Shader address, pnan, singleseg, threading, like a shader record. */ + #define V3D_CSD_QUEUED_CFG5 0x00918 ++#define V3D_V7_CSD_QUEUED_CFG5 0x00944 + + /* Uniforms address (4 byte aligned) */ + #define V3D_CSD_QUEUED_CFG6 0x0091c ++#define V3D_V7_CSD_QUEUED_CFG6 0x00948 ++ ++#define V3D_V7_CSD_QUEUED_CFG7 0x0094c + + #define V3D_CSD_CURRENT_CFG0 0x00920 ++#define V3D_V7_CSD_CURRENT_CFG0 0x00958 + #define V3D_CSD_CURRENT_CFG1 0x00924 ++#define V3D_V7_CSD_CURRENT_CFG1 0x0095c + #define V3D_CSD_CURRENT_CFG2 0x00928 ++#define V3D_V7_CSD_CURRENT_CFG2 0x00960 + #define V3D_CSD_CURRENT_CFG3 0x0092c ++#define V3D_V7_CSD_CURRENT_CFG3 0x00964 + #define V3D_CSD_CURRENT_CFG4 0x00930 ++#define V3D_V7_CSD_CURRENT_CFG4 0x00968 + #define V3D_CSD_CURRENT_CFG5 0x00934 ++#define V3D_V7_CSD_CURRENT_CFG5 0x0096c + #define V3D_CSD_CURRENT_CFG6 0x00938 ++#define V3D_V7_CSD_CURRENT_CFG6 0x00970 ++#define V3D_V7_CSD_CURRENT_CFG7 0x00974 + + #define V3D_CSD_CURRENT_ID0 0x0093c ++#define V3D_V7_CSD_CURRENT_ID0 0x00978 + # define V3D_CSD_CURRENT_ID0_WG_X_MASK V3D_MASK(31, 16) + # define V3D_CSD_CURRENT_ID0_WG_X_SHIFT 16 + # define V3D_CSD_CURRENT_ID0_WG_IN_SG_MASK V3D_MASK(11, 8) +@@ -453,6 +499,7 @@ + # define V3D_CSD_CURRENT_ID0_L_IDX_SHIFT 0 + + #define V3D_CSD_CURRENT_ID1 0x00940 ++#define V3D_V7_CSD_CURRENT_ID1 0x0097c + # define V3D_CSD_CURRENT_ID0_WG_Z_MASK V3D_MASK(31, 16) + # define V3D_CSD_CURRENT_ID0_WG_Z_SHIFT 16 + # define V3D_CSD_CURRENT_ID0_WG_Y_MASK V3D_MASK(15, 0) +diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c +index 06238e6d7f5c..3f79e4113cc7 100644 +--- a/drivers/gpu/drm/v3d/v3d_sched.c ++++ b/drivers/gpu/drm/v3d/v3d_sched.c +@@ -19,6 +19,7 @@ + */ + + #include <linux/kthread.h> ++#include <linux/sched/clock.h> + + #include "v3d_drv.h" + #include "v3d_regs.h" +@@ -72,6 +73,114 @@ v3d_switch_perfmon(struct v3d_dev *v3d, struct v3d_job *job) + v3d_perfmon_start(v3d, job->perfmon); + } + ++/* ++ * Updates the scheduling stats of the gpu queues runtime for completed jobs. ++ * ++ * It should be called before any new job submission to the queue or before ++ * accessing the stats from the debugfs interface. ++ * ++ * It is expected that calls to this function are done with queue_stats->lock ++ * locked. ++ */ ++void ++v3d_sched_stats_update(struct v3d_queue_stats *queue_stats) ++{ ++ struct list_head *pid_stats_list = &queue_stats->pid_stats_list; ++ struct v3d_queue_pid_stats *cur, *tmp; ++ u64 runtime = 0; ++ bool store_pid_stats = ++ time_is_after_jiffies(queue_stats->gpu_pid_stats_timeout); ++ ++ /* If debugfs stats gpu_pid_usage has not been polled for a period, ++ * the pid stats collection is stopped and we purge any existing ++ * pid_stats. ++ * ++ * pid_stats are also purged for clients that have reached the ++ * timeout_purge because the process probably does not exist anymore. ++ */ ++ list_for_each_entry_safe_reverse(cur, tmp, pid_stats_list, list) { ++ if (!store_pid_stats || time_is_before_jiffies(cur->timeout_purge)) { ++ list_del(&cur->list); ++ kfree(cur); ++ } else { ++ break; ++ } ++ } ++ /* If a job has finished its stats are updated. */ ++ if (queue_stats->last_pid && queue_stats->last_exec_end) { ++ runtime = queue_stats->last_exec_end - ++ queue_stats->last_exec_start; ++ queue_stats->runtime += runtime; ++ ++ if (store_pid_stats) { ++ struct v3d_queue_pid_stats *pid_stats; ++ /* Last job info is always at the head of the list */ ++ pid_stats = list_first_entry_or_null(pid_stats_list, ++ struct v3d_queue_pid_stats, list); ++ if (pid_stats && ++ pid_stats->pid == queue_stats->last_pid) { ++ pid_stats->runtime += runtime; ++ } ++ } ++ queue_stats->last_pid = 0; ++ } ++} ++ ++/* ++ * Updates the queue usage adding the information of a new job that is ++ * about to be sent to the GPU to be executed. ++ */ ++int ++v3d_sched_stats_add_job(struct v3d_queue_stats *queue_stats, ++ struct drm_sched_job *sched_job) ++{ ++ ++ struct v3d_queue_pid_stats *pid_stats = NULL; ++ struct v3d_job *job = sched_job?to_v3d_job(sched_job):NULL; ++ struct v3d_queue_pid_stats *cur; ++ struct list_head *pid_stats_list = &queue_stats->pid_stats_list; ++ int ret = 0; ++ ++ mutex_lock(&queue_stats->lock); ++ ++ /* Completion of previous job requires an update of its runtime stats */ ++ v3d_sched_stats_update(queue_stats); ++ ++ queue_stats->last_exec_start = local_clock(); ++ queue_stats->last_exec_end = 0; ++ queue_stats->jobs_sent++; ++ queue_stats->last_pid = job->client_pid; ++ ++ /* gpu usage stats by process are being collected */ ++ if (time_is_after_jiffies(queue_stats->gpu_pid_stats_timeout)) { ++ list_for_each_entry(cur, pid_stats_list, list) { ++ if (cur->pid == job->client_pid) { ++ pid_stats = cur; + break; + } ++ } ++ /* pid_stats of this client is moved to the head of the list. */ ++ if (pid_stats) { ++ list_move(&pid_stats->list, pid_stats_list); + } else { -+ /* Default to 18bit if no connector found. */ - dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1, - DPI_FORMAT); -- break; -- case MEDIA_BUS_FMT_RGB565_1X16: -- dpi_c |= VC4_SET_FIELD(DPI_FORMAT_16BIT_565_RGB_3, -- DPI_FORMAT); -- break; -- default: -- DRM_ERROR("Unknown media bus format %d\n", bus_format); -- break; ++ pid_stats = kzalloc(sizeof(struct v3d_queue_pid_stats), ++ GFP_KERNEL); ++ if (!pid_stats) { ++ ret = -ENOMEM; ++ goto err_mem; ++ } ++ pid_stats->pid = job->client_pid; ++ list_add(&pid_stats->list, pid_stats_list); ++ } ++ pid_stats->jobs_sent++; ++ pid_stats->timeout_purge = jiffies + V3D_QUEUE_STATS_TIMEOUT; ++ } + - } ++err_mem: ++ mutex_unlock(&queue_stats->lock); ++ return ret; ++} ++ + static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job) + { + struct v3d_bin_job *job = to_bin_job(sched_job); +@@ -107,6 +216,7 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job) + trace_v3d_submit_cl(dev, false, to_v3d_fence(fence)->seqno, + job->start, job->end); + ++ v3d_sched_stats_add_job(&v3d->gpu_queue_statsV3D_BIN, sched_job); + v3d_switch_perfmon(v3d, &job->base); + + /* Set the current and end address of the control list. +@@ -158,6 +268,7 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job) + trace_v3d_submit_cl(dev, true, to_v3d_fence(fence)->seqno, + job->start, job->end); + ++ v3d_sched_stats_add_job(&v3d->gpu_queue_statsV3D_RENDER, sched_job); + v3d_switch_perfmon(v3d, &job->base); + + /* XXX: Set the QCFG */ +@@ -171,6 +282,8 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job) + return fence; + } + ++#define V3D_TFU_REG(name) ((v3d->ver < 71) ? V3D_TFU_ ## name : V3D_V7_TFU_ ## name) ++ + static struct dma_fence * + v3d_tfu_job_run(struct drm_sched_job *sched_job) + { +@@ -190,20 +303,23 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job) + + trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno); + +- V3D_WRITE(V3D_TFU_IIA, job->args.iia); +- V3D_WRITE(V3D_TFU_IIS, job->args.iis); +- V3D_WRITE(V3D_TFU_ICA, job->args.ica); +- V3D_WRITE(V3D_TFU_IUA, job->args.iua); +- V3D_WRITE(V3D_TFU_IOA, job->args.ioa); +- V3D_WRITE(V3D_TFU_IOS, job->args.ios); +- V3D_WRITE(V3D_TFU_COEF0, job->args.coef0); +- if (job->args.coef0 & V3D_TFU_COEF0_USECOEF) { +- V3D_WRITE(V3D_TFU_COEF1, job->args.coef1); +- V3D_WRITE(V3D_TFU_COEF2, job->args.coef2); +- V3D_WRITE(V3D_TFU_COEF3, job->args.coef3); ++ v3d_sched_stats_add_job(&v3d->gpu_queue_statsV3D_TFU, sched_job); ++ V3D_WRITE(V3D_TFU_REG(IIA), job->args.iia); ++ V3D_WRITE(V3D_TFU_REG(IIS), job->args.iis); ++ V3D_WRITE(V3D_TFU_REG(ICA), job->args.ica); ++ V3D_WRITE(V3D_TFU_REG(IUA), job->args.iua); ++ V3D_WRITE(V3D_TFU_REG(IOA), job->args.ioa); ++ if (v3d->ver >= 71) ++ V3D_WRITE(V3D_V7_TFU_IOC, job->args.v71.ioc); ++ V3D_WRITE(V3D_TFU_REG(IOS), job->args.ios); ++ V3D_WRITE(V3D_TFU_REG(COEF0), job->args.coef0); ++ if (v3d->ver >= 71 || (job->args.coef0 & V3D_TFU_COEF0_USECOEF)) { ++ V3D_WRITE(V3D_TFU_REG(COEF1), job->args.coef1); ++ V3D_WRITE(V3D_TFU_REG(COEF2), job->args.coef2); ++ V3D_WRITE(V3D_TFU_REG(COEF3), job->args.coef3); + } + /* ICFG kicks off the job. */ +- V3D_WRITE(V3D_TFU_ICFG, job->args.icfg | V3D_TFU_ICFG_IOC); ++ V3D_WRITE(V3D_TFU_REG(ICFG), job->args.icfg | V3D_TFU_ICFG_IOC); + + return fence; + } +@@ -215,7 +331,7 @@ v3d_csd_job_run(struct drm_sched_job *sched_job) + struct v3d_dev *v3d = job->base.v3d; + struct drm_device *dev = &v3d->drm; + struct dma_fence *fence; +- int i; ++ int i, csd_cfg0_reg, csd_cfg_reg_count; + + v3d->csd_job = job; + +@@ -231,12 +347,15 @@ v3d_csd_job_run(struct drm_sched_job *sched_job) + + trace_v3d_submit_csd(dev, to_v3d_fence(fence)->seqno); + ++ v3d_sched_stats_add_job(&v3d->gpu_queue_statsV3D_CSD, sched_job); + v3d_switch_perfmon(v3d, &job->base); + +- for (i = 1; i <= 6; i++) +- V3D_CORE_WRITE(0, V3D_CSD_QUEUED_CFG0 + 4 * i, job->args.cfgi); ++ csd_cfg0_reg = v3d->ver < 71 ? V3D_CSD_QUEUED_CFG0 : V3D_V7_CSD_QUEUED_CFG0; ++ csd_cfg_reg_count = v3d->ver < 71 ? 6 : 7; ++ for (i = 1; i <= csd_cfg_reg_count; i++) ++ V3D_CORE_WRITE(0, csd_cfg0_reg + 4 * i, job->args.cfgi); + /* CFG0 write kicks off the job. */ +- V3D_CORE_WRITE(0, V3D_CSD_QUEUED_CFG0, job->args.cfg0); ++ V3D_CORE_WRITE(0, csd_cfg0_reg, job->args.cfg0); + + return fence; + } +@@ -247,7 +366,10 @@ v3d_cache_clean_job_run(struct drm_sched_job *sched_job) + struct v3d_job *job = to_v3d_job(sched_job); + struct v3d_dev *v3d = job->v3d; + ++ v3d_sched_stats_add_job(&v3d->gpu_queue_statsV3D_CACHE_CLEAN, ++ sched_job); + v3d_clean_caches(v3d); ++ v3d->gpu_queue_statsV3D_CACHE_CLEAN.last_exec_end = local_clock(); + + return NULL; + } +@@ -336,7 +458,8 @@ v3d_csd_job_timedout(struct drm_sched_job *sched_job) + { + struct v3d_csd_job *job = to_csd_job(sched_job); + struct v3d_dev *v3d = job->base.v3d; +- u32 batches = V3D_CORE_READ(0, V3D_CSD_CURRENT_CFG4); ++ u32 batches = V3D_CORE_READ(0, (v3d->ver < 71 ? V3D_CSD_CURRENT_CFG4 : ++ V3D_V7_CSD_CURRENT_CFG4)); + + /* If we've made progress, skip reset and let the timer get + * rearmed. +@@ -385,8 +508,18 @@ v3d_sched_init(struct v3d_dev *v3d) + int hw_jobs_limit = 1; + int job_hang_limit = 0; + int hang_limit_ms = 500; ++ enum v3d_queue q; + int ret; + ++ for (q = 0; q < V3D_MAX_QUEUES; q++) { ++ INIT_LIST_HEAD(&v3d->gpu_queue_statsq.pid_stats_list); ++ /* Setting timeout before current jiffies disables collecting ++ * pid_stats on scheduling init. ++ */ ++ v3d->gpu_queue_statsq.gpu_pid_stats_timeout = jiffies - 1; ++ mutex_init(&v3d->gpu_queue_statsq.lock); ++ } ++ + ret = drm_sched_init(&v3d->queueV3D_BIN.sched, + &v3d_bin_sched_ops, + hw_jobs_limit, job_hang_limit, +@@ -440,9 +573,20 @@ void + v3d_sched_fini(struct v3d_dev *v3d) + { + enum v3d_queue q; ++ struct v3d_queue_stats *queue_stats; + + for (q = 0; q < V3D_MAX_QUEUES; q++) { +- if (v3d->queueq.sched.ready) ++ if (v3d->queueq.sched.ready) { ++ queue_stats = &v3d->gpu_queue_statsq; ++ mutex_lock(&queue_stats->lock); ++ /* Setting gpu_pid_stats_timeout to jiffies-1 will ++ * make v3d_sched_stats_update to purge all ++ * allocated pid_stats. ++ */ ++ queue_stats->gpu_pid_stats_timeout = jiffies - 1; ++ v3d_sched_stats_update(queue_stats); ++ mutex_unlock(&queue_stats->lock); + drm_sched_fini(&v3d->queueq.sched); ++ } + } + } +diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile +index c41f89a15a55..823ffbe0b78d 100644 +--- a/drivers/gpu/drm/vc4/Makefile ++++ b/drivers/gpu/drm/vc4/Makefile +@@ -9,6 +9,7 @@ vc4-y := \ + vc4_dpi.o \ + vc4_dsi.o \ + vc4_fence.o \ ++ vc4_firmware_kms.o \ + vc4_kms.o \ + vc4_gem.o \ + vc4_hdmi.o \ +@@ -30,7 +31,8 @@ vc4-$(CONFIG_DRM_VC4_KUNIT_TEST) += \ + tests/vc4_mock_crtc.o \ + tests/vc4_mock_output.o \ + tests/vc4_mock_plane.o \ +- tests/vc4_test_pv_muxing.o ++ tests/vc4_test_pv_muxing.o \ ++ tests/vc4_test_lbm_size.o + + vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o + +diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.c b/drivers/gpu/drm/vc4/tests/vc4_mock.c +index 63ca46f4cb35..a9b739141ad4 100644 +--- a/drivers/gpu/drm/vc4/tests/vc4_mock.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock.c +@@ -51,8 +51,8 @@ struct vc4_mock_desc { + + static const struct vc4_mock_desc vc4_mock = + VC4_MOCK_DESC( +- VC4_MOCK_CRTC_DESC(&vc4_txp_crtc_data, +- VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP, ++ VC4_MOCK_CRTC_DESC(&bcm2835_txp_data.base, ++ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP0, + DRM_MODE_ENCODER_VIRTUAL, + DRM_MODE_CONNECTOR_WRITEBACK)), + VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv0_data, +@@ -77,8 +77,8 @@ static const struct vc4_mock_desc vc4_mock = + + static const struct vc4_mock_desc vc5_mock = + VC4_MOCK_DESC( +- VC4_MOCK_CRTC_DESC(&vc4_txp_crtc_data, +- VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP, ++ VC4_MOCK_CRTC_DESC(&bcm2835_txp_data.base, ++ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP0, + DRM_MODE_ENCODER_VIRTUAL, + DRM_MODE_CONNECTOR_WRITEBACK)), + VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv0_data, +@@ -106,6 +106,26 @@ static const struct vc4_mock_desc vc5_mock = + DRM_MODE_CONNECTOR_HDMIA)), + ); + ++static const struct vc4_mock_desc vc6_mock = ++ VC4_MOCK_DESC( ++ VC4_MOCK_CRTC_DESC(&bcm2712_mop_data.base, ++ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP0, ++ DRM_MODE_ENCODER_VIRTUAL, ++ DRM_MODE_CONNECTOR_WRITEBACK)), ++ VC4_MOCK_CRTC_DESC(&bcm2712_moplet_data.base, ++ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP1, ++ DRM_MODE_ENCODER_VIRTUAL, ++ DRM_MODE_CONNECTOR_WRITEBACK)), ++ VC4_MOCK_PIXELVALVE_DESC(&bcm2712_pv0_data, ++ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI0, ++ DRM_MODE_ENCODER_TMDS, ++ DRM_MODE_CONNECTOR_HDMIA)), ++ VC4_MOCK_PIXELVALVE_DESC(&bcm2712_pv1_data, ++ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI1, ++ DRM_MODE_ENCODER_TMDS, ++ DRM_MODE_CONNECTOR_HDMIA)), ++); ++ + static int __build_one_pipe(struct kunit *test, struct drm_device *drm, + const struct vc4_mock_pipe_desc *pipe) + { +@@ -160,15 +180,33 @@ static void kunit_action_drm_dev_unregister(void *ptr) + drm_dev_unregister(drm); + } + +-static struct vc4_dev *__mock_device(struct kunit *test, bool is_vc5) ++static struct vc4_dev *__mock_device(struct kunit *test, enum vc4_gen gen) + { ++ const struct vc4_mock_desc *desc; ++ const struct drm_driver *drv; + struct drm_device *drm; +- const struct drm_driver *drv = is_vc5 ? &vc5_drm_driver : &vc4_drm_driver; +- const struct vc4_mock_desc *desc = is_vc5 ? &vc5_mock : &vc4_mock; + struct vc4_dev *vc4; + struct device *dev; + int ret; + ++ switch (gen) { ++ case VC4_GEN_4: ++ drv = &vc4_drm_driver; ++ desc = &vc4_mock; ++ break; ++ case VC4_GEN_5: ++ drv = &vc5_drm_driver; ++ desc = &vc5_mock; ++ break; ++ case VC4_GEN_6: ++ drv = &vc5_drm_driver; ++ desc = &vc6_mock; ++ break; ++ ++ default: ++ return NULL; ++ } ++ + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + +@@ -178,9 +216,9 @@ static struct vc4_dev *__mock_device(struct kunit *test, bool is_vc5) + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4); + + vc4->dev = dev; +- vc4->is_vc5 = is_vc5; ++ vc4->gen = gen; + +- vc4->hvs = __vc4_hvs_alloc(vc4, NULL); ++ vc4->hvs = __vc4_hvs_alloc(vc4, NULL, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4->hvs); + + drm = &vc4->base; +@@ -203,10 +241,15 @@ static struct vc4_dev *__mock_device(struct kunit *test, bool is_vc5) + + struct vc4_dev *vc4_mock_device(struct kunit *test) + { +- return __mock_device(test, false); ++ return __mock_device(test, VC4_GEN_4); + } + + struct vc4_dev *vc5_mock_device(struct kunit *test) + { +- return __mock_device(test, true); ++ return __mock_device(test, VC4_GEN_5); ++} ++ ++struct vc4_dev *vc6_mock_device(struct kunit *test) ++{ ++ return __mock_device(test, VC4_GEN_6); + } +diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.h b/drivers/gpu/drm/vc4/tests/vc4_mock.h +index 2d0b339bd9f3..1f3d064a8f60 100644 +--- a/drivers/gpu/drm/vc4/tests/vc4_mock.h ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h +@@ -7,9 +7,9 @@ + + static inline + struct drm_crtc *vc4_find_crtc_for_encoder(struct kunit *test, +- struct drm_device *drm, + struct drm_encoder *encoder) + { ++ struct drm_device *drm = encoder->dev; + struct drm_crtc *crtc; + + KUNIT_ASSERT_EQ(test, hweight32(encoder->possible_crtcs), 1); +@@ -21,6 +21,20 @@ struct drm_crtc *vc4_find_crtc_for_encoder(struct kunit *test, + return NULL; + } + ++static inline ++struct drm_plane *vc4_mock_find_plane_for_crtc(struct kunit *test, ++ struct drm_crtc *crtc) ++{ ++ struct drm_device *drm = crtc->dev; ++ struct drm_plane *plane; ++ ++ drm_for_each_plane(plane, drm) ++ if (plane->possible_crtcs & drm_crtc_mask(crtc)) ++ return plane; ++ ++ return NULL; ++} ++ + struct vc4_dummy_plane { + struct vc4_plane plane; + }; +@@ -28,6 +42,10 @@ struct vc4_dummy_plane { + struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test, + struct drm_device *drm, + enum drm_plane_type type); ++struct drm_plane * ++vc4_mock_atomic_add_plane(struct kunit *test, ++ struct drm_atomic_state *state, ++ struct drm_crtc *crtc); + + struct vc4_dummy_crtc { + struct vc4_crtc crtc; +@@ -55,10 +73,12 @@ struct vc4_dummy_output *vc4_dummy_output(struct kunit *test, + + struct vc4_dev *vc4_mock_device(struct kunit *test); + struct vc4_dev *vc5_mock_device(struct kunit *test); ++struct vc4_dev *vc6_mock_device(struct kunit *test); + +-int vc4_mock_atomic_add_output(struct kunit *test, +- struct drm_atomic_state *state, +- enum vc4_encoder_type type); ++struct vc4_dummy_output * ++vc4_mock_atomic_add_output(struct kunit *test, ++ struct drm_atomic_state *state, ++ enum vc4_encoder_type type); + int vc4_mock_atomic_del_output(struct kunit *test, + struct drm_atomic_state *state, + enum vc4_encoder_type type); +diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c +index e70d7c3076ac..bcc6c78d80ab 100644 +--- a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c +@@ -61,9 +61,10 @@ static const struct drm_display_mode default_mode = { + DRM_SIMPLE_MODE(640, 480, 64, 48) + }; + +-int vc4_mock_atomic_add_output(struct kunit *test, +- struct drm_atomic_state *state, +- enum vc4_encoder_type type) ++struct vc4_dummy_output * ++vc4_mock_atomic_add_output(struct kunit *test, ++ struct drm_atomic_state *state, ++ enum vc4_encoder_type type) + { + struct drm_device *drm = state->dev; + struct drm_connector_state *conn_state; +@@ -77,7 +78,7 @@ int vc4_mock_atomic_add_output(struct kunit *test, + encoder = vc4_find_encoder_by_type(drm, type); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder); + +- crtc = vc4_find_crtc_for_encoder(test, drm, encoder); ++ crtc = vc4_find_crtc_for_encoder(test, encoder); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + + output = encoder_to_vc4_dummy_output(encoder); +@@ -96,7 +97,7 @@ int vc4_mock_atomic_add_output(struct kunit *test, + + crtc_state->active = true; + +- return 0; ++ return output; + } + + int vc4_mock_atomic_del_output(struct kunit *test, +@@ -115,7 +116,7 @@ int vc4_mock_atomic_del_output(struct kunit *test, + encoder = vc4_find_encoder_by_type(drm, type); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder); + +- crtc = vc4_find_crtc_for_encoder(test, drm, encoder); ++ crtc = vc4_find_crtc_for_encoder(test, encoder); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + + crtc_state = drm_atomic_get_crtc_state(state, crtc); +diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c +index 62b18f5f41db..d5083695399f 100644 +--- a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c +@@ -1,6 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + + #include <drm/drm_atomic_state_helper.h> ++#include <drm/drm_atomic_uapi.h> + #include <drm/drm_fourcc.h> + #include <drm/drm_modeset_helper_vtables.h> + #include <drm/drm_plane.h> +@@ -10,16 +11,20 @@ + #include "vc4_mock.h" + + static const struct drm_plane_helper_funcs vc4_dummy_plane_helper_funcs = { ++ .atomic_check = vc4_plane_atomic_check, + }; + + static const struct drm_plane_funcs vc4_dummy_plane_funcs = { +- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, +- .reset = drm_atomic_helper_plane_reset, ++ .atomic_destroy_state = vc4_plane_destroy_state, ++ .atomic_duplicate_state = vc4_plane_duplicate_state, ++ .reset = vc4_plane_reset, + }; + + static const uint32_t vc4_dummy_plane_formats = { ++ DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888, ++ DRM_FORMAT_YUV420, ++ DRM_FORMAT_YUV422, + }; + + struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test, +@@ -45,3 +50,24 @@ struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test, + + return dummy_plane; + } ++ ++struct drm_plane * ++vc4_mock_atomic_add_plane(struct kunit *test, ++ struct drm_atomic_state *state, ++ struct drm_crtc *crtc) ++{ ++ struct drm_plane_state *plane_state; ++ struct drm_plane *plane; ++ int ret; ++ ++ plane = vc4_mock_find_plane_for_crtc(test, crtc); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane); ++ ++ plane_state = drm_atomic_get_plane_state(state, plane); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_state); ++ ++ ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); ++ KUNIT_EXPECT_EQ(test, ret, 0); ++ ++ return plane; ++} +diff --git a/drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c b/drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c +new file mode 100644 +index 000000000000..5f4e3013e0ed +--- /dev/null ++++ b/drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c +@@ -0,0 +1,308 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include <drm/drm_atomic_helper.h> ++#include <drm/drm_atomic_uapi.h> ++#include <drm/drm_drv.h> ++#include <drm/drm_fourcc.h> ++#include <drm/drm_framebuffer.h> ++#include <drm/drm_plane.h> ++#include <drm/drm_kunit_helpers.h> ++ ++#include "../../drm_crtc_internal.h" ++#include "../../drm_internal.h" ++ ++#include <kunit/test.h> ++ ++#include "../vc4_drv.h" ++ ++#include "vc4_mock.h" ++ ++u32 vc4_lbm_size(struct drm_plane_state *state); ++ ++struct vc4_lbm_size_priv { ++ struct vc4_dev *vc4; ++ struct drm_file *file; ++ struct drm_modeset_acquire_ctx ctx; ++ struct drm_atomic_state *state; ++}; ++ ++struct vc4_lbm_size_param { ++ unsigned int src_w, src_h; ++ unsigned int crtc_w, crtc_h; ++ bool forced_alpha; ++ u32 fourcc; ++ enum vc4_scaling_mode expected_x_scaling2; ++ enum vc4_scaling_mode expected_y_scaling2; ++ unsigned int expected_lbm_size; ++}; ++ ++static const struct vc4_lbm_size_param vc4_test_lbm_size_params = { ++ { ++ .src_w = 256, ++ .crtc_w = 256, ++ .src_h = 256, ++ .crtc_h = 512, ++ .fourcc = DRM_FORMAT_ARGB8888, ++ .expected_x_scaling = { VC4_SCALING_NONE, }, ++ .expected_y_scaling = { VC4_SCALING_PPF, }, ++ .expected_lbm_size = 32, ++ }, ++ { ++ .src_w = 256, ++ .crtc_w = 179, ++ .src_h = 256, ++ .crtc_h = 512, ++ .fourcc = DRM_FORMAT_ARGB8888, ++ .expected_x_scaling = { VC4_SCALING_PPF, }, ++ .expected_y_scaling = { VC4_SCALING_PPF, }, ++ .expected_lbm_size = 23, ++ }, ++ { ++ .src_w = 256, ++ .crtc_w = 256, ++ .src_h = 256, ++ .crtc_h = 512, ++ .fourcc = DRM_FORMAT_XRGB8888, ++ .expected_x_scaling = { VC4_SCALING_NONE, }, ++ .expected_y_scaling = { VC4_SCALING_PPF, }, ++ .expected_lbm_size = 24, ++ }, ++ { ++ .src_w = 100, ++ .crtc_w = 73, ++ .src_h = 100, ++ .crtc_h = 73, ++ .fourcc = DRM_FORMAT_XRGB8888, ++ .expected_x_scaling = { VC4_SCALING_PPF, }, ++ .expected_y_scaling = { VC4_SCALING_PPF, }, ++ .expected_lbm_size = 8, ++ }, ++ { ++ .src_w = 256, ++ .crtc_w = 256, ++ .src_h = 256, ++ .crtc_h = 512, ++ .forced_alpha = true, ++ .fourcc = DRM_FORMAT_ARGB8888, ++ .expected_x_scaling = { VC4_SCALING_NONE, }, ++ .expected_y_scaling = { VC4_SCALING_PPF, }, ++ .expected_lbm_size = 24, ++ }, ++ { ++ .src_w = 100, ++ .crtc_w = 73, ++ .src_h = 100, ++ .crtc_h = 73, ++ .forced_alpha = true, ++ .fourcc = DRM_FORMAT_ARGB8888, ++ .expected_x_scaling = { VC4_SCALING_PPF, }, ++ .expected_y_scaling = { VC4_SCALING_PPF, }, ++ .expected_lbm_size = 8, ++ }, ++ { ++ .src_w = 256, ++ .crtc_w = 94, ++ .src_h = 256, ++ .crtc_h = 94, ++ .fourcc = DRM_FORMAT_ARGB8888, ++ .expected_x_scaling = { VC4_SCALING_TPZ, }, ++ .expected_y_scaling = { VC4_SCALING_TPZ, }, ++ .expected_lbm_size = 6, ++ }, ++ ++/* ++ * TODO: Those tests reflect the LBM size calculation examples, but the ++ * driver ends up taking different scaler filters decisions, and thus ++ * doesn't end up with the same sizes. It would be valuable to have ++ * those tests, but the driver doesn't take a bad decision either, so ++ * it's not clear what we should do at this point. ++ */ ++#if 0 ++ { ++ .src_w = 320, ++ .crtc_w = 320, ++ .src_h = 320, ++ .crtc_h = 320, ++ .fourcc = DRM_FORMAT_YUV420, ++ .expected_x_scaling = { VC4_SCALING_NONE, VC4_SCALING_NONE, }, ++ .expected_y_scaling = { VC4_SCALING_NONE, VC4_SCALING_PPF, }, ++ .expected_lbm_size = 10, ++ }, ++ { ++ .src_w = 512, ++ .crtc_w = 512, ++ .src_h = 512, ++ .crtc_h = 256, ++ .fourcc = DRM_FORMAT_YUV420, ++ .expected_x_scaling = { VC4_SCALING_NONE, VC4_SCALING_NONE, }, ++ .expected_y_scaling = { VC4_SCALING_TPZ, VC4_SCALING_NONE, }, ++ .expected_lbm_size = 5, ++ }, ++ { ++ .src_w = 486, ++ .crtc_w = 157, ++ .src_h = 404, ++ .crtc_h = 929, ++ .fourcc = DRM_FORMAT_YUV422, ++ .expected_x_scaling = { VC4_SCALING_PPF, VC4_SCALING_PPF, }, ++ .expected_y_scaling = { VC4_SCALING_PPF, VC4_SCALING_PPF, }, ++ .expected_lbm_size = 20, ++ }, ++ { ++ .src_w = 320, ++ .crtc_w = 128, ++ .src_h = 176, ++ .crtc_h = 70, ++ .fourcc = DRM_FORMAT_YUV420, ++ .expected_x_scaling = { VC4_SCALING_TPZ, VC4_SCALING_TPZ, }, ++ .expected_y_scaling = { VC4_SCALING_TPZ, VC4_SCALING_TPZ, }, ++ .expected_lbm_size = 8, ++ }, ++#endif ++}; ++ ++static void vc4_test_lbm_size_desc(const struct vc4_lbm_size_param *t, char *desc) ++{ ++ snprintf(desc, KUNIT_PARAM_DESC_SIZE, ++ "%ux%u to %ux%u %s(%p4cc)", ++ t->src_w, t->src_h, ++ t->crtc_w, t->crtc_h, ++ t->forced_alpha ? "with forced alpha " : "", ++ &t->fourcc); ++} ++ ++KUNIT_ARRAY_PARAM(vc4_test_lbm_size, ++ vc4_test_lbm_size_params, ++ vc4_test_lbm_size_desc); ++ ++static void drm_vc4_test_vc4_lbm_size(struct kunit *test) ++{ ++ const struct vc4_lbm_size_param *params = test->param_value; ++ const struct vc4_lbm_size_priv *priv = test->priv; ++ const struct drm_format_info *info; ++ struct drm_mode_fb_cmd2 fb_req = { }; ++ struct drm_atomic_state *state = priv->state; ++ struct vc4_plane_state *vc4_plane_state; ++ struct drm_plane_state *plane_state; ++ struct vc4_dummy_output *output; ++ struct drm_framebuffer *fb; ++ struct drm_plane *plane; ++ struct drm_crtc *crtc; ++ unsigned int i; ++ int ret; ++ ++ info = drm_format_info(params->fourcc); ++ KUNIT_ASSERT_NOT_NULL(test, info); ++ ++ output = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); ++ ++ crtc = vc4_find_crtc_for_encoder(test, &output->encoder.base); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); ++ ++ plane = vc4_mock_atomic_add_plane(test, state, crtc); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane); ++ ++ plane_state = drm_atomic_get_plane_state(state, plane); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_state); ++ ++ vc4_plane_state = to_vc4_plane_state(plane_state); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4_plane_state); ++ ++ fb_req.pixel_format = params->fourcc; ++ fb_req.width = params->src_w; ++ fb_req.height = params->src_h; ++ ++ for (i = 0; i < info->num_planes; i++) { ++ struct drm_mode_create_dumb dumb_args = { }; ++ ++ dumb_args.width = params->src_w; ++ dumb_args.height = params->src_h; ++ dumb_args.bpp = drm_format_info_bpp(info, i); ++ ++ ret = drm_mode_create_dumb(state->dev, &dumb_args, priv->file); ++ KUNIT_ASSERT_EQ(test, ret, 0); ++ ++ fb_req.handlesi = dumb_args.handle; ++ fb_req.pitchesi = dumb_args.pitch; ++ } ++ ++ fb = drm_internal_framebuffer_create(state->dev, &fb_req, priv->file); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb); ++ ++ drm_atomic_set_fb_for_plane(plane_state, fb); ++ ++ plane_state->src_x = 0; ++ plane_state->src_y = 0; ++ plane_state->src_h = params->src_h << 16; ++ plane_state->src_w = params->src_w << 16; ++ ++ plane_state->crtc_x = 0; ++ plane_state->crtc_y = 0; ++ plane_state->crtc_h = params->crtc_h; ++ plane_state->crtc_w = params->crtc_w; ++ ++ if (params->forced_alpha) ++ plane_state->alpha = 128; ++ ++ ret = drm_atomic_check_only(state); ++ KUNIT_ASSERT_EQ(test, ret, 0); ++ ++ KUNIT_EXPECT_EQ(test, vc4_plane_state->lbm_size, params->expected_lbm_size); ++ ++ for (i = 0; i < 2; i++) { ++ KUNIT_EXPECT_EQ(test, ++ vc4_plane_state->x_scalingi, ++ params->expected_x_scalingi); ++ KUNIT_EXPECT_EQ(test, ++ vc4_plane_state->y_scalingi, ++ params->expected_y_scalingi); ++ } ++ ++ drm_framebuffer_put(fb); ++ ++ for (i = 0; i < info->num_planes; i++) ++ drm_mode_destroy_dumb(state->dev, fb_req.handlesi, priv->file); ++} ++ ++static struct kunit_case vc4_lbm_size_tests = { ++ KUNIT_CASE_PARAM(drm_vc4_test_vc4_lbm_size, ++ vc4_test_lbm_size_gen_params), ++ {} ++}; ++ ++static int vc4_lbm_size_test_init(struct kunit *test) ++{ ++ struct drm_modeset_acquire_ctx *ctx; ++ struct vc4_lbm_size_priv *priv; ++ struct drm_device *drm; ++ struct vc4_dev *vc4; ++ ++ priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); ++ KUNIT_ASSERT_NOT_NULL(test, priv); ++ test->priv = priv; ++ ++ vc4 = vc6_mock_device(test); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4); ++ priv->vc4 = vc4; ++ ++ priv->file = drm_file_alloc(priv->vc4->base.primary); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->file); ++ ++ ctx = drm_kunit_helper_acquire_ctx_alloc(test); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); ++ ++ drm = &vc4->base; ++ priv->state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->state); ++ ++ return 0; ++} ++ ++static struct kunit_suite vc4_lbm_size_test_suite = { ++ .name = "vc4-lbm-size", ++ .init = vc4_lbm_size_test_init, ++ .test_cases = vc4_lbm_size_tests, ++}; ++ ++kunit_test_suite(vc4_lbm_size_test_suite); +diff --git a/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c +index 61622e951031..830deb45f309 100644 +--- a/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c +@@ -90,7 +90,7 @@ static const struct encoder_constraint vc4_encoder_constraints = { + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI0, 0), + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI0, 1), + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_VEC, 1), +- ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP, 2), ++ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP0, 2), + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI1, 2), + }; + +@@ -98,12 +98,19 @@ static const struct encoder_constraint vc5_encoder_constraints = { + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DPI, 0), + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI0, 0), + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_VEC, 1), +- ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP, 0, 2), ++ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP0, 0, 2), + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI1, 0, 1, 2), + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI0, 0, 1, 2), + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI1, 0, 1, 2), + }; + ++static const struct encoder_constraint vc6_encoder_constraints = { ++ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI0, 0), ++ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI1, 1), ++ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP1, 1), ++ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP0, 2), ++}; ++ + static bool check_vc4_encoder_constraints(enum vc4_encoder_type type, unsigned int channel) + { + return __check_encoder_constraints(vc4_encoder_constraints, +@@ -118,6 +125,13 @@ static bool check_vc5_encoder_constraints(enum vc4_encoder_type type, unsigned i + type, channel); + } + ++static bool check_vc6_encoder_constraints(enum vc4_encoder_type type, unsigned int channel) ++{ ++ return __check_encoder_constraints(vc6_encoder_constraints, ++ ARRAY_SIZE(vc6_encoder_constraints), ++ type, channel); ++} ++ + static struct vc4_crtc_state * + get_vc4_crtc_state_for_encoder(struct kunit *test, + const struct drm_atomic_state *state, +@@ -131,7 +145,7 @@ get_vc4_crtc_state_for_encoder(struct kunit *test, + encoder = vc4_find_encoder_by_type(drm, type); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder); + +- crtc = vc4_find_crtc_for_encoder(test, drm, encoder); ++ crtc = vc4_find_crtc_for_encoder(test, encoder); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + + new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); +@@ -195,6 +209,9 @@ static void vc4_test_pv_muxing_desc(const struct pv_muxing_param *t, char *desc) + #define VC5_PV_MUXING_TEST(_name, ...) \ + PV_MUXING_TEST(_name, vc5_mock_device, check_vc5_encoder_constraints, __VA_ARGS__) + ++#define VC6_PV_MUXING_TEST(_name, ...) \ ++ PV_MUXING_TEST(_name, vc6_mock_device, check_vc6_encoder_constraints, __VA_ARGS__) ++ + static const struct pv_muxing_param vc4_test_pv_muxing_params = { + VC4_PV_MUXING_TEST("1 output: DSI0", + VC4_ENCODER_TYPE_DSI0), +@@ -207,7 +224,7 @@ static const struct pv_muxing_param vc4_test_pv_muxing_params = { + VC4_PV_MUXING_TEST("1 output: DSI1", + VC4_ENCODER_TYPE_DSI1), + VC4_PV_MUXING_TEST("1 output: TXP", +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("2 outputs: DSI0, HDMI0", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_HDMI0), +@@ -219,7 +236,7 @@ static const struct pv_muxing_param vc4_test_pv_muxing_params = { + VC4_ENCODER_TYPE_DSI1), + VC4_PV_MUXING_TEST("2 outputs: DSI0, TXP", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("2 outputs: DPI, HDMI0", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_HDMI0), +@@ -231,19 +248,19 @@ static const struct pv_muxing_param vc4_test_pv_muxing_params = { + VC4_ENCODER_TYPE_DSI1), + VC4_PV_MUXING_TEST("2 outputs: DPI, TXP", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("2 outputs: HDMI0, DSI1", + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_DSI1), + VC4_PV_MUXING_TEST("2 outputs: HDMI0, TXP", + VC4_ENCODER_TYPE_HDMI0, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("2 outputs: VEC, DSI1", + VC4_ENCODER_TYPE_VEC, + VC4_ENCODER_TYPE_DSI1), + VC4_PV_MUXING_TEST("2 outputs: VEC, TXP", + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, DSI1", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_HDMI0, +@@ -251,7 +268,7 @@ static const struct pv_muxing_param vc4_test_pv_muxing_params = { + VC4_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, TXP", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_HDMI0, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("3 outputs: DSI0, VEC, DSI1", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +@@ -259,7 +276,7 @@ static const struct pv_muxing_param vc4_test_pv_muxing_params = { + VC4_PV_MUXING_TEST("3 outputs: DSI0, VEC, TXP", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("3 outputs: DPI, HDMI0, DSI1", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_HDMI0, +@@ -267,7 +284,7 @@ static const struct pv_muxing_param vc4_test_pv_muxing_params = { + VC4_PV_MUXING_TEST("3 outputs: DPI, HDMI0, TXP", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_HDMI0, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("3 outputs: DPI, VEC, DSI1", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +@@ -275,7 +292,7 @@ static const struct pv_muxing_param vc4_test_pv_muxing_params = { + VC4_PV_MUXING_TEST("3 outputs: DPI, VEC, TXP", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + }; + + KUNIT_ARRAY_PARAM(vc4_test_pv_muxing, +@@ -287,7 +304,7 @@ static const struct pv_muxing_param vc4_test_pv_muxing_invalid_params = { + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_DSI0), + VC4_PV_MUXING_TEST("TXP/DSI1 Conflict", +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1), + VC4_PV_MUXING_TEST("HDMI0/VEC Conflict", + VC4_ENCODER_TYPE_HDMI0, +@@ -296,22 +313,22 @@ static const struct pv_muxing_param vc4_test_pv_muxing_invalid_params = { + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_DSI1, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, TXP", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, + VC4_ENCODER_TYPE_DSI1, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("More than 3 outputs: DPI, HDMI0, DSI1, TXP", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_DSI1, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, TXP", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, + VC4_ENCODER_TYPE_DSI1, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + }; + + KUNIT_ARRAY_PARAM(vc4_test_pv_muxing_invalid, +@@ -342,7 +359,7 @@ static const struct pv_muxing_param vc5_test_pv_muxing_params = { + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("2 outputs: DPI, TXP", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC5_PV_MUXING_TEST("2 outputs: DPI, VEC", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC), +@@ -360,7 +377,7 @@ static const struct pv_muxing_param vc5_test_pv_muxing_params = { + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("2 outputs: DSI0, TXP", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC5_PV_MUXING_TEST("2 outputs: DSI0, VEC", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC), +@@ -372,7 +389,7 @@ static const struct pv_muxing_param vc5_test_pv_muxing_params = { + VC4_ENCODER_TYPE_VEC), + VC5_PV_MUXING_TEST("2 outputs: DSI1, TXP", + VC4_ENCODER_TYPE_DSI1, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC5_PV_MUXING_TEST("2 outputs: DSI1, HDMI0", + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0), +@@ -384,7 +401,7 @@ static const struct pv_muxing_param vc5_test_pv_muxing_params = { + VC4_ENCODER_TYPE_VEC), + VC5_PV_MUXING_TEST("2 outputs: HDMI0, TXP", + VC4_ENCODER_TYPE_HDMI0, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC5_PV_MUXING_TEST("2 outputs: HDMI0, HDMI1", + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), +@@ -393,14 +410,14 @@ static const struct pv_muxing_param vc5_test_pv_muxing_params = { + VC4_ENCODER_TYPE_VEC), + VC5_PV_MUXING_TEST("2 outputs: HDMI1, TXP", + VC4_ENCODER_TYPE_HDMI1, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC5_PV_MUXING_TEST("2 outputs: TXP, VEC", +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_VEC), + VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, TXP", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, DSI1", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +@@ -415,15 +432,15 @@ static const struct pv_muxing_param vc5_test_pv_muxing_params = { + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, DSI1", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1), + VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, HDMI0", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI0), + VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, HDMI1", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("3 outputs: DPI, DSI1, HDMI0", + VC4_ENCODER_TYPE_DPI, +@@ -440,7 +457,7 @@ static const struct pv_muxing_param vc5_test_pv_muxing_params = { + VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, TXP", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, DSI1", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +@@ -455,15 +472,15 @@ static const struct pv_muxing_param vc5_test_pv_muxing_params = { + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, DSI1", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1), + VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, HDMI0", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI0), + VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, HDMI1", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("3 outputs: DSI0, DSI1, HDMI0", + VC4_ENCODER_TYPE_DSI0, +@@ -490,17 +507,17 @@ static const struct pv_muxing_param vc5_test_pv_muxing_invalid_params = { + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI0", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI0), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI1", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI0", + VC4_ENCODER_TYPE_DPI, +@@ -519,17 +536,17 @@ static const struct pv_muxing_param vc5_test_pv_muxing_invalid_params = { + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI0", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI1", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, HDMI0, HDMI1", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, DSI1, HDMI0, HDMI1", +@@ -540,19 +557,19 @@ static const struct pv_muxing_param vc5_test_pv_muxing_invalid_params = { + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI0", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI1", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI0, HDMI1", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI0, HDMI1", +@@ -563,24 +580,24 @@ static const struct pv_muxing_param vc5_test_pv_muxing_invalid_params = { + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI0, HDMI1", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI0", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI0), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI1", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI0", + VC4_ENCODER_TYPE_DSI0, +@@ -599,17 +616,17 @@ static const struct pv_muxing_param vc5_test_pv_muxing_invalid_params = { + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI0", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI1", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, HDMI0, HDMI1", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, DSI1, HDMI0, HDMI1", +@@ -620,19 +637,19 @@ static const struct pv_muxing_param vc5_test_pv_muxing_invalid_params = { + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI0", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI1", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI0, HDMI1", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI0, HDMI1", +@@ -643,27 +660,27 @@ static const struct pv_muxing_param vc5_test_pv_muxing_invalid_params = { + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI0, HDMI1", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: VEC, TXP, DSI1, HDMI0, HDMI1", + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI0, HDMI1", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI0, HDMI1", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), +@@ -673,6 +690,54 @@ KUNIT_ARRAY_PARAM(vc5_test_pv_muxing_invalid, + vc5_test_pv_muxing_invalid_params, + vc4_test_pv_muxing_desc); + ++static const struct pv_muxing_param vc6_test_pv_muxing_params = { ++ VC6_PV_MUXING_TEST("1 output: HDMI0", ++ VC4_ENCODER_TYPE_HDMI0), ++ VC6_PV_MUXING_TEST("1 output: HDMI1", ++ VC4_ENCODER_TYPE_HDMI1), ++ VC6_PV_MUXING_TEST("1 output: MOPLET", ++ VC4_ENCODER_TYPE_TXP1), ++ VC6_PV_MUXING_TEST("1 output: MOP", ++ VC4_ENCODER_TYPE_TXP0), ++ VC6_PV_MUXING_TEST("2 outputs: HDMI0, HDMI1", ++ VC4_ENCODER_TYPE_HDMI0, ++ VC4_ENCODER_TYPE_HDMI1), ++ VC6_PV_MUXING_TEST("2 outputs: HDMI0, MOPLET", ++ VC4_ENCODER_TYPE_HDMI0, ++ VC4_ENCODER_TYPE_TXP1), ++ VC6_PV_MUXING_TEST("2 outputs: HDMI0, MOP", ++ VC4_ENCODER_TYPE_HDMI0, ++ VC4_ENCODER_TYPE_TXP0), ++ VC6_PV_MUXING_TEST("2 outputs: HDMI1, MOP", ++ VC4_ENCODER_TYPE_HDMI1, ++ VC4_ENCODER_TYPE_TXP0), ++ VC6_PV_MUXING_TEST("2 outputs: MOPLET, MOP", ++ VC4_ENCODER_TYPE_TXP1, ++ VC4_ENCODER_TYPE_TXP0), ++ VC6_PV_MUXING_TEST("3 outputs: HDMI0, HDMI1, MOP", ++ VC4_ENCODER_TYPE_HDMI0, ++ VC4_ENCODER_TYPE_HDMI1, ++ VC4_ENCODER_TYPE_TXP0), ++ VC6_PV_MUXING_TEST("3 outputs: HDMI0, MOPLET, MOP", ++ VC4_ENCODER_TYPE_HDMI0, ++ VC4_ENCODER_TYPE_TXP1, ++ VC4_ENCODER_TYPE_TXP0), ++}; ++ ++KUNIT_ARRAY_PARAM(vc6_test_pv_muxing, ++ vc6_test_pv_muxing_params, ++ vc4_test_pv_muxing_desc); ++ ++static const struct pv_muxing_param vc6_test_pv_muxing_invalid_params = { ++ VC6_PV_MUXING_TEST("HDMI1/MOPLET Conflict", ++ VC4_ENCODER_TYPE_HDMI1, ++ VC4_ENCODER_TYPE_TXP1), ++}; ++ ++KUNIT_ARRAY_PARAM(vc6_test_pv_muxing_invalid, ++ vc6_test_pv_muxing_invalid_params, ++ vc4_test_pv_muxing_desc); ++ + static void drm_vc4_test_pv_muxing(struct kunit *test) + { + const struct pv_muxing_param *params = test->param_value; +@@ -682,10 +747,11 @@ static void drm_vc4_test_pv_muxing(struct kunit *test) + int ret; + + for (i = 0; i < params->nencoders; i++) { ++ struct vc4_dummy_output *output; + enum vc4_encoder_type enc_type = params->encodersi; + +- ret = vc4_mock_atomic_add_output(test, state, enc_type); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ output = vc4_mock_atomic_add_output(test, state, enc_type); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); + } + + ret = drm_atomic_check_only(state); +@@ -711,10 +777,11 @@ static void drm_vc4_test_pv_muxing_invalid(struct kunit *test) + int ret; + + for (i = 0; i < params->nencoders; i++) { ++ struct vc4_dummy_output *output; + enum vc4_encoder_type enc_type = params->encodersi; + +- ret = vc4_mock_atomic_add_output(test, state, enc_type); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ output = vc4_mock_atomic_add_output(test, state, enc_type); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); + } + + ret = drm_atomic_check_only(state); +@@ -775,6 +842,20 @@ static struct kunit_suite vc5_pv_muxing_test_suite = { + .test_cases = vc5_pv_muxing_tests, + }; + ++static struct kunit_case vc6_pv_muxing_tests = { ++ KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing, ++ vc6_test_pv_muxing_gen_params), ++ KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing_invalid, ++ vc6_test_pv_muxing_invalid_gen_params), ++ {} ++}; ++ ++static struct kunit_suite vc6_pv_muxing_test_suite = { ++ .name = "vc6-pv-muxing-combinations", ++ .init = vc4_pv_muxing_test_init, ++ .test_cases = vc6_pv_muxing_tests, ++}; ++ + /* See + * https://lore.kernel.org/all/3e113525-aa89-b1e2-56b7-ca55bd41d057@samsung.com/ + * and +@@ -784,6 +865,7 @@ static void drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable(struct kunit *tes + { + struct drm_modeset_acquire_ctx *ctx; + struct drm_atomic_state *state; ++ struct vc4_dummy_output *output; + struct vc4_crtc_state *new_vc4_crtc_state; + struct vc4_hvs_state *new_hvs_state; + unsigned int hdmi0_channel; +@@ -802,8 +884,8 @@ static void drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable(struct kunit *tes + state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +- ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ output = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); +@@ -825,8 +907,8 @@ static void drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable(struct kunit *tes + state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +- ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ output = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); +@@ -856,6 +938,7 @@ static void drm_test_vc5_pv_muxing_bugs_stable_fifo(struct kunit *test) + { + struct drm_modeset_acquire_ctx *ctx; + struct drm_atomic_state *state; ++ struct vc4_dummy_output *output; + struct vc4_crtc_state *new_vc4_crtc_state; + struct vc4_hvs_state *new_hvs_state; + unsigned int old_hdmi0_channel; +@@ -874,11 +957,11 @@ static void drm_test_vc5_pv_muxing_bugs_stable_fifo(struct kunit *test) + state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +- ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ output = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); + +- ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ output = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); +@@ -951,6 +1034,7 @@ drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable_too_many_crtc_state(struct ku + { + struct drm_modeset_acquire_ctx *ctx; + struct drm_atomic_state *state; ++ struct vc4_dummy_output *output; + struct vc4_crtc_state *new_vc4_crtc_state; + struct drm_device *drm; + struct vc4_dev *vc4; +@@ -966,8 +1050,8 @@ drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable_too_many_crtc_state(struct ku + state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +- ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ output = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); +@@ -978,8 +1062,8 @@ drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable_too_many_crtc_state(struct ku + state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +- ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ output = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); +@@ -1004,5 +1088,6 @@ static struct kunit_suite vc5_pv_muxing_bugs_test_suite = { + kunit_test_suites( + &vc4_pv_muxing_test_suite, + &vc5_pv_muxing_test_suite, ++ &vc6_pv_muxing_test_suite, + &vc5_pv_muxing_bugs_test_suite + ); +diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c +index 86d629e45307..06c791ace2d8 100644 +--- a/drivers/gpu/drm/vc4/vc4_bo.c ++++ b/drivers/gpu/drm/vc4/vc4_bo.c +@@ -251,7 +251,7 @@ void vc4_bo_add_to_purgeable_pool(struct vc4_bo *bo) + { + struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev); + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + mutex_lock(&vc4->purgeable.lock); +@@ -265,7 +265,7 @@ static void vc4_bo_remove_from_purgeable_pool_locked(struct vc4_bo *bo) + { + struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev); + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + /* list_del_init() is used here because the caller might release +@@ -396,7 +396,7 @@ struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size) + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_bo *bo; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return ERR_PTR(-ENODEV); + + bo = kzalloc(sizeof(*bo), GFP_KERNEL); +@@ -427,7 +427,7 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, + struct drm_gem_dma_object *dma_obj; + struct vc4_bo *bo; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return ERR_PTR(-ENODEV); + + if (size == 0) +@@ -496,7 +496,7 @@ int vc4_bo_dumb_create(struct drm_file *file_priv, + struct vc4_bo *bo = NULL; + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + ret = vc4_dumb_fixup_args(args); +@@ -622,7 +622,7 @@ int vc4_bo_inc_usecnt(struct vc4_bo *bo) + struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev); + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + /* Fast path: if the BO is already retained by someone, no need to +@@ -661,7 +661,7 @@ void vc4_bo_dec_usecnt(struct vc4_bo *bo) + { + struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev); + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + /* Fast path: if the BO is still retained by someone, no need to test +@@ -783,7 +783,7 @@ int vc4_create_bo_ioctl(struct drm_device *dev, void *data, + struct vc4_bo *bo = NULL; + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + ret = vc4_grab_bin_bo(vc4, vc4file); +@@ -813,7 +813,7 @@ int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data, + struct drm_vc4_mmap_bo *args = data; + struct drm_gem_object *gem_obj; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + gem_obj = drm_gem_object_lookup(file_priv, args->handle); +@@ -839,7 +839,7 @@ vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data, + struct vc4_bo *bo = NULL; + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (args->size == 0) +@@ -918,7 +918,7 @@ int vc4_set_tiling_ioctl(struct drm_device *dev, void *data, + struct vc4_bo *bo; + bool t_format; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (args->flags != 0) +@@ -964,7 +964,7 @@ int vc4_get_tiling_ioctl(struct drm_device *dev, void *data, + struct drm_gem_object *gem_obj; + struct vc4_bo *bo; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (args->flags != 0 || args->modifier != 0) +@@ -1007,7 +1007,7 @@ int vc4_bo_cache_init(struct drm_device *dev) + int ret; + int i; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + /* Create the initial set of BO labels that the kernel will +@@ -1071,7 +1071,7 @@ int vc4_label_bo_ioctl(struct drm_device *dev, void *data, + struct drm_gem_object *gem_obj; + int ret = 0, label; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (!args->len) +diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c +index 8b5a7e5eb146..b86b5dc00c15 100644 +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -83,13 +83,22 @@ static unsigned int + vc4_crtc_get_cob_allocation(struct vc4_dev *vc4, unsigned int channel) + { + struct vc4_hvs *hvs = vc4->hvs; +- u32 dispbase = HVS_READ(SCALER_DISPBASEX(channel)); ++ u32 dispbase, top, base; ++ + /* Top/base are supposed to be 4-pixel aligned, but the + * Raspberry Pi firmware fills the low bits (which are + * presumably ignored). + */ +- u32 top = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_TOP) & ~3; +- u32 base = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_BASE) & ~3; ++ ++ if (vc4->gen >= VC4_GEN_6) { ++ dispbase = HVS_READ(SCALER6_DISPX_COB(channel)); ++ top = VC4_GET_FIELD(dispbase, SCALER6_DISPX_COB_TOP) & ~3; ++ base = VC4_GET_FIELD(dispbase, SCALER6_DISPX_COB_BASE) & ~3; ++ } else { ++ dispbase = HVS_READ(SCALER_DISPBASEX(channel)); ++ top = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_TOP) & ~3; ++ base = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_BASE) & ~3; ++ } + + return top - base + 4; + } +@@ -105,6 +114,7 @@ static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc, + struct vc4_hvs *hvs = vc4->hvs; + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state); ++ unsigned int channel = vc4_crtc_state->assigned_channel; + unsigned int cob_size; + u32 val; + int fifo_lines; +@@ -121,7 +131,10 @@ static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc, + * Read vertical scanline which is currently composed for our + * pixelvalve by the HVS, and also the scaler status. + */ +- val = HVS_READ(SCALER_DISPSTATX(vc4_crtc_state->assigned_channel)); ++ if (vc4->gen >= VC4_GEN_6) ++ val = HVS_READ(SCALER6_DISPX_STATUS(channel)); ++ else ++ val = HVS_READ(SCALER_DISPSTATX(channel)); + + /* Get optional system timestamp after query. */ + if (etime) +@@ -130,18 +143,23 @@ static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc, + /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */ + + /* Vertical position of hvs composed scanline. */ +- *vpos = VC4_GET_FIELD(val, SCALER_DISPSTATX_LINE); ++ ++ if (vc4->gen >= VC4_GEN_6) ++ *vpos = VC4_GET_FIELD(val, SCALER6_DISPX_STATUS_YLINE); ++ else ++ *vpos = VC4_GET_FIELD(val, SCALER_DISPSTATX_LINE); ++ + *hpos = 0; + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) { + *vpos /= 2; + + /* Use hpos to correct for field offset in interlaced mode. */ +- if (vc4_hvs_get_fifo_frame_count(hvs, vc4_crtc_state->assigned_channel) % 2) ++ if (vc4_hvs_get_fifo_frame_count(hvs, channel) % 2) + *hpos += mode->crtc_htotal / 2; + } + +- cob_size = vc4_crtc_get_cob_allocation(vc4, vc4_crtc_state->assigned_channel); ++ cob_size = vc4_crtc_get_cob_allocation(vc4, channel); + /* This is the offset we need for translating hvs -> pv scanout pos. */ + fifo_lines = cob_size / mode->crtc_hdisplay; + +@@ -222,6 +240,11 @@ static u32 vc4_get_fifo_full_level(struct vc4_crtc *vc4_crtc, u32 format) + const struct vc4_crtc_data *crtc_data = vc4_crtc_to_vc4_crtc_data(vc4_crtc); + const struct vc4_pv_data *pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc); + struct vc4_dev *vc4 = to_vc4_dev(vc4_crtc->base.dev); ++ ++ /* ++ * NOTE: Could we use register 0x68 (PV_HW_CFG1) to get the FIFO ++ * size? ++ */ + u32 fifo_len_bytes = pv_data->fifo_depth; + + /* +@@ -263,7 +286,7 @@ static u32 vc4_get_fifo_full_level(struct vc4_crtc *vc4_crtc, u32 format) + * Removing 1 from the FIFO full level however + * seems to completely remove that issue. + */ +- if (!vc4->is_vc5) ++ if (vc4->gen == VC4_GEN_4) + return fifo_len_bytes - 3 * HVS_FIFO_LATENCY_PIX - 1; + + return fifo_len_bytes - 3 * HVS_FIFO_LATENCY_PIX; +@@ -303,6 +326,23 @@ struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc, + return NULL; + } + ++#define drm_for_each_connector_mask(connector, dev, connector_mask) \ ++ list_for_each_entry((connector), &(dev)->mode_config.connector_list, head) \ ++ for_each_if ((connector_mask) & drm_connector_mask(connector)) ++ ++struct drm_connector *vc4_get_crtc_connector(struct drm_crtc *crtc, ++ struct drm_crtc_state *state) ++{ ++ struct drm_connector *connector; ++ ++ WARN_ON(hweight32(state->connector_mask) > 1); ++ ++ drm_for_each_connector_mask(connector, crtc->dev, state->connector_mask) ++ return connector; + -+ if (connector->display_info.bus_flags & -+ DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) -+ dpi_c |= DPI_PIXEL_CLK_INVERT; ++ return NULL; ++} + -+ if (connector->display_info.bus_flags & DRM_BUS_FLAG_DE_LOW) -+ dpi_c |= DPI_OUTPUT_ENABLE_INVERT; + static void vc4_crtc_pixelvalve_reset(struct drm_crtc *crtc) + { + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); +@@ -403,6 +443,7 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode + */ + CRTC_WRITE(PV_V_CONTROL, + PV_VCONTROL_CONTINUOUS | ++ (vc4->gen >= VC4_GEN_6 ? PV_VCONTROL_ODD_TIMING : 0) | + (is_dsi ? PV_VCONTROL_DSI : 0) | + PV_VCONTROL_INTERLACE | + (odd_field_first +@@ -414,6 +455,7 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode } 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) -- dpi_c |= DPI_HSYNC_INVERT; -- else if (!(mode->flags & DRM_MODE_FLAG_PHSYNC)) -- dpi_c |= DPI_HSYNC_DISABLE; -+ if (mode->flags & DRM_MODE_FLAG_CSYNC) { -+ if (mode->flags & DRM_MODE_FLAG_NCSYNC) -+ dpi_c |= DPI_OUTPUT_ENABLE_INVERT; -+ } else { -+ dpi_c |= DPI_OUTPUT_ENABLE_MODE; -+ -+ if (mode->flags & DRM_MODE_FLAG_NHSYNC) -+ dpi_c |= DPI_HSYNC_INVERT; -+ else if (!(mode->flags & DRM_MODE_FLAG_PHSYNC)) -+ dpi_c |= DPI_HSYNC_DISABLE; - -- if (mode->flags & DRM_MODE_FLAG_NVSYNC) -- dpi_c |= DPI_VSYNC_INVERT; -- else if (!(mode->flags & DRM_MODE_FLAG_PVSYNC)) -- dpi_c |= DPI_VSYNC_DISABLE; -+ if (mode->flags & DRM_MODE_FLAG_NVSYNC) -+ dpi_c |= DPI_VSYNC_INVERT; -+ else if (!(mode->flags & DRM_MODE_FLAG_PVSYNC)) -+ dpi_c |= DPI_VSYNC_DISABLE; + CRTC_WRITE(PV_V_CONTROL, + PV_VCONTROL_CONTINUOUS | ++ (vc4->gen >= VC4_GEN_6 ? PV_VCONTROL_ODD_TIMING : 0) | + (is_dsi ? PV_VCONTROL_DSI : 0)); + CRTC_WRITE(PV_VSYNCD_EVEN, 0); + } +@@ -428,11 +470,17 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode + if (is_dsi) + CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep); + +- if (vc4->is_vc5) ++ if (vc4->gen >= VC4_GEN_5) + CRTC_WRITE(PV_MUX_CFG, + VC4_SET_FIELD(PV_MUX_CFG_RGB_PIXEL_MUX_MODE_NO_SWAP, + PV_MUX_CFG_RGB_PIXEL_MUX_MODE)); + ++ if (vc4->gen >= VC4_GEN_6) ++ CRTC_WRITE(PV_PIPE_INIT_CTRL, ++ VC4_SET_FIELD(1, PV_PIPE_INIT_CTRL_PV_INIT_WIDTH) | ++ VC4_SET_FIELD(1, PV_PIPE_INIT_CTRL_PV_INIT_IDLE) | ++ PV_PIPE_INIT_CTRL_PV_INIT_EN); ++ + CRTC_WRITE(PV_CONTROL, PV_CONTROL_FIFO_CLR | + vc4_crtc_get_fifo_full_level_bits(vc4_crtc, format) | + VC4_SET_FIELD(format, PV_CONTROL_FORMAT) | +@@ -458,8 +506,10 @@ static void require_hvs_enabled(struct drm_device *dev) + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_hvs *hvs = vc4->hvs; + +- WARN_ON_ONCE((HVS_READ(SCALER_DISPCTRL) & SCALER_DISPCTRL_ENABLE) != +- SCALER_DISPCTRL_ENABLE); ++ if (vc4->gen >= VC4_GEN_6) ++ WARN_ON_ONCE(!(HVS_READ(SCALER6_CONTROL) & SCALER6_CONTROL_HVS_EN)); ++ else ++ WARN_ON_ONCE(!(HVS_READ(SCALER_DISPCTRL) & SCALER_DISPCTRL_ENABLE)); + } + + static int vc4_crtc_disable(struct drm_crtc *crtc, +@@ -529,7 +579,11 @@ int vc4_crtc_disable_at_boot(struct drm_crtc *crtc) + if (!(of_device_is_compatible(vc4_crtc->pdev->dev.of_node, + "brcm,bcm2711-pixelvalve2") || + of_device_is_compatible(vc4_crtc->pdev->dev.of_node, +- "brcm,bcm2711-pixelvalve4"))) ++ "brcm,bcm2711-pixelvalve4") || ++ of_device_is_compatible(vc4_crtc->pdev->dev.of_node, ++ "brcm,bcm2712-pixelvalve0") || ++ of_device_is_compatible(vc4_crtc->pdev->dev.of_node, ++ "brcm,bcm2712-pixelvalve1"))) + return 0; + + if (!(CRTC_READ(PV_CONTROL) & PV_CONTROL_EN)) +@@ -603,6 +657,8 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc, + + vc4_crtc_disable(crtc, encoder, state, old_vc4_state->assigned_channel); + ++ vc4_hvs_atomic_disable(crtc, state); ++ + /* + * Make sure we issue a vblank event after disabling the CRTC if + * someone was waiting it. +@@ -735,10 +791,16 @@ int vc4_crtc_atomic_check(struct drm_crtc *crtc, + 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; ++ if (memcmp(&vc4_state->margins, &conn_state->tv.margins, ++ sizeof(vc4_state->margins))) { ++ memcpy(&vc4_state->margins, &conn_state->tv.margins, ++ sizeof(vc4_state->margins)); ++ ++ /* Need to force the dlist entries for all planes to be ++ * updated so that the dest rectangles are changed. ++ */ ++ crtc_state->zpos_changed = true; ++ } + break; + } + +@@ -781,14 +843,21 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_hvs *hvs = vc4->hvs; ++ unsigned int current_dlist; + u32 chan = vc4_crtc->current_hvs_channel; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + spin_lock(&vc4_crtc->irq_lock); ++ ++ if (vc4->gen >= VC4_GEN_6) ++ current_dlist = VC4_GET_FIELD(HVS_READ(SCALER6_DISPX_DL(chan)), ++ SCALER6_DISPX_DL_LACT); ++ else ++ current_dlist = HVS_READ(SCALER_DISPLACTX(chan)); ++ + if (vc4_crtc->event && +- (vc4_crtc->current_dlist == HVS_READ(SCALER_DISPLACTX(chan)) || +- vc4_crtc->feeds_txp)) { ++ (vc4_crtc->current_dlist == current_dlist || vc4_crtc->feeds_txp)) { + drm_crtc_send_vblank_event(crtc, vc4_crtc->event); + vc4_crtc->event = NULL; + drm_crtc_vblank_put(crtc); +@@ -799,7 +868,8 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) + * the CRTC and encoder already reconfigured, leading to + * underruns. This can be seen when reconfiguring the CRTC. + */ +- vc4_hvs_unmask_underrun(hvs, chan); ++ if (0 && vc4->gen < VC4_GEN_6) ++ vc4_hvs_unmask_underrun(hvs, chan); + } + spin_unlock(&vc4_crtc->irq_lock); + spin_unlock_irqrestore(&dev->event_lock, flags); +@@ -913,7 +983,7 @@ static int vc4_async_set_fence_cb(struct drm_device *dev, + struct dma_fence *fence; + int ret; + +- if (!vc4->is_vc5) { ++ if (vc4->gen == VC4_GEN_4) { + struct vc4_bo *bo = to_vc4_bo(&dma_bo->base); + + return vc4_queue_seqno_cb(dev, &flip_state->cb.seqno, bo->seqno, +@@ -1000,7 +1070,7 @@ static int vc4_async_page_flip(struct drm_crtc *crtc, + struct vc4_bo *bo = to_vc4_bo(&dma_bo->base); + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + /* +@@ -1043,7 +1113,7 @@ int vc4_page_flip(struct drm_crtc *crtc, + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + +- if (vc4->is_vc5) ++ if (vc4->gen > VC4_GEN_4) + return vc5_async_page_flip(crtc, fb, event, flags); + else + return vc4_async_page_flip(crtc, fb, event, flags); +@@ -1074,14 +1144,8 @@ void vc4_crtc_destroy_state(struct drm_crtc *crtc, + struct vc4_dev *vc4 = to_vc4_dev(crtc->dev); + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state); + +- if (drm_mm_node_allocated(&vc4_state->mm)) { +- unsigned long flags; +- +- spin_lock_irqsave(&vc4->hvs->mm_lock, flags); +- drm_mm_remove_node(&vc4_state->mm); +- spin_unlock_irqrestore(&vc4->hvs->mm_lock, flags); +- +- } ++ vc4_hvs_mark_dlist_entry_stale(vc4->hvs, vc4_state->mm); ++ vc4_state->mm = NULL; + + drm_atomic_helper_crtc_destroy_state(crtc, state); + } +@@ -1257,6 +1321,32 @@ const struct vc4_pv_data bcm2711_pv4_data = { + }, + }; + ++const struct vc4_pv_data bcm2712_pv0_data = { ++ .base = { ++ .debugfs_name = "crtc0_regs", ++ .hvs_available_channels = BIT(0), ++ .hvs_output = 0, ++ }, ++ .fifo_depth = 64, ++ .pixels_per_clock = 1, ++ .encoder_types = { ++ 0 = VC4_ENCODER_TYPE_HDMI0, ++ }, ++}; ++ ++const struct vc4_pv_data bcm2712_pv1_data = { ++ .base = { ++ .debugfs_name = "crtc1_regs", ++ .hvs_available_channels = BIT(1), ++ .hvs_output = 1, ++ }, ++ .fifo_depth = 64, ++ .pixels_per_clock = 1, ++ .encoder_types = { ++ 0 = VC4_ENCODER_TYPE_HDMI1, ++ }, ++}; ++ + static const struct of_device_id vc4_crtc_dt_match = { + { .compatible = "brcm,bcm2835-pixelvalve0", .data = &bcm2835_pv0_data }, + { .compatible = "brcm,bcm2835-pixelvalve1", .data = &bcm2835_pv1_data }, +@@ -1266,6 +1356,8 @@ static const struct of_device_id vc4_crtc_dt_match = { + { .compatible = "brcm,bcm2711-pixelvalve2", .data = &bcm2711_pv2_data }, + { .compatible = "brcm,bcm2711-pixelvalve3", .data = &bcm2711_pv3_data }, + { .compatible = "brcm,bcm2711-pixelvalve4", .data = &bcm2711_pv4_data }, ++ { .compatible = "brcm,bcm2712-pixelvalve0", .data = &bcm2712_pv0_data }, ++ { .compatible = "brcm,bcm2712-pixelvalve1", .data = &bcm2712_pv1_data }, + {} + }; + +@@ -1338,21 +1430,38 @@ int __vc4_crtc_init(struct drm_device *drm, + + drm_crtc_helper_add(crtc, crtc_helper_funcs); + +- if (!vc4->is_vc5) { ++ if (vc4->gen == VC4_GEN_4) { + drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r)); +- + drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size); + } ++ + ++ if (vc4->gen == VC4_GEN_4) { + /* We support CTM, but only for one CRTC at a time. It's therefore + * implemented as private driver state in vc4_kms, not here. + */ +- drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size); +- } ++ drm_crtc_enable_color_mgmt(crtc, 0, true, 0); + +- for (i = 0; i < crtc->gamma_size; i++) { +- vc4_crtc->lut_ri = i; +- vc4_crtc->lut_gi = i; +- vc4_crtc->lut_bi = i; ++ /* Initialize the VC4 gamma LUTs */ ++ for (i = 0; i < crtc->gamma_size; i++) { ++ vc4_crtc->lut_ri = i; ++ vc4_crtc->lut_gi = i; ++ vc4_crtc->lut_bi = i; ++ } ++ } else { ++ /* Initialize the VC5 gamma PWL entries. Assume 12-bit pipeline, ++ * evenly spread over full range. ++ */ ++ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++) { ++ vc4_crtc->pwl_ri = ++ VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8); ++ vc4_crtc->pwl_gi = ++ VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8); ++ vc4_crtc->pwl_bi = ++ VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8); ++ vc4_crtc->pwl_ai = ++ VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8); ++ } + } + + return 0; +diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c +index fac624a663ea..8144dedf2248 100644 +--- a/drivers/gpu/drm/vc4/vc4_debugfs.c ++++ b/drivers/gpu/drm/vc4/vc4_debugfs.c +@@ -24,7 +24,8 @@ vc4_debugfs_init(struct drm_minor *minor) + struct vc4_dev *vc4 = to_vc4_dev(minor->dev); + struct drm_device *drm = &vc4->base; - DPI_WRITE(DPI_C, dpi_c); +- drm_WARN_ON(drm, vc4_hvs_debugfs_init(minor)); ++ if (vc4->hvs) ++ drm_WARN_ON(drm, vc4_hvs_debugfs_init(minor)); + if (vc4->v3d) { + drm_WARN_ON(drm, vc4_bo_debugfs_init(minor)); diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c -index 839610f8092a..dec3620bc7c5 100644 +index 1b3531374967..220e8625402b 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c -@@ -36,6 +36,8 @@ - #include <drm/drm_fb_helper.h> - #include <drm/drm_vblank.h> +@@ -29,6 +29,7 @@ + #include <linux/of_device.h> + #include <linux/platform_device.h> + #include <linux/pm_runtime.h> ++#include <linux/dma-direct.h> -+#include <soc/bcm2835/raspberrypi-firmware.h> -+ - #include "uapi/drm/vc4_drm.h" + #include <drm/drm_aperture.h> + #include <drm/drm_atomic_helper.h> +@@ -98,7 +99,7 @@ static int vc4_get_param_ioctl(struct drm_device *dev, void *data, + if (args->pad != 0) + return -EINVAL; - #include "vc4_drv.h" -@@ -246,6 +248,28 @@ static void vc4_match_add_drivers(struct device *dev, - } +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (!vc4->v3d) +@@ -147,7 +148,7 @@ static int vc4_open(struct drm_device *dev, struct drm_file *file) + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_file *vc4file; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + vc4file = kzalloc(sizeof(*vc4file), GFP_KERNEL); +@@ -165,7 +166,7 @@ static void vc4_close(struct drm_device *dev, struct drm_file *file) + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_file *vc4file = file->driver_priv; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + if (vc4file->bin_bo_used) +@@ -175,6 +176,19 @@ static void vc4_close(struct drm_device *dev, struct drm_file *file) + kfree(vc4file); } -+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" }, -+ {} -+}; ++struct drm_gem_object * ++vc4_prime_import_sg_table(struct drm_device *dev, ++ struct dma_buf_attachment *attach, ++ struct sg_table *sgt) ++{ ++ phys_addr_t phys = dma_to_phys(dev->dev, sg_dma_address(sgt->sgl)); ++ ++ if (is_swiotlb_buffer(dev->dev, phys)) ++ return ERR_PTR(-EINVAL); ++ ++ return drm_gem_dma_prime_import_sg_table(dev, attach, sgt); ++} + + DEFINE_DRM_GEM_FOPS(vc4_drm_fops); + + static const struct drm_ioctl_desc vc4_drm_ioctls = { +@@ -211,7 +225,8 @@ const struct drm_driver vc4_drm_driver = { + + .gem_create_object = vc4_create_object, + +- DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(vc4_bo_dumb_create), ++ .dumb_create = vc4_bo_dumb_create, ++ .gem_prime_import_sg_table = vc4_prime_import_sg_table, + + .ioctls = vc4_drm_ioctls, + .num_ioctls = ARRAY_SIZE(vc4_drm_ioctls), +@@ -234,7 +249,8 @@ const struct drm_driver vc5_drm_driver = { + .debugfs_init = vc4_debugfs_init, + #endif + +- DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(vc5_dumb_create), ++ .dumb_create = vc5_dumb_create, ++ .gem_prime_import_sg_table = vc4_prime_import_sg_table, + + .fops = &vc4_drm_fops, + +@@ -275,13 +291,27 @@ static void vc4_component_unbind_all(void *ptr) + + static const struct of_device_id vc4_dma_range_matches = { + { .compatible = "brcm,bcm2711-hvs" }, ++ { .compatible = "brcm,bcm2712-hvs" }, + { .compatible = "brcm,bcm2835-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 @@ -59290,59 +87909,87 @@ static int vc4_drm_bind(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); -@@ -263,6 +287,16 @@ static int vc4_drm_bind(struct device *dev) - vc4_drm_driver.driver_features &= ~DRIVER_RENDER; - of_node_put(node); +@@ -291,17 +321,30 @@ static int vc4_drm_bind(struct device *dev) + struct vc4_dev *vc4; + struct device_node *node; + struct drm_crtc *crtc; +- bool is_vc5; ++ enum vc4_gen gen; ++ bool step_d0 = false; + int ret = 0; -+ 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; -+ } +- dev->coherent_dma_mask = DMA_BIT_MASK(32); ++ if (of_device_is_compatible(dev->of_node, "brcm,bcm2712d0-vc6")) { ++ gen = VC4_GEN_6; ++ step_d0 = true; ++ } else if (of_device_is_compatible(dev->of_node, "brcm,bcm2712-vc6")) ++ gen = VC4_GEN_6; ++ else if (of_device_is_compatible(dev->of_node, "brcm,bcm2711-vc5")) ++ gen = VC4_GEN_5; ++ else ++ gen = VC4_GEN_4; + +- is_vc5 = of_device_is_compatible(dev->of_node, "brcm,bcm2711-vc5"); +- if (is_vc5) ++ if (gen > VC4_GEN_4) + driver = &vc5_drm_driver; + else + driver = &vc4_drm_driver; + ++ if (gen >= VC4_GEN_6) ++ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36)); ++ else ++ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + - vc4 = devm_drm_dev_alloc(dev, &vc4_drm_driver, struct vc4_dev, base); + node = of_find_matching_node_and_match(NULL, vc4_dma_range_matches, + NULL); + if (node) { +@@ -315,13 +358,14 @@ static int vc4_drm_bind(struct device *dev) + vc4 = devm_drm_dev_alloc(dev, driver, struct vc4_dev, base); if (IS_ERR(vc4)) return PTR_ERR(vc4); -@@ -285,22 +319,43 @@ static int vc4_drm_bind(struct device *dev) +- vc4->is_vc5 = is_vc5; ++ vc4->gen = gen; ++ vc4->step_d0 = step_d0; + vc4->dev = dev; + + drm = &vc4->base; + platform_set_drvdata(pdev, drm); + +- if (!is_vc5) { ++ if (gen == VC4_GEN_4) { + ret = drmm_mutex_init(drm, &vc4->bin_bo_lock); + if (ret) + return ret; +@@ -335,7 +379,7 @@ static int vc4_drm_bind(struct device *dev) 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 (!is_vc5) { ++ if (gen == VC4_GEN_4) { + ret = vc4_gem_init(drm); + if (ret) + return ret; +@@ -354,7 +398,7 @@ static int vc4_drm_bind(struct device *dev) + if (ret) + return ret; + +- if (firmware) { ++ if (firmware && !firmware_kms()) { + ret = rpi_firmware_property(firmware, + RPI_FIRMWARE_NOTIFY_DISPLAY_DONE, + NULL, 0); +@@ -372,16 +416,20 @@ static int vc4_drm_bind(struct device *dev) 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; ++ return ret; + } ret = vc4_kms_load(drm); @@ -59358,102 +88005,191 @@ ret = drm_dev_register(drm, 0); if (ret < 0) -@@ -330,14 +385,24 @@ static const struct component_master_ops vc4_drm_ops = { - .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, +@@ -425,6 +473,7 @@ static struct platform_driver *const component_drivers = { &vc4_dsi_driver, -- &vc4_hvs_driver, &vc4_txp_driver, &vc4_crtc_driver, + &vc4_firmware_kms_driver, &vc4_v3d_driver, }; +@@ -436,6 +485,9 @@ static int vc4_platform_drm_probe(struct platform_device *pdev) + vc4_match_add_drivers(dev, &match, + component_drivers, ARRAY_SIZE(component_drivers)); + ++ if (!match) ++ return -ENODEV; ++ + return component_master_add_with_match(dev, &vc4_drm_ops, match); + } + +@@ -446,6 +498,8 @@ static void vc4_platform_drm_remove(struct platform_device *pdev) + + static const struct of_device_id vc4_of_match = { + { .compatible = "brcm,bcm2711-vc5", }, ++ { .compatible = "brcm,bcm2712-vc6", }, ++ { .compatible = "brcm,bcm2712d0-vc6", }, + { .compatible = "brcm,bcm2835-vc4", }, + { .compatible = "brcm,cygnus-vc4", }, + {}, diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h -index 9809c3a856c6..dd34de6e677b 100644 +index bf66499765fb..70703d28b0b5 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h -@@ -19,6 +19,7 @@ - #include <drm/drm_modeset_lock.h> +@@ -14,6 +14,7 @@ + #include <drm/drm_debugfs.h> + #include <drm/drm_device.h> + #include <drm/drm_encoder.h> ++#include <drm/drm_fourcc.h> + #include <drm/drm_gem_dma_helper.h> + #include <drm/drm_managed.h> + #include <drm/drm_mm.h> +@@ -22,6 +23,7 @@ + #include <kunit/test-bug.h> #include "uapi/drm/vc4_drm.h" +#include "vc4_regs.h" struct drm_device; struct drm_gem_object; -@@ -74,12 +75,16 @@ struct vc4_perfmon { +@@ -79,16 +81,27 @@ struct vc4_perfmon { + u64 counters; + }; + ++enum vc4_gen { ++ VC4_GEN_4, ++ VC4_GEN_5, ++ VC4_GEN_6, ++}; ++ struct vc4_dev { struct drm_device base; + struct device *dev; + +- bool is_vc5; ++ enum vc4_gen gen; ++ bool step_d0; + + unsigned int irq; + 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; -@@ -201,9 +206,6 @@ struct vc4_dev { - - 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; +@@ -309,13 +322,22 @@ struct vc4_v3d { + struct debugfs_regset32 regset; + }; -@@ -325,6 +327,7 @@ struct vc4_hvs { ++#define HVS_NUM_CHANNELS 3 ++ + struct vc4_hvs { + struct vc4_dev *vc4; + struct platform_device *pdev; + void __iomem *regs; u32 __iomem *dlist; ++ unsigned int dlist_mem_size; struct clk *core_clk; -+ struct clk_request *core_req; ++ struct clk *disp_clk; ++ ++ struct { ++ unsigned int desc; ++ unsigned int enabled: 1; ++ } eof_irqHVS_NUM_CHANNELS; + + unsigned long max_core_rate; + +@@ -325,8 +347,16 @@ struct vc4_hvs { + struct drm_mm dlist_mm; + /* Memory manager for the LBM memory used by HVS scaling. */ + struct drm_mm lbm_mm; ++ ++ /* Memory manager for the UPM memory used for prefetching. */ ++ struct drm_mm upm_mm; ++ struct ida upm_handles; ++ + spinlock_t mm_lock; + ++ struct list_head stale_dlist_entries; ++ struct work_struct free_dlist_work; ++ + struct drm_mm_node mitchell_netravali_filter; - /* Memory manager for CRTCs to allocate space in the display - * list. Units are dwords. -@@ -444,12 +447,12 @@ struct vc4_encoder { - 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); + struct debugfs_regset32 regset; +@@ -346,7 +376,7 @@ struct vc4_hvs { + bool vc5_hdmi_enable_4096by2160; }; - static inline struct vc4_encoder * -@@ -480,6 +483,17 @@ struct vc4_pv_data { +-#define HVS_NUM_CHANNELS 3 ++#define HVS_UBM_WORD_SIZE 256 + + struct vc4_hvs_state { + struct drm_private_state base; +@@ -388,12 +418,14 @@ struct vc4_plane_state { + u32 dlist_size; /* Number of dwords allocated for the display list */ + u32 dlist_count; /* Number of used dwords in the display list. */ + ++ u32 lbm_size; /* LBM requirements for this plane */ ++ + /* Offset in the dlist to various words, for pageflip or + * cursor updates. + */ + u32 pos0_offset; + u32 pos2_offset; +- u32 ptr0_offset; ++ u32 ptr0_offsetDRM_FORMAT_MAX_PLANES; + u32 lbm_offset; + + /* Offset where the plane's dlist was last stored in the +@@ -403,7 +435,7 @@ struct vc4_plane_state { + + /* Clipped coordinates of the plane on the display. */ + int crtc_x, crtc_y, crtc_w, crtc_h; +- /* Clipped area being scanned from in the FB. */ ++ /* Clipped area being scanned from in the FB in u16.16 format */ + u32 src_x, src_y; + + u32 src_w2, src_h2; +@@ -413,13 +445,14 @@ struct vc4_plane_state { + bool is_unity; + bool is_yuv; +- /* Offset to start scanning out from the start of the plane's +- * BO. +- */ +- u32 offsets3; ++ /* Our allocation in UPM for prefetching. */ ++ struct drm_mm_node upmDRM_FORMAT_MAX_PLANES; + +- /* Our allocation in LBM for temporary storage during scaling. */ +- struct drm_mm_node lbm; ++ /* The Unified Pre-Fetcher Handle */ ++ unsigned int upm_handleDRM_FORMAT_MAX_PLANES; ++ ++ /* Number of lines to pre-fetch */ ++ unsigned int upm_buffer_lines; + + /* Set when the plane has per-pixel alpha content or does not cover + * the entire screen. This is a hint to the CRTC that it might need +@@ -455,7 +488,8 @@ enum vc4_encoder_type { + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_SMI, + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, ++ VC4_ENCODER_TYPE_TXP1, }; + struct vc4_encoder { +@@ -490,6 +524,17 @@ struct drm_encoder *vc4_find_encoder_by_type(struct drm_device *drm, + return NULL; + } + +struct vc5_gamma_entry { + u32 x_c_terms; + u32 grad_term; @@ -59465,10 +88201,39 @@ + .grad_term = (g) \ +} + + struct vc4_crtc_data { + const char *name; + +@@ -502,7 +547,18 @@ struct vc4_crtc_data { + int hvs_output; + }; + +-extern const struct vc4_crtc_data vc4_txp_crtc_data; ++struct vc4_txp_data { ++ struct vc4_crtc_data base; ++ enum vc4_encoder_type encoder_type; ++ unsigned int high_addr_ptr_reg; ++ unsigned int has_byte_enable:1; ++ unsigned int size_minus_one:1; ++ unsigned int supports_40bit_addresses:1; ++}; ++ ++extern const struct vc4_txp_data bcm2712_mop_data; ++extern const struct vc4_txp_data bcm2712_moplet_data; ++extern const struct vc4_txp_data bcm2835_txp_data; + + struct vc4_pv_data { + struct vc4_crtc_data base; +@@ -524,6 +580,8 @@ extern const struct vc4_pv_data bcm2711_pv1_data; + extern const struct vc4_pv_data bcm2711_pv2_data; + extern const struct vc4_pv_data bcm2711_pv3_data; + extern const struct vc4_pv_data bcm2711_pv4_data; ++extern const struct vc4_pv_data bcm2712_pv0_data; ++extern const struct vc4_pv_data bcm2712_pv1_data; + struct vc4_crtc { struct drm_crtc base; - struct platform_device *pdev; -@@ -489,13 +503,50 @@ struct vc4_crtc { +@@ -534,9 +592,19 @@ struct vc4_crtc { /* Timestamp at start of vblank irq - unaffected by lock delays. */ ktime_t t_vblank; @@ -59491,65 +88256,66 @@ struct drm_pending_vblank_event *event; - struct debugfs_regset32 regset; -+ -+ /** -+ * @feeds_txp: True if the CRTC feeds our writeback controller. -+ */ -+ bool feeds_txp; -+ -+ /** -+ * @irq_lock: Spinlock protecting the resources shared between -+ * the atomic code and our vblank handler. -+ */ -+ spinlock_t irq_lock; -+ -+ /** -+ * @current_dlist: Start offset of the display list currently -+ * set in the HVS for that CRTC. Protected by @irq_lock, and -+ * copied in vc4_hvs_update_dlist() for the CRTC interrupt -+ * handler to have access to that value. -+ */ -+ unsigned int current_dlist; +@@ -568,6 +636,9 @@ struct vc4_crtc { + * access to that value. + */ + unsigned int current_hvs_channel; + -+ /** -+ * @current_hvs_channel: HVS channel currently assigned to the -+ * CRTC. Protected by @irq_lock, and copied in -+ * vc4_hvs_atomic_begin() for the CRTC interrupt handler to have -+ * access to that value. -+ */ -+ unsigned int current_hvs_channel; ++ /* @lbm: Our allocation in LBM for temporary storage during scaling. */ ++ struct drm_mm_node lbm; }; - static inline struct vc4_crtc * -@@ -518,11 +569,16 @@ vc4_crtc_to_vc4_pv_data(const struct vc4_crtc *crtc) - return container_of(data, struct vc4_pv_data, base); + #define to_vc4_crtc(_crtc) \ +@@ -587,22 +658,27 @@ vc4_crtc_to_vc4_pv_data(const struct vc4_crtc *crtc) + return container_of_const(data, struct vc4_pv_data, base); } +struct drm_connector *vc4_get_crtc_connector(struct drm_crtc *crtc, + struct drm_crtc_state *state); + -+struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc, -+ struct drm_crtc_state *state); + struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc, + struct drm_crtc_state *state); + ++struct vc4_hvs_dlist_allocation { ++ struct list_head node; ++ struct drm_mm_node mm_node; ++ unsigned int channel; ++ u8 target_frame_count; ++ bool dlist_programmed; ++}; + struct vc4_crtc_state { struct drm_crtc_state base; - /* Dlist area for this CRTC configuration. */ - struct drm_mm_node mm; -- bool feed_txp; +- /* Dlist area for this CRTC configuration. */ +- struct drm_mm_node mm; ++ struct vc4_hvs_dlist_allocation *mm; bool txp_armed; unsigned int assigned_channel; -@@ -533,6 +589,8 @@ struct vc4_crtc_state { - unsigned int bottom; - } margins; - -+ unsigned long hvs_load; +- struct { +- unsigned int left; +- unsigned int right; +- unsigned int top; +- unsigned int bottom; +- } margins; ++ struct drm_connector_tv_margins margins; + + unsigned long hvs_load; + +@@ -639,6 +715,12 @@ struct vc4_crtc_state { + writel(val, hvs->regs + (offset)); \ + } while (0) + ++#define HVS_READ6(offset) \ ++ HVS_READ(hvs->vc4->step_d0 ? SCALER6_ ## offset : SCALER6D0_ ## offset) \ + - /* Transitional state below, only valid during atomic commits */ - bool update_muxing; - }; -@@ -877,6 +935,9 @@ extern struct platform_driver vc4_dsi_driver; ++#define HVS_WRITE6(offset, val) \ ++ HVS_WRITE(hvs->vc4->step_d0 ? SCALER6_ ## offset : SCALER6D0_ ## offset, val) \ ++ + #define VC4_REG32(reg) { .name = #reg, .offset = reg } + + struct vc4_exec_info { +@@ -963,6 +1045,9 @@ extern struct platform_driver vc4_dsi_driver; /* vc4_fence.c */ extern const struct dma_fence_ops vc4_fence_ops; @@ -59559,606 +88325,41 @@ /* vc4_gem.c */ int vc4_gem_init(struct drm_device *dev); int vc4_submit_cl_ioctl(struct drm_device *dev, void *data, -@@ -917,10 +978,11 @@ void vc4_irq_reset(struct drm_device *dev); - 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_begin(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 --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c -index eaf276978ee7..1c6939c9c232 100644 ---- a/drivers/gpu/drm/vc4/vc4_dsi.c -+++ b/drivers/gpu/drm/vc4/vc4_dsi.c -@@ -181,8 +181,50 @@ - - #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) -@@ -306,11 +348,11 @@ - # 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) -@@ -493,6 +535,18 @@ - */ - #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; -@@ -509,8 +563,7 @@ struct vc4_dsi { - 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; -@@ -586,10 +639,10 @@ dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val) - #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 { -@@ -750,6 +803,9 @@ static void vc4_dsi_encoder_disable(struct drm_encoder *encoder) - 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); -@@ -794,11 +850,9 @@ static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder, - /* Find what divider gets us a faster clock than the requested - * pixel clock. - */ -- for (divider = 1; divider < 8; divider++) { -- if (parent_rate / divider < pll_clock) { -- divider--; -+ for (divider = 1; divider < 7; divider++) { -+ if (parent_rate / (divider + 1) < pll_clock) - break; -- } - } - - /* Now that we've picked a PLL divider, calculate back to its -@@ -837,7 +891,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) - - 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; - } - -@@ -871,7 +925,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) - 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)); - -@@ -883,6 +937,9 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) - - 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) | -@@ -1017,7 +1074,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) - 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))); - -@@ -1043,18 +1100,15 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) - 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); - -@@ -1173,13 +1227,28 @@ static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host, - /* 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. */ -@@ -1196,7 +1265,7 @@ static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host, - 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; -@@ -1242,7 +1311,7 @@ static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host, - 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; - } - -@@ -1305,8 +1374,32 @@ static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = { - .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 }, - {} - }; - -@@ -1317,7 +1410,7 @@ static void dsi_handle_error(struct vc4_dsi *dsi, - 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; - } - -@@ -1351,26 +1444,28 @@ static irqreturn_t vc4_dsi_irq_handler(int irq, void *data) - 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; -@@ -1390,12 +1485,12 @@ vc4_dsi_init_phy_clocks(struct vc4_dsi *dsi) - 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; - -@@ -1411,8 +1506,12 @@ vc4_dsi_init_phy_clocks(struct vc4_dsi *dsi) - for (i = 0; i < ARRAY_SIZE(phy_clocks); i++) { - struct clk_fixed_factor *fix = &dsi->phy_clocksi; - struct clk_init_data init; -+ char clk_name16; - int ret; - -+ snprintf(clk_name, sizeof(clk_name), -+ "dsi%u_%s", dsi->variant->port, phy_clocksi.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 -@@ -1429,10 +1528,7 @@ vc4_dsi_init_phy_clocks(struct vc4_dsi *dsi) - memset(&init, 0, sizeof(init)); - init.parent_names = &parent_name; - init.num_parents = 1; -- if (dsi->port == 1) -- init.name = phy_clocksi.dsi1_name; -- else -- init.name = phy_clocksi.dsi0_name; -+ init.name = clk_name; - init.ops = &clk_fixed_factor_ops; - - ret = devm_clk_hw_register(dev, &fix->hw); -@@ -1451,7 +1547,6 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) - { - struct platform_device *pdev = to_platform_device(dev); - struct drm_device *drm = dev_get_drvdata(master); -- struct vc4_dev *vc4 = to_vc4_dev(drm); - struct vc4_dsi *dsi = dev_get_drvdata(dev); - struct vc4_dsi_encoder *vc4_dsi_encoder; - struct drm_panel *panel; -@@ -1463,7 +1558,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) - 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); -@@ -1471,7 +1566,8 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) - 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; - -@@ -1480,13 +1576,8 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) - 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", -@@ -1494,11 +1585,11 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) - 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); -@@ -1515,7 +1606,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) - if (ret != -EPROBE_DEFER) - DRM_ERROR("Failed to get DMA channel: %d\n", - ret); -- return ret; -+ goto err_free_dma_mem; - } - - /* Get the physical address of the device's registers. The -@@ -1544,7 +1635,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to get interrupt: %d\n", ret); -- return ret; -+ goto err_free_dma; - } - - dsi->escape_clock = devm_clk_get(dev, "escape"); -@@ -1552,7 +1643,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) - ret = PTR_ERR(dsi->escape_clock); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to get escape clock: %d\n", ret); -- return ret; -+ goto err_free_dma; - } - - dsi->pll_phy_clock = devm_clk_get(dev, "phy"); -@@ -1560,7 +1651,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) - ret = PTR_ERR(dsi->pll_phy_clock); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to get phy clock: %d\n", ret); -- return ret; -+ goto err_free_dma; - } - - dsi->pixel_clock = devm_clk_get(dev, "pixel"); -@@ -1568,7 +1659,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) - ret = PTR_ERR(dsi->pixel_clock); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to get pixel clock: %d\n", ret); -- return ret; -+ goto err_free_dma; - } - - ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, -@@ -1583,29 +1674,28 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) - if (ret == -ENODEV) - return 0; - -- return ret; -+ goto err_free_dma; - } - - if (panel) { - dsi->bridge = devm_drm_panel_bridge_add_typed(dev, panel, - DRM_MODE_CONNECTOR_DSI); -- if (IS_ERR(dsi->bridge)) -- return PTR_ERR(dsi->bridge); -+ if (IS_ERR(dsi->bridge)) { -+ ret = PTR_ERR(dsi->bridge); -+ goto err_free_dma; -+ } - } - - /* The esc clock rate is supposed to always be 100Mhz. */ - ret = clk_set_rate(dsi->escape_clock, 100 * 1000000); - if (ret) { - dev_err(dev, "Failed to set esc clock: %d\n", ret); -- return ret; -+ goto err_free_dma; - } - - ret = vc4_dsi_init_phy_clocks(dsi); - if (ret) -- return ret; -- -- if (dsi->port == 1) -- vc4->dsi1 = dsi; -+ goto err_free_dma; - - drm_simple_encoder_init(drm, dsi->encoder, DRM_MODE_ENCODER_DSI); - drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs); -@@ -1613,7 +1703,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) - ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL, 0); - if (ret) { - dev_err(dev, "bridge attach failed: %d\n", ret); -- return ret; -+ goto err_free_dma; - } - /* Disable the atomic helper calls into the bridge. We - * manually call the bridge pre_enable / enable / etc. calls -@@ -1622,21 +1712,29 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) - */ - 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); - - return 0; -+ -+err_free_dma: -+ if (dsi->reg_dma_chan) { -+ dma_release_channel(dsi->reg_dma_chan); -+ dsi->reg_dma_chan = NULL; -+ } -+err_free_dma_mem: -+ if (dsi->reg_dma_mem) { -+ dma_free_coherent(dev, 4, dsi->reg_dma_mem, dsi->reg_dma_paddr); -+ dsi->reg_dma_mem = NULL; -+ } -+ -+ return ret; - } - - 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) -@@ -1649,8 +1747,15 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master, - list_splice_init(&dsi->bridge_chain, &dsi->encoder->bridge_chain); - drm_encoder_cleanup(dsi->encoder); - -- if (dsi->port == 1) -- vc4->dsi1 = NULL; -+ if (dsi->reg_dma_chan) { -+ dma_release_channel(dsi->reg_dma_chan); -+ dsi->reg_dma_chan = NULL; -+ } -+ -+ if (dsi->reg_dma_mem) { -+ dma_free_coherent(dev, 4, dsi->reg_dma_mem, dsi->reg_dma_paddr); -+ dsi->reg_dma_mem = NULL; -+ } - } +@@ -1001,10 +1086,14 @@ void vc4_irq_reset(struct drm_device *dev); - static const struct component_ops vc4_dsi_ops = { + /* vc4_hvs.c */ + extern struct platform_driver vc4_hvs_driver; +-struct vc4_hvs *__vc4_hvs_alloc(struct vc4_dev *vc4, struct platform_device *pdev); ++struct vc4_hvs *__vc4_hvs_alloc(struct vc4_dev *vc4, ++ void __iomem *regs, ++ struct platform_device *pdev); + void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int output); + int vc4_hvs_get_fifo_from_output(struct vc4_hvs *hvs, unsigned int output); + u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo); ++void vc4_hvs_mark_dlist_entry_stale(struct vc4_hvs *hvs, ++ struct vc4_hvs_dlist_allocation *alloc); + int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state); + void vc4_hvs_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state); + void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state); +@@ -1022,6 +1111,12 @@ int vc4_kms_load(struct drm_device *dev); + struct drm_plane *vc4_plane_init(struct drm_device *dev, + enum drm_plane_type type, + uint32_t possible_crtcs); ++void vc4_plane_reset(struct drm_plane *plane); ++void vc4_plane_destroy_state(struct drm_plane *plane, ++ struct drm_plane_state *state); ++struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane); ++int vc4_plane_atomic_check(struct drm_plane *plane, ++ struct drm_atomic_state *state); + int vc4_plane_create_additional_planes(struct drm_device *dev); + u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist); + u32 vc4_plane_dlist_size(const struct drm_plane_state *state); diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c new file mode 100644 -index 000000000000..d6d50b5f64dd +index 000000000000..11ee7eadc804 --- /dev/null +++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -0,0 +1,1992 @@ +@@ -0,0 +1,2077 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2016 Broadcom @@ -60178,10 +88379,13 @@ + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc_helper.h> ++#include <drm/drm_blend.h> +#include <drm/drm_drv.h> -+#include <drm/drm_fb_cma_helper.h> ++#include <drm/drm_edid.h> ++#include <drm/drm_fb_dma_helper.h> +#include <drm/drm_fourcc.h> -+#include <drm/drm_gem_framebuffer_helper.h> ++#include <drm/drm_framebuffer.h> ++#include <drm/drm_gem_atomic_helper.h> +#include <drm/drm_plane_helper.h> +#include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> @@ -60205,9 +88409,15 @@ + u32 max_pixel_clock2; //Max pixel clock for each display +}; + ++enum vc4_fkms_revision { ++ BCM2835_6_7, ++ BCM2711, ++ BCM2712, ++}; ++ +struct vc4_fkms { + struct get_display_cfg cfg; -+ bool bcm2711; ++ enum vc4_fkms_revision revision; +}; + +#define PLANES_PER_CRTC 8 @@ -60342,18 +88552,22 @@ + .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_XBGR8888, ++ .vc_image = VC_IMAGE_RGBX32, ++ }, ++ { ++ .drm = DRM_FORMAT_ABGR8888, ++ .vc_image = VC_IMAGE_RGBA32, ++ }, ++ { ++ .drm = DRM_FORMAT_RGBX8888, ++ .vc_image = VC_IMAGE_BGRX8888, ++ }, ++ { ++ .drm = DRM_FORMAT_BGRX8888, ++ .vc_image = VC_IMAGE_RGBX8888, ++ }, + { + .drm = DRM_FORMAT_RGB565, + .vc_image = VC_IMAGE_RGB565, @@ -60417,9 +88631,7 @@ +/* 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 vc4_fkms_crtc { + struct drm_crtc base; + struct drm_encoder *encoder; + struct drm_connector *connector; @@ -60431,9 +88643,9 @@ + u32 display_type; +}; + -+static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc) ++static inline struct vc4_fkms_crtc *to_vc4_fkms_crtc(struct drm_crtc *crtc) +{ -+ return container_of(crtc, struct vc4_crtc, base); ++ return container_of(crtc, struct vc4_fkms_crtc, base); +} + +struct vc4_fkms_encoder { @@ -60641,7 +88853,7 @@ +} + +static void vc4_plane_atomic_update(struct drm_plane *plane, -+ struct drm_plane_state *old_state) ++ struct drm_atomic_state *old_state) +{ + struct drm_plane_state *state = plane->state; + @@ -60657,7 +88869,7 @@ +} + +static void vc4_plane_atomic_disable(struct drm_plane *plane, -+ struct drm_plane_state *old_state) ++ struct drm_atomic_state *old_state) +{ + struct drm_plane_state *state = plane->state; + struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); @@ -60682,7 +88894,7 @@ + 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); ++ struct drm_gem_dma_object *bo; + const struct drm_format_info *drm_fmt = fb->format; + const struct vc_image_format *vc_fmt = + vc4_get_vc_image_fmt(drm_fmt->format); @@ -60706,7 +88918,8 @@ + state->normalized_zpos : -127; + mb->plane.num_planes = num_planes; + mb->plane.is_vu = vc_fmt->is_vu; -+ mb->plane.planes0 = bo->paddr + fb->offsets0; ++ bo = drm_fb_dma_get_gem_obj(fb, 0); ++ mb->plane.planes0 = bo->dma_addr + fb->offsets0; + + rotation = drm_rotation_simplify(state->rotation, + DRM_MODE_ROTATE_0 | @@ -60726,11 +88939,14 @@ + /* Makes assumptions on the stride for the chroma planes as we + * can't easily plumb in non-standard pitches. + */ -+ mb->plane.planes1 = bo->paddr + fb->offsets1; -+ if (num_planes > 2) -+ mb->plane.planes2 = bo->paddr + fb->offsets2; -+ else ++ bo = drm_fb_dma_get_gem_obj(fb, 1); ++ mb->plane.planes1 = bo->dma_addr + fb->offsets1; ++ if (num_planes > 2) { ++ bo = drm_fb_dma_get_gem_obj(fb, 2); ++ mb->plane.planes2 = bo->dma_addr + fb->offsets2; ++ } else { + mb->plane.planes2 = 0; ++ } + + /* Special case the YUV420 with U and V as line interleaved + * planes as we have special handling for that case. @@ -60820,19 +89036,65 @@ + return 0; +} + -+static int vc4_plane_atomic_check(struct drm_plane *plane, -+ struct drm_plane_state *state) ++static int vc4_fkms_plane_atomic_check(struct drm_plane *plane, ++ struct drm_atomic_state *state) +{ ++ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, ++ plane); + struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); + -+ if (!plane_enabled(state)) ++ if (!plane_enabled(new_plane_state)) + return 0; + -+ return vc4_plane_to_mb(plane, &vc4_plane->mb, state); ++ return vc4_plane_to_mb(plane, &vc4_plane->mb, new_plane_state); ++} ++ ++static void vc4_plane_atomic_async_update(struct drm_plane *plane, ++ struct drm_atomic_state *state) ++{ ++ struct drm_plane_state *new_plane_state = ++ drm_atomic_get_new_plane_state(state, plane); ++ ++ swap(plane->state->fb, new_plane_state->fb); ++ plane->state->crtc_x = new_plane_state->crtc_x; ++ plane->state->crtc_y = new_plane_state->crtc_y; ++ plane->state->crtc_w = new_plane_state->crtc_w; ++ plane->state->crtc_h = new_plane_state->crtc_h; ++ plane->state->src_x = new_plane_state->src_x; ++ plane->state->src_y = new_plane_state->src_y; ++ plane->state->src_w = new_plane_state->src_w; ++ plane->state->src_h = new_plane_state->src_h; ++ plane->state->alpha = new_plane_state->alpha; ++ plane->state->pixel_blend_mode = new_plane_state->pixel_blend_mode; ++ plane->state->rotation = new_plane_state->rotation; ++ plane->state->zpos = new_plane_state->zpos; ++ plane->state->normalized_zpos = new_plane_state->normalized_zpos; ++ plane->state->color_encoding = new_plane_state->color_encoding; ++ plane->state->color_range = new_plane_state->color_range; ++ plane->state->src = new_plane_state->src; ++ plane->state->dst = new_plane_state->dst; ++ plane->state->visible = new_plane_state->visible; ++ ++ vc4_plane_set_blank(plane, false); ++} ++ ++static int vc4_plane_atomic_async_check(struct drm_plane *plane, ++ struct drm_atomic_state *state) ++{ ++ struct drm_plane_state *new_plane_state = ++ drm_atomic_get_new_plane_state(state, plane); ++ int ret = -EINVAL; ++ ++ if (plane->type == 2 && ++ plane->state->fb && ++ new_plane_state->crtc->state->active) ++ ret = 0; ++ ++ return ret; +} + +/* Called during init to allocate the plane's atomic state. */ -+static void vc4_plane_reset(struct drm_plane *plane) ++static void vc4_fkms_plane_reset(struct drm_plane *plane) +{ + struct vc4_plane_state *vc4_state; + @@ -60892,7 +89154,7 @@ + } +} + -+static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) ++static struct drm_plane_state *vc4_fkms_plane_duplicate_state(struct drm_plane *plane) +{ + struct vc4_plane_state *vc4_state; + @@ -60913,18 +89175,20 @@ + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = vc4_plane_destroy, + .set_property = NULL, -+ .reset = vc4_plane_reset, -+ .atomic_duplicate_state = vc4_plane_duplicate_state, ++ .reset = vc4_fkms_plane_reset, ++ .atomic_duplicate_state = vc4_fkms_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, + .format_mod_supported = vc4_fkms_format_mod_supported, +}; + +static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = { -+ .prepare_fb = drm_gem_fb_prepare_fb, ++ .prepare_fb = drm_gem_plane_helper_prepare_fb, + .cleanup_fb = NULL, -+ .atomic_check = vc4_plane_atomic_check, ++ .atomic_check = vc4_fkms_plane_atomic_check, + .atomic_update = vc4_plane_atomic_update, + .atomic_disable = vc4_plane_atomic_disable, ++ .atomic_async_check = vc4_plane_atomic_async_check, ++ .atomic_async_update = vc4_plane_atomic_async_update, +}; + +static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev, @@ -61026,10 +89290,10 @@ +{ + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); -+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct vc4_fkms_crtc *vc4_fkms_crtc = to_vc4_fkms_crtc(crtc); + struct drm_display_mode *mode = &crtc->state->adjusted_mode; + struct vc4_fkms_encoder *vc4_encoder = -+ to_vc4_fkms_encoder(vc4_crtc->encoder); ++ to_vc4_fkms_encoder(vc4_fkms_crtc->encoder); + struct mailbox_set_mode mb = { + .tag1 = { RPI_FIRMWARE_SET_TIMING, + sizeof(struct set_timings), 0}, @@ -61037,20 +89301,20 @@ + union hdmi_infoframe frame; + int ret; + -+ ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, vc4_crtc->connector, mode); ++ ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, vc4_fkms_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, ++ vc4_fkms_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.display = vc4_fkms_crtc->display_number; + + mb.timings.clock = mode->clock; + mb.timings.hdisplay = mode->hdisplay; @@ -61100,7 +89364,7 @@ + mb.timings.flags |= TIMINGS_FLAGS_DVI; + } else { + struct vc4_fkms_connector_state *conn_state = -+ to_vc4_fkms_connector_state(vc4_crtc->connector->state); ++ to_vc4_fkms_connector_state(vc4_fkms_crtc->connector->state); + + if (conn_state->broadcast_rgb == VC4_BROADCAST_RGB_AUTO) { + /* See CEA-861-E - 5.1 Default Encoding Parameters */ @@ -61160,7 +89424,7 @@ + */ + + drm_atomic_crtc_for_each_plane(plane, crtc) -+ vc4_plane_atomic_disable(plane, plane->state); ++ vc4_plane_atomic_disable(plane, state); + + /* + * Make sure we issue a vblank event after disabling the CRTC if @@ -61178,7 +89442,7 @@ + +static void vc4_crtc_consume_event(struct drm_crtc *crtc) +{ -+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct vc4_fkms_crtc *vc4_fkms_crtc = to_vc4_fkms_crtc(crtc); + struct drm_device *dev = crtc->dev; + unsigned long flags; + @@ -61190,7 +89454,7 @@ + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + + spin_lock_irqsave(&dev->event_lock, flags); -+ vc4_crtc->event = crtc->state->event; ++ vc4_fkms_crtc->event = crtc->state->event; + crtc->state->event = NULL; + spin_unlock_irqrestore(&dev->event_lock, flags); +} @@ -61214,7 +89478,7 @@ +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 vc4_fkms_crtc *vc4_fkms_crtc = to_vc4_fkms_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_fkms *fkms = vc4->fkms; @@ -61235,7 +89499,7 @@ + /* Limit the pixel clock based on the HDMI clock limits from the + * firmware + */ -+ switch (vc4_crtc->display_number) { ++ switch (vc4_fkms_crtc->display_number) { + case 2: /* HDMI0 */ + if (fkms->cfg.max_pixel_clock0 && + mode->clock > fkms->cfg.max_pixel_clock0) @@ -61251,8 +89515,8 @@ + /* 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) && ++ if (fkms->revision >= BCM2711 && ++ (vc4_fkms_crtc->display_number == 2 || vc4_fkms_crtc->display_number == 7) && + !(mode->flags & DRM_MODE_FLAG_DBLCLK) && + ((mode->hdisplay | /* active */ + (mode->hsync_start - mode->hdisplay) | /* front porch */ @@ -61267,7 +89531,7 @@ + return MODE_OK; +} + -+static int vc4_crtc_atomic_check(struct drm_crtc *crtc, ++static int vc4_fkms_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, @@ -61304,16 +89568,16 @@ + vc4_crtc_consume_event(crtc); +} + -+static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) ++static void vc4_crtc_handle_page_flip(struct vc4_fkms_crtc *vc4_fkms_crtc) +{ -+ struct drm_crtc *crtc = &vc4_crtc->base; ++ struct drm_crtc *crtc = &vc4_fkms_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; ++ if (vc4_fkms_crtc->event) { ++ drm_crtc_send_vblank_event(crtc, vc4_fkms_crtc->event); ++ vc4_fkms_crtc->event = NULL; + drm_crtc_vblank_put(crtc); + } + spin_unlock_irqrestore(&dev->event_lock, flags); @@ -61321,7 +89585,7 @@ + +static irqreturn_t vc4_crtc_irq_handler(int irq, void *data) +{ -+ struct vc4_crtc **crtc_list = data; ++ struct vc4_fkms_crtc **crtc_list = data; + int i; + u32 stat = readl(crtc_list0->regs + SMICS); + irqreturn_t ret = IRQ_NONE; @@ -61369,6 +89633,20 @@ + return ret; +} + ++static irqreturn_t vc4_crtc2712_irq_handler(int irq, void *data) ++{ ++ struct vc4_fkms_crtc **crtc_list = data; ++ int i; ++ ++ for (i = 0; crtc_listi; i++) { ++ if (crtc_listi->vblank_enabled) ++ drm_crtc_handle_vblank(&crtc_listi->base); ++ vc4_crtc_handle_page_flip(crtc_listi); ++ } ++ ++ return IRQ_HANDLED; ++} ++ +static int vc4_fkms_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, @@ -61412,22 +89690,22 @@ + +static int vc4_fkms_enable_vblank(struct drm_crtc *crtc) +{ -+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct vc4_fkms_crtc *vc4_fkms_crtc = to_vc4_fkms_crtc(crtc); + + DRM_DEBUG_KMS("CRTC:%d enable_vblank.\n", + crtc->base.id); -+ vc4_crtc->vblank_enabled = true; ++ vc4_fkms_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); ++ struct vc4_fkms_crtc *vc4_fkms_crtc = to_vc4_fkms_crtc(crtc); + + DRM_DEBUG_KMS("CRTC:%d disable_vblank.\n", + crtc->base.id); -+ vc4_crtc->vblank_enabled = false; ++ vc4_fkms_crtc->vblank_enabled = false; +} + +static const struct drm_crtc_funcs vc4_crtc_funcs = { @@ -61447,16 +89725,19 @@ +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_check = vc4_fkms_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", ++ .data = (void *)BCM2835_6_7 }, + { .compatible = "raspberrypi,rpi-firmware-kms-2711", -+ .data = (void *)1 }, ++ .data = (void *)BCM2711 }, ++ { .compatible = "raspberrypi,rpi-firmware-kms-2712", ++ .data = (void *)BCM2712 }, + {} +}; + @@ -61741,7 +90022,7 @@ +static void vc4_hdmi_connector_reset(struct drm_connector *connector) +{ + drm_atomic_helper_connector_reset(connector); -+ drm_atomic_helper_connector_tv_reset(connector); ++ drm_atomic_helper_connector_tv_margins_reset(connector); +} + +static const struct drm_connector_funcs vc4_fkms_connector_funcs = { @@ -61916,10 +90197,10 @@ + +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_fkms_crtc **ret_crtc) +{ + struct vc4_dev *vc4 = to_vc4_dev(drm); -+ struct vc4_crtc *vc4_crtc; ++ struct vc4_fkms_crtc *vc4_fkms_crtc; + struct vc4_fkms_encoder *vc4_encoder; + struct drm_crtc *crtc; + struct drm_plane *destroy_plane, *temp; @@ -61932,13 +90213,13 @@ + struct drm_plane *planesPLANES_PER_CRTC; + int ret, i; + -+ vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL); -+ if (!vc4_crtc) ++ vc4_fkms_crtc = devm_kzalloc(dev, sizeof(*vc4_fkms_crtc), GFP_KERNEL); ++ if (!vc4_fkms_crtc) + return -ENOMEM; -+ crtc = &vc4_crtc->base; ++ crtc = &vc4_fkms_crtc->base; + -+ vc4_crtc->display_number = display_ref; -+ vc4_crtc->display_type = vc4_get_display_type(display_ref); ++ vc4_fkms_crtc->display_number = display_ref; ++ vc4_fkms_crtc->display_type = vc4_get_display_type(display_ref); + + /* Blank the firmware provided framebuffer */ + rpi_firmware_property_list(vc4->firmware, &blank, sizeof(blank)); @@ -61972,29 +90253,29 @@ + vc4_encoder = devm_kzalloc(dev, sizeof(*vc4_encoder), GFP_KERNEL); + if (!vc4_encoder) + return -ENOMEM; -+ vc4_crtc->encoder = &vc4_encoder->base; ++ vc4_fkms_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); ++ vc4_fkms_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); ++ vc4_fkms_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base, ++ display_ref); ++ if (IS_ERR(vc4_fkms_crtc->connector)) { ++ ret = PTR_ERR(vc4_fkms_crtc->connector); + goto err_destroy_encoder; + } + -+ *ret_crtc = vc4_crtc; ++ *ret_crtc = vc4_fkms_crtc; + + return 0; + +err_destroy_encoder: -+ vc4_fkms_encoder_destroy(vc4_crtc->encoder); ++ vc4_fkms_encoder_destroy(vc4_fkms_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)) @@ -62011,7 +90292,7 @@ + struct vc4_dev *vc4 = to_vc4_dev(drm); + struct device_node *firmware_node; + const struct of_device_id *match; -+ struct vc4_crtc **crtc_list; ++ struct vc4_fkms_crtc **crtc_list; + u32 num_displays, display_num; + struct vc4_fkms *fkms; + int ret; @@ -62026,11 +90307,10 @@ + match = of_match_device(vc4_firmware_kms_dt_match, dev); + if (!match) + return -ENODEV; -+ if (match->data) -+ fkms->bcm2711 = true; ++ fkms->revision = (enum vc4_fkms_revision)match->data; + + firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0); -+ vc4->firmware = rpi_firmware_get(firmware_node); ++ vc4->firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node); + if (!vc4->firmware) { + DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n"); + return -EPROBE_DEFER; @@ -62094,10 +90374,16 @@ + if (IS_ERR(crtc_list0->regs)) + DRM_ERROR("Oh dear, failed to map registers\n"); + -+ writel(0, crtc_list0->regs + SMICS); -+ ret = devm_request_irq(dev, platform_get_irq(pdev, 0), -+ vc4_crtc_irq_handler, 0, -+ "vc4 firmware kms", crtc_list); ++ if (fkms->revision >= BCM2712) { ++ ret = devm_request_irq(dev, platform_get_irq(pdev, 0), ++ vc4_crtc2712_irq_handler, 0, ++ "vc4 firmware kms", crtc_list); ++ } else { ++ writel(0, crtc_list0->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 { @@ -62115,7 +90401,7 @@ + void *data) +{ + struct platform_device *pdev = to_platform_device(dev); -+ struct vc4_crtc **crtc_list = dev_get_drvdata(dev); ++ struct vc4_fkms_crtc **crtc_list = dev_get_drvdata(dev); + int i; + + for (i = 0; crtc_listi; i++) { @@ -62152,4764 +90438,5184 @@ + }, +}; diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c -index b641252939d8..445d3bab89e0 100644 +index 03648f954985..0d94165d4b6b 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c -@@ -1026,7 +1026,6 @@ int vc4_queue_seqno_cb(struct drm_device *dev, - void (*func)(struct vc4_seqno_cb *cb)) - { +@@ -76,7 +76,7 @@ vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, + u32 i; + int ret = 0; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (!vc4->v3d) { +@@ -389,7 +389,7 @@ vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno, uint64_t timeout_ns, + unsigned long timeout_expire; + DEFINE_WAIT(wait); + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (vc4->finished_seqno >= seqno) +@@ -474,7 +474,7 @@ vc4_submit_next_bin_job(struct drm_device *dev) + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_exec_info *exec; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + again: +@@ -522,7 +522,7 @@ vc4_submit_next_render_job(struct drm_device *dev) + if (!exec) + return; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + /* A previous RCL may have written to one of our textures, and +@@ -543,7 +543,7 @@ vc4_move_job_to_render(struct drm_device *dev, struct vc4_exec_info *exec) + struct vc4_dev *vc4 = to_vc4_dev(dev); + bool was_empty = list_empty(&vc4->render_job_list); + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + list_move_tail(&exec->head, &vc4->render_job_list); +@@ -970,7 +970,7 @@ vc4_job_handle_completed(struct vc4_dev *vc4) + unsigned long irqflags; + struct vc4_seqno_cb *cb, *cb_temp; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + spin_lock_irqsave(&vc4->job_lock, irqflags); +@@ -1009,7 +1009,7 @@ int vc4_queue_seqno_cb(struct drm_device *dev, struct vc4_dev *vc4 = to_vc4_dev(dev); -- int ret = 0; unsigned long irqflags; +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + cb->func = func; -@@ -1041,7 +1040,7 @@ int vc4_queue_seqno_cb(struct drm_device *dev, - } - spin_unlock_irqrestore(&vc4->job_lock, irqflags); +@@ -1065,7 +1065,7 @@ vc4_wait_seqno_ioctl(struct drm_device *dev, void *data, + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct drm_vc4_wait_seqno *args = data; -- return ret; -+ return 0; - } +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + return vc4_wait_for_seqno_ioctl_helper(dev, args->seqno, +@@ -1082,7 +1082,7 @@ vc4_wait_bo_ioctl(struct drm_device *dev, void *data, + struct drm_gem_object *gem_obj; + struct vc4_bo *bo; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (args->pad != 0) +@@ -1131,7 +1131,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data, + args->shader_rec_size, + args->bo_handle_count); + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (!vc4->v3d) { +@@ -1268,7 +1268,7 @@ int vc4_gem_init(struct drm_device *dev) + struct vc4_dev *vc4 = to_vc4_dev(dev); + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + vc4->dma_fence_context = dma_fence_context_alloc(1); +@@ -1327,7 +1327,7 @@ int vc4_gem_madvise_ioctl(struct drm_device *dev, void *data, + struct vc4_bo *bo; + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; - /* Scheduled when any job has been completed, this walks the list of + switch (args->madv) { diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c -index a308f2d05d17..f1e0e0064b09 100644 +index 25c9c71256d3..7429bbee5bec 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c -@@ -35,6 +35,7 @@ - #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> +@@ -41,6 +41,8 @@ #include <linux/component.h> + #include <linux/gpio/consumer.h> #include <linux/i2c.h> -@@ -44,16 +45,27 @@ ++#include <linux/module.h> ++#include <linux/moduleparam.h> + #include <linux/of.h> + #include <linux/of_address.h> #include <linux/pm_runtime.h> - #include <linux/rational.h> +@@ -48,6 +50,7 @@ #include <linux/reset.h> -+#include <sound/asoundef.h> #include <sound/dmaengine_pcm.h> -+#include <sound/hdmi-codec.h> + #include <sound/hdmi-codec.h> ++#include <sound/jack.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" - #include "vc4_hdmi_regs.h" - #include "vc4_regs.h" +@@ -109,6 +112,10 @@ -+/* -+ * "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 -+ - #define VC5_HDMI_HORZA_HFP_SHIFT 16 - #define VC5_HDMI_HORZA_HFP_MASK VC4_MASK(28, 16) - #define VC5_HDMI_HORZA_VPOS BIT(15) -@@ -76,12 +88,69 @@ - #define VC5_HDMI_VERTB_VSPO_SHIFT 16 - #define VC5_HDMI_VERTB_VSPO_MASK VC4_MASK(29, 16) + #define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000) -+#define VC5_HDMI_MISC_CONTROL_PIXEL_REP_SHIFT 0 -+#define VC5_HDMI_MISC_CONTROL_PIXEL_REP_MASK VC4_MASK(3, 0) -+ -+#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) ++/* bit field to force hotplug detection. bit0 = HDMI0 */ ++static int force_hotplug = 0; ++module_param(force_hotplug, int, 0644); ++ + static const char * const output_format_str = { + VC4_HDMI_OUTPUT_RGB = "RGB", + VC4_HDMI_OUTPUT_YUV420 = "YUV 4:2:0", +@@ -179,6 +186,8 @@ static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) + if (!drm_dev_enter(drm, &idx)) + return -ENODEV; + ++ WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev)); + -+#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) + drm_print_regset32(&p, &vc4_hdmi->hdmi_regset); + drm_print_regset32(&p, &vc4_hdmi->hd_regset); + drm_print_regset32(&p, &vc4_hdmi->cec_regset); +@@ -188,6 +197,8 @@ static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) + drm_print_regset32(&p, &vc4_hdmi->ram_regset); + drm_print_regset32(&p, &vc4_hdmi->rm_regset); + ++ pm_runtime_put(&vc4_hdmi->pdev->dev); + -+#define VC5_HDMI_GCP_CONFIG_GCP_ENABLE BIT(31) + drm_dev_exit(idx); + + return 0; +@@ -411,7 +422,7 @@ static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi, + enum drm_connector_status status) + { + struct drm_connector *connector = &vc4_hdmi->connector; +- struct edid *edid; ++ struct edid *edid = NULL; + int ret; + + /* +@@ -429,12 +440,25 @@ static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi, + * the lock for now. + */ + ++ if (status != connector_status_disconnected) ++ edid = drm_get_edid(connector, vc4_hdmi->ddc); + -+#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) ++ /* ++ * Report plugged/unplugged events to ALSA jack detection. Do this ++ * *after* EDID probing, otherwise userspace might try to bring up ++ * audio before it's ready. ++ */ ++ mutex_lock(&vc4_hdmi->update_plugged_status_lock); ++ if (vc4_hdmi->plugged_cb && vc4_hdmi->codec_dev) ++ vc4_hdmi->plugged_cb(vc4_hdmi->codec_dev, ++ status != connector_status_disconnected); ++ mutex_unlock(&vc4_hdmi->update_plugged_status_lock); + - # define VC4_HD_M_SW_RST BIT(2) - # define VC4_HD_M_ENABLE BIT(0) + if (status == connector_status_disconnected) { + cec_phys_addr_invalidate(vc4_hdmi->cec_adap); + return; + } - #define HSM_MIN_CLOCK_FREQ 120000000 - #define CEC_CLOCK_FREQ 40000 --#define VC4_HSM_MID_CLOCK 149985000 -+#define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000) -+ -+static const char * const output_format_str = { -+ VC4_HDMI_OUTPUT_RGB = "RGB", -+ VC4_HDMI_OUTPUT_YUV420 = "YUV 4:2:0", -+ VC4_HDMI_OUTPUT_YUV422 = "YUV 4:2:2", -+ VC4_HDMI_OUTPUT_YUV444 = "YUV 4:4:4", -+}; +- edid = drm_get_edid(connector, vc4_hdmi->ddc); + if (!edid) + return; + +@@ -472,7 +496,9 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector, + + WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev)); + +- if (vc4_hdmi->hpd_gpio) { ++ if (force_hotplug & BIT(vc4_hdmi->encoder.type - VC4_ENCODER_TYPE_HDMI0)) ++ status = connector_status_connected; ++ else if (vc4_hdmi->hpd_gpio) { + if (gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) + status = connector_status_connected; + } else { +@@ -748,7 +774,6 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, + + 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); +@@ -757,8 +782,12 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, + connector->doublescan_allowed = 0; + connector->stereo_allowed = 1; + +- if (vc4_hdmi->variant->supports_hdr) ++ if (vc4_hdmi->variant->supports_hdr) { ++ drm_connector_attach_max_bpc_property(connector, 8, 12); + drm_connector_attach_hdr_output_metadata_property(connector); ++ } else { ++ drm_connector_attach_max_bpc_property(connector, 8, 8); ++ } + + vc4_hdmi_attach_broadcast_rgb_property(dev, vc4_hdmi); + +@@ -1087,6 +1116,7 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, + { + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_device *drm = vc4_hdmi->connector.dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); + unsigned long flags; + int idx; + +@@ -1103,14 +1133,25 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, + + HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_CLRRGB); + ++ if (vc4->gen >= VC4_GEN_6) ++ HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) | ++ VC4_HD_VID_CTL_BLANKPIX); + -+static const char *vc4_hdmi_output_fmt_str(enum vc4_hdmi_output_format fmt) + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + + mdelay(1); + +- spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); +- HDMI_WRITE(HDMI_VID_CTL, +- HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); +- spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ /* ++ * TODO: This should work on BCM2712, but doesn't for some ++ * reason and result in a system lockup. ++ */ ++ if (vc4->gen < VC4_GEN_6) { ++ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); ++ HDMI_WRITE(HDMI_VID_CTL, ++ HDMI_READ(HDMI_VID_CTL) & ++ ~VC4_HD_VID_CTL_ENABLE); ++ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ } + + vc4_hdmi_disable_scrambling(encoder); + +@@ -1738,7 +1779,6 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, + goto err_put_runtime_pm; + } + +- + vc4_hdmi_cec_update_clk_div(vc4_hdmi); + + if (tmds_char_rate > 297000000) +@@ -1843,10 +1883,12 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + + HDMI_WRITE(HDMI_VID_CTL, ++ HDMI_READ(HDMI_VID_CTL) | + VC4_HD_VID_CTL_ENABLE | + VC4_HD_VID_CTL_CLRRGB | + VC4_HD_VID_CTL_UNDERFLOW_ENABLE | + VC4_HD_VID_CTL_FRAME_COUNTER_RESET | ++ VC4_HD_VID_CTL_BLANK_INSERT_EN | + (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) | + (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); + +@@ -1944,9 +1986,6 @@ vc4_hdmi_sink_supports_format_bpc(const struct vc4_hdmi *vc4_hdmi, + case VC4_HDMI_OUTPUT_RGB: + drm_dbg(dev, "RGB Format, checking the constraints.\n"); + +- if (!(info->color_formats & DRM_COLOR_FORMAT_RGB444)) +- return false; +- + if (bpc == 10 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30)) { + drm_dbg(dev, "10 BPC but sink doesn't support Deep Color 30.\n"); + return false; +@@ -2118,7 +2157,7 @@ vc4_hdmi_encoder_compute_config(const struct vc4_hdmi *vc4_hdmi, + { + struct drm_device *dev = vc4_hdmi->connector.dev; + struct drm_connector_state *conn_state = &vc4_state->base; +- unsigned int max_bpc = clamp_t(unsigned int, conn_state->max_bpc, 8, 12); ++ unsigned int max_bpc = clamp_t(unsigned int, conn_state->max_requested_bpc, 8, 12); + unsigned int bpc; + int ret; + +@@ -2386,7 +2425,7 @@ static int vc4_hdmi_audio_startup(struct device *dev, void *data) + } + + if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) { +- ret = -ENODEV; ++ ret = -ENOTSUPP; + goto out_dev_exit; + } + +@@ -2513,6 +2552,7 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, + { + struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); + struct drm_device *drm = vc4_hdmi->connector.dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); + struct drm_encoder *encoder = &vc4_hdmi->encoder.base; + unsigned int sample_rate = params->sample_rate; + unsigned int channels = params->channels; +@@ -2571,11 +2611,24 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, + VC4_HDMI_AUDIO_PACKET_CEA_MASK); + + /* 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)); ++ if (vc4->gen >= VC4_GEN_5 && vc4->step_d0) ++ HDMI_WRITE(HDMI_MAI_THR, ++ VC4_SET_FIELD(0x10, VC4_D0_HD_MAI_THR_PANICHIGH) | ++ VC4_SET_FIELD(0x10, VC4_D0_HD_MAI_THR_PANICLOW) | ++ VC4_SET_FIELD(0x1c, VC4_D0_HD_MAI_THR_DREQHIGH) | ++ VC4_SET_FIELD(0x1c, VC4_D0_HD_MAI_THR_DREQLOW)); ++ else if (vc4->gen >= VC4_GEN_5) ++ HDMI_WRITE(HDMI_MAI_THR, ++ VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICHIGH) | ++ VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICLOW) | ++ VC4_SET_FIELD(0x1c, VC4_HD_MAI_THR_DREQHIGH) | ++ VC4_SET_FIELD(0x1c, VC4_HD_MAI_THR_DREQLOW)); ++ else ++ HDMI_WRITE(HDMI_MAI_THR, ++ VC4_SET_FIELD(0x8, VC4_HD_MAI_THR_PANICHIGH) | ++ VC4_SET_FIELD(0x8, VC4_HD_MAI_THR_PANICLOW) | ++ VC4_SET_FIELD(0x6, VC4_HD_MAI_THR_DREQHIGH) | ++ VC4_SET_FIELD(0x8, VC4_HD_MAI_THR_DREQLOW)); + + HDMI_WRITE(HDMI_MAI_CONFIG, + VC4_HDMI_MAI_CONFIG_BIT_REVERSE | +@@ -2652,8 +2705,23 @@ static int vc4_hdmi_audio_get_eld(struct device *dev, void *data, + return 0; + } + ++static int vc4_hdmi_audio_hook_plugged_cb(struct device *dev, void *data, ++ hdmi_codec_plugged_cb fn, ++ struct device *codec_dev) +{ -+ if (fmt >= ARRAY_SIZE(output_format_str)) -+ return "invalid"; -+ -+ return output_format_strfmt; -+} -+ -+static unsigned long long -+vc4_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode, -+ unsigned int bpc, enum vc4_hdmi_output_format fmt); ++ struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); + -+static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode, -+ unsigned int bpc, -+ enum vc4_hdmi_output_format fmt) -+{ -+ unsigned long long clock = vc4_hdmi_encoder_compute_mode_clock(mode, bpc, fmt); ++ mutex_lock(&vc4_hdmi->update_plugged_status_lock); ++ vc4_hdmi->plugged_cb = fn; ++ vc4_hdmi->codec_dev = codec_dev; ++ mutex_unlock(&vc4_hdmi->update_plugged_status_lock); + -+ return clock > HDMI_14_MAX_TMDS_CLK; ++ return 0; +} + -+static bool vc4_hdmi_is_full_range_rgb(struct vc4_hdmi *vc4_hdmi, -+ const struct drm_display_mode *mode) + static const struct hdmi_codec_ops vc4_hdmi_codec_ops = { + .get_eld = vc4_hdmi_audio_get_eld, ++ .hook_plugged_cb = vc4_hdmi_audio_hook_plugged_cb, + .prepare = vc4_hdmi_audio_prepare, + .audio_shutdown = vc4_hdmi_audio_shutdown, + .audio_startup = vc4_hdmi_audio_startup, +@@ -2673,6 +2741,22 @@ static void vc4_hdmi_audio_codec_release(void *ptr) + vc4_hdmi->audio.codec_pdev = NULL; + } + ++static int vc4_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd) +{ -+ struct vc4_hdmi_encoder *vc4_encoder = &vc4_hdmi->encoder; ++ struct vc4_hdmi *vc4_hdmi = snd_soc_card_get_drvdata(rtd->card); ++ struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; ++ int ret; + -+ if (vc4_hdmi->broadcast_rgb == VC4_BROADCAST_RGB_LIMITED) -+ return false; -+ else if (vc4_hdmi->broadcast_rgb == VC4_BROADCAST_RGB_FULL) -+ return true; -+ return !vc4_encoder->hdmi_monitor || -+ drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_FULL; ++ ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, ++ &vc4_hdmi->hdmi_jack); ++ if (ret) { ++ dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret); ++ return ret; ++ } ++ ++ return snd_soc_component_set_jack(component, &vc4_hdmi->hdmi_jack, NULL); +} - - static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) ++ + static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) { -@@ -91,12 +160,22 @@ static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) + const struct vc4_hdmi_register *mai_data = +@@ -2681,7 +2765,7 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) + struct snd_soc_card *card = &vc4_hdmi->audio.card; + struct device *dev = &vc4_hdmi->pdev->dev; + struct platform_device *codec_pdev; +- const __be32 *addr; ++ struct resource *iomem; + int index, len; + int ret; - 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); +@@ -2717,20 +2801,15 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) + } - return 0; - } + /* +- * Get the physical address of VC4_HD_MAI_DATA. We need to retrieve +- * the bus address specified in the DT, because the physical address +- * (the one returned by platform_get_resource()) is not appropriate +- * for DMA transfers. +- * This VC/MMU should probably be exposed to avoid this kind of hacks. ++ * Get the physical address of VC4_HD_MAI_DATA. + */ + index = of_property_match_string(dev->of_node, "reg-names", "hd"); + /* Before BCM2711, we don't have a named register range */ + if (index < 0) + index = 1; ++ iomem = platform_get_resource(vc4_hdmi->pdev, IORESOURCE_MEM, index); - static void vc4_hdmi_reset(struct vc4_hdmi *vc4_hdmi) - { -+ unsigned long flags; -+ -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ - HDMI_WRITE(HDMI_M_CTL, VC4_HD_M_SW_RST); - udelay(1); - HDMI_WRITE(HDMI_M_CTL, 0); -@@ -108,24 +187,36 @@ static void vc4_hdmi_reset(struct vc4_hdmi *vc4_hdmi) - VC4_HDMI_SW_RESET_FORMAT_DETECT); +- addr = of_get_address(dev->of_node, index, NULL, NULL); +- +- vc4_hdmi->audio.dma_data.addr = be32_to_cpup(addr) + mai_data->offset; ++ vc4_hdmi->audio.dma_data.addr = iomem->start + mai_data->offset; + vc4_hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + vc4_hdmi->audio.dma_data.maxburst = 2; - HDMI_WRITE(HDMI_SW_RESET_CONTROL, 0); -+ -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); - } +@@ -2800,6 +2879,8 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) + dai_link->codecs->name = dev_name(&codec_pdev->dev); + dai_link->platforms->name = dev_name(dev); - static void vc5_hdmi_reset(struct vc4_hdmi *vc4_hdmi) - { -+ unsigned long flags; ++ dai_link->init = vc4_hdmi_codec_init; + - reset_control_reset(vc4_hdmi->reset); + card->dai_link = dai_link; + card->num_links = 1; + card->name = vc4_hdmi->variant->card_name; +@@ -3571,6 +3652,7 @@ static int vc4_hdmi_runtime_suspend(struct device *dev) + { + struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ - HDMI_WRITE(HDMI_DVP_CTL, 0); ++ clk_disable_unprepare(vc4_hdmi->audio_clock); + clk_disable_unprepare(vc4_hdmi->hsm_clock); - HDMI_WRITE(HDMI_CLOCK_STOP, - HDMI_READ(HDMI_CLOCK_STOP) | VC4_DVP_HT_CLOCK_STOP_PIXEL); + return 0; +@@ -3603,6 +3685,10 @@ static int vc4_hdmi_runtime_resume(struct device *dev) + goto err_disable_clk; + } + ++ ret = clk_prepare_enable(vc4_hdmi->audio_clock); ++ if (ret) ++ goto err_disable_clk; + -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); - } + if (vc4_hdmi->variant->reset) + vc4_hdmi->variant->reset(vc4_hdmi); - #ifdef CONFIG_DRM_VC4_HDMI_CEC - static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) - { -+ unsigned long cec_rate = clk_get_rate(vc4_hdmi->cec_clock); -+ unsigned long flags; - u16 clk_cnt; - u32 value; +@@ -3655,6 +3741,8 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) + if (ret) + return ret; -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); ++ mutex_init(&vc4_hdmi->update_plugged_status_lock); + - value = HDMI_READ(HDMI_CEC_CNTRL_1); - value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK; + spin_lock_init(&vc4_hdmi->hw_lock); + INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq); -@@ -133,30 +224,37 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) - * 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 = cec_rate / CEC_CLOCK_FREQ; - value |= clk_cnt << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT; - HDMI_WRITE(HDMI_CEC_CNTRL_1, value); -+ -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); +@@ -3723,7 +3811,9 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) + return ret; + + if ((of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi0") || +- of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi1")) && ++ of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi1") || ++ of_device_is_compatible(dev->of_node, "brcm,bcm2712-hdmi0") || ++ of_device_is_compatible(dev->of_node, "brcm,bcm2712-hdmi1")) && + HDMI_READ(HDMI_VID_CTL) & VC4_HD_VID_CTL_ENABLE) { + clk_prepare_enable(vc4_hdmi->pixel_clock); + clk_prepare_enable(vc4_hdmi->hsm_clock); +@@ -3765,8 +3855,16 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) + return ret; } - #else - 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 void vc4_hdmi_unbind(struct device *dev, struct device *master, void *data) ++{ ++ struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); + - 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; - -+ mutex_lock(&vc4_hdmi->mutex); ++ mutex_destroy(&vc4_hdmi->update_plugged_status_lock); ++} + - WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev)); + static const struct component_ops vc4_hdmi_ops = { + .bind = vc4_hdmi_bind, ++ .unbind = vc4_hdmi_unbind, + }; - if (vc4_hdmi->hpd_gpio) { - if (gpio_get_value_cansleep(vc4_hdmi->hpd_gpio) ^ - vc4_hdmi->hpd_active_low) - connected = true; -- } else if (drm_probe_ddc(vc4_hdmi->ddc)) { -- connected = true; -- } else if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) { -- connected = true; -+ } else { -+ if (vc4_hdmi->variant->hp_detect && -+ vc4_hdmi->variant->hp_detect(vc4_hdmi)) -+ connected = true; - } - - if (connected) { -@@ -167,16 +265,25 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) - cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid); - vc4_hdmi->encoder.hdmi_monitor = drm_detect_hdmi_monitor(edid); - kfree(edid); -+ } else { -+ vc4_hdmi->encoder.hdmi_monitor = false; - } - } + static int vc4_hdmi_dev_probe(struct platform_device *pdev) +@@ -3857,10 +3955,66 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = { + .hp_detect = vc5_hdmi_hp_detect, + }; -- pm_runtime_put(&vc4_hdmi->pdev->dev); -- return connector_status_connected; -+ vc4_hdmi_enable_scrambling(&vc4_hdmi->encoder.base.base); ++static const struct vc4_hdmi_variant bcm2712_hdmi0_variant = { ++ .encoder_type = VC4_ENCODER_TYPE_HDMI0, ++ .debugfs_name = "hdmi0_regs", ++ .card_name = "vc4-hdmi-0", ++ .max_pixel_clock = 600000000, ++ .registers = vc6_hdmi_hdmi0_fields, ++ .num_registers = ARRAY_SIZE(vc6_hdmi_hdmi0_fields), ++ .phy_lane_mapping = { ++ PHY_LANE_0, ++ PHY_LANE_1, ++ PHY_LANE_2, ++ PHY_LANE_CK, ++ }, ++ .unsupported_odd_h_timings = false, ++ .external_irq_controller = true, + -+ ret = connector_status_connected; -+ goto out; - } - -+ vc4_hdmi->encoder.hdmi_monitor = false; ++ .init_resources = vc5_hdmi_init_resources, ++ .csc_setup = vc5_hdmi_csc_setup, ++ .reset = vc5_hdmi_reset, ++ .set_timings = vc5_hdmi_set_timings, ++ .phy_init = vc6_hdmi_phy_init, ++ .phy_disable = vc6_hdmi_phy_disable, ++ .channel_map = vc5_hdmi_channel_map, ++ .supports_hdr = true, ++ .hp_detect = vc5_hdmi_hp_detect, ++}; ++ ++static const struct vc4_hdmi_variant bcm2712_hdmi1_variant = { ++ .encoder_type = VC4_ENCODER_TYPE_HDMI1, ++ .debugfs_name = "hdmi1_regs", ++ .card_name = "vc4-hdmi-1", ++ .max_pixel_clock = 600000000, ++ .registers = vc6_hdmi_hdmi1_fields, ++ .num_registers = ARRAY_SIZE(vc6_hdmi_hdmi1_fields), ++ .phy_lane_mapping = { ++ PHY_LANE_0, ++ PHY_LANE_1, ++ PHY_LANE_2, ++ PHY_LANE_CK, ++ }, ++ .unsupported_odd_h_timings = false, ++ .external_irq_controller = true, + - cec_phys_addr_invalidate(vc4_hdmi->cec_adap); ++ .init_resources = vc5_hdmi_init_resources, ++ .csc_setup = vc5_hdmi_csc_setup, ++ .reset = vc5_hdmi_reset, ++ .set_timings = vc5_hdmi_set_timings, ++ .phy_init = vc6_hdmi_phy_init, ++ .phy_disable = vc6_hdmi_phy_disable, ++ .channel_map = vc5_hdmi_channel_map, ++ .supports_hdr = true, ++ .hp_detect = vc5_hdmi_hp_detect, ++}; + -+out: - pm_runtime_put(&vc4_hdmi->pdev->dev); -- return connector_status_disconnected; -+ mutex_unlock(&vc4_hdmi->mutex); -+ return ret; - } + static const struct of_device_id vc4_hdmi_dt_match = { + { .compatible = "brcm,bcm2835-hdmi", .data = &bcm2835_variant }, + { .compatible = "brcm,bcm2711-hdmi0", .data = &bcm2711_hdmi0_variant }, + { .compatible = "brcm,bcm2711-hdmi1", .data = &bcm2711_hdmi1_variant }, ++ { .compatible = "brcm,bcm2712-hdmi0", .data = &bcm2712_hdmi0_variant }, ++ { .compatible = "brcm,bcm2712-hdmi1", .data = &bcm2712_hdmi1_variant }, + {} + }; - static void vc4_hdmi_connector_destroy(struct drm_connector *connector) -@@ -192,10 +299,14 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) - int ret = 0; - struct edid *edid; +diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h +index 934d5d61485a..b4212dad23d8 100644 +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -2,8 +2,10 @@ + #define _VC4_HDMI_H_ + + #include <drm/drm_connector.h> ++#include <linux/mutex.h> + #include <media/cec.h> + #include <sound/dmaengine_pcm.h> ++#include <sound/hdmi-codec.h> + #include <sound/soc.h> -+ mutex_lock(&vc4_hdmi->mutex); + #include "vc4_drv.h" +@@ -228,6 +230,31 @@ struct vc4_hdmi { + * for use outside of KMS hooks. Protected by @mutex. + */ + enum vc4_hdmi_output_format output_format; + - edid = drm_get_edid(connector, vc4_hdmi->ddc); - cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid); -- if (!edid) -- return -ENODEV; -+ if (!edid) { -+ ret = -ENODEV; -+ goto out; -+ } ++ /** ++ * @plugged_cb: Callback provided by hdmi-codec to indicate that an ++ * HDMI hotplug occurred and jack state should be updated. Protected by ++ * @update_plugged_status_lock. ++ */ ++ hdmi_codec_plugged_cb plugged_cb; ++ ++ /** ++ * @plugged_cb: Context for plugged_cb. Protected by ++ * @update_plugged_status_lock. ++ */ ++ struct device *codec_dev; ++ ++ /** ++ * @update_plugged_status_lock: Prevents a race condition where an HDMI ++ * hotplug might occur between @plugged_cb and @codec_dev being set. ++ */ ++ struct mutex update_plugged_status_lock; ++ ++ /** ++ * @hdmi_jack: Represents the connection state of the HDMI plug, for ++ * ALSA jack detection. ++ */ ++ struct snd_soc_jack hdmi_jack; + }; - vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); + #define connector_to_vc4_hdmi(_connector) \ +@@ -263,4 +290,8 @@ 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); -@@ -203,28 +314,193 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) - 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, 8, VC4_HDMI_OUTPUT_RGB)) { -+ 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."); -+ } -+ } -+ } ++void vc6_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, ++ struct vc4_hdmi_connector_state *vc4_conn_state); ++void vc6_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi); + -+out: -+ mutex_unlock(&vc4_hdmi->mutex); + #endif /* _VC4_HDMI_H_ */ +diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c +index ec24999bf96d..0d5562714832 100644 +--- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c +@@ -125,6 +125,48 @@ + #define VC4_HDMI_RM_FORMAT_SHIFT_SHIFT 24 + #define VC4_HDMI_RM_FORMAT_SHIFT_MASK VC4_MASK(25, 24) + ++#define VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_BG_PWRUP BIT(8) ++#define VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_LDO_PWRUP BIT(7) ++#define VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_BIAS_PWRUP BIT(6) ++#define VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_RNDGEN_PWRUP BIT(4) ++#define VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_TX_CK_PWRUP BIT(3) ++#define VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_TX_2_PWRUP BIT(2) ++#define VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_TX_1_PWRUP BIT(1) ++#define VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_TX_0_PWRUP BIT(0) ++ ++#define VC6_HDMI_TX_PHY_PLL_REFCLK_REFCLK_SEL_CMOS BIT(13) ++#define VC6_HDMI_TX_PHY_PLL_REFCLK_REFFRQ_MASK VC4_MASK(9, 0) ++ ++#define VC6_HDMI_TX_PHY_PLL_POST_KDIV_CLK0_SEL_MASK VC4_MASK(3, 2) ++#define VC6_HDMI_TX_PHY_PLL_POST_KDIV_KDIV_MASK VC4_MASK(1, 0) ++ ++#define VC6_HDMI_TX_PHY_PLL_VCOCLK_DIV_VCODIV_EN BIT(10) ++#define VC6_HDMI_TX_PHY_PLL_VCOCLK_DIV_VCODIV_MASK VC4_MASK(9, 0) ++ ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_CTL_MASK VC4_MASK(31, 28) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_ENABLE_MASK VC4_MASK(27, 27) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_RATE_CTL_MASK VC4_MASK(26, 26) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_POST_TAP_EN_MASK VC4_MASK(25, 25) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_LDMOS_BIAS_CTL_MASK VC4_MASK(24, 23) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_COM_MODE_LDMOS_EN_MASK VC4_MASK(22, 22) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EDGE_SEL_MASK VC4_MASK(21, 21) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_HS_EN_MASK VC4_MASK(20, 20) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_TERM_CTL_MASK VC4_MASK(19, 18) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_EN_MASK VC4_MASK(17, 17) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_EN_MASK VC4_MASK(16, 16) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_CTL_MASK VC4_MASK(15, 12) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_HS_EN_MASK VC4_MASK(11, 11) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_MAIN_TAP_CURRENT_SELECT_MASK VC4_MASK(10, 8) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_POST_TAP_CURRENT_SELECT_MASK VC4_MASK(7, 5) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_LOADING_MASK VC4_MASK(4, 3) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_DRIVING_MASK VC4_MASK(2, 1) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_PRE_TAP_EN_MASK VC4_MASK(0, 0) + - return ret; - } ++#define VC6_HDMI_TX_PHY_PLL_RESET_CTL_PLL_PLLPOST_RESETB BIT(1) ++#define VC6_HDMI_TX_PHY_PLL_RESET_CTL_PLL_RESETB BIT(0) ++ ++#define VC6_HDMI_TX_PHY_PLL_POWERUP_CTL_PLL_PWRUP BIT(0) ++ + #define OSCILLATOR_FREQUENCY 54000000 -+static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector, -+ struct drm_atomic_state *state) + void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, +@@ -558,3 +600,601 @@ void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi) + VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + } ++ ++#define VC6_VCO_MIN_FREQ (8ULL * 1000 * 1000 * 1000) ++#define VC6_VCO_MAX_FREQ (12ULL * 1000 * 1000 * 1000) ++ ++static unsigned long long ++vc6_phy_get_vco_freq(unsigned long long tmds_rate, unsigned int *vco_div) +{ -+ 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; ++ unsigned int min_div; ++ unsigned int max_div; ++ unsigned int div; ++ ++ div = 0; ++ while (tmds_rate * div * 10 < VC6_VCO_MIN_FREQ) ++ div++; ++ min_div = div; ++ ++ while (tmds_rate * (div + 1) * 10 < VC6_VCO_MAX_FREQ) ++ div++; ++ max_div = div; ++ ++ div = min_div + (max_div - min_div) / 2; ++ ++ *vco_div = div; ++ return tmds_rate * div * 10; ++} ++ ++struct vc6_phy_lane_settings { ++ unsigned int ext_current_ctl:4; ++ unsigned int ffe_enable:1; ++ unsigned int slew_rate_ctl:1; ++ unsigned int ffe_post_tap_en:1; ++ unsigned int ldmos_bias_ctl:2; ++ unsigned int com_mode_ldmos_en:1; ++ unsigned int edge_sel:1; ++ unsigned int ext_current_src_hs_en:1; ++ unsigned int term_ctl:2; ++ unsigned int ext_current_src_en:1; ++ unsigned int int_current_src_en:1; ++ unsigned int int_current_ctl:4; ++ unsigned int int_current_src_hs_en:1; ++ unsigned int main_tap_current_select:3; ++ unsigned int post_tap_current_select:3; ++ unsigned int slew_ctl_slow_loading:2; ++ unsigned int slew_ctl_slow_driving:2; ++ unsigned int ffe_pre_tap_en:1; ++}; ++ ++struct vc6_phy_settings { ++ unsigned long long min_rate; ++ unsigned long long max_rate; ++ struct vc6_phy_lane_settings channel3; ++ struct vc6_phy_lane_settings clock; ++}; + -+ if (!crtc) -+ return 0; ++static const struct vc6_phy_settings vc6_hdmi_phy_settings = { ++ { ++ 0, 222000000, ++ { ++ { ++ /* 200mA */ ++ .ext_current_ctl = 8, + -+ if (old_state->colorspace != new_state->colorspace || -+ !drm_connector_atomic_hdr_metadata_equal(old_state, new_state)) { -+ struct drm_crtc_state *crtc_state; ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, + -+ crtc_state = drm_atomic_get_crtc_state(state, crtc); -+ if (IS_ERR(crtc_state)) -+ return PTR_ERR(crtc_state); ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, + -+ crtc_state->mode_changed = true; -+ } ++ /* 200mA */ ++ .int_current_ctl = 8, + -+ return 0; -+} ++ /* 17.6 mA */ ++ .main_tap_current_select = 7, ++ }, ++ { ++ /* 200mA */ ++ .ext_current_ctl = 8, + -+/** -+ * vc4_hdmi_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_hdmi_connector_get_property(struct drm_connector *connector, -+ const struct drm_connector_state *state, -+ struct drm_property *property, -+ uint64_t *val) -+{ -+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector); -+ const struct vc4_hdmi_connector_state *vc4_conn_state = -+ const_conn_state_to_vc4_hdmi_conn_state(state); ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, + -+ if (property == vc4_hdmi->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; -+ } ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, + -+ return 0; -+} ++ /* 200mA */ ++ .int_current_ctl = 8, + -+/** -+ * vc4_hdmi_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_hdmi_connector_set_property(struct drm_connector *connector, -+ struct drm_connector_state *state, -+ struct drm_property *property, -+ uint64_t val) -+{ -+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector); -+ struct vc4_hdmi_connector_state *vc4_conn_state = -+ conn_state_to_vc4_hdmi_conn_state(state); ++ /* 17.6 mA */ ++ .main_tap_current_select = 7, ++ }, ++ { ++ /* 200mA */ ++ .ext_current_ctl = 8, + -+ if (property == vc4_hdmi->broadcast_rgb_property) { -+ vc4_conn_state->broadcast_rgb = val; -+ return 0; -+ } ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, + -+ DRM_DEBUG_ATOMIC("Unknown property PROP:%d:%s\n", -+ property->base.id, property->name); -+ return -EINVAL; -+} ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, + - 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); ++ /* 200mA */ ++ .int_current_ctl = 8, + -+ if (connector->state) -+ __drm_atomic_helper_connector_destroy_state(connector->state); ++ /* 17.6 mA */ ++ .main_tap_current_select = 7, ++ }, ++ }, ++ { ++ /* 200mA */ ++ .ext_current_ctl = 8, + -+ kfree(old_state); -+ __drm_atomic_helper_connector_reset(connector, &new_state->base); ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, + -+ if (!new_state) -+ return; ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, + -+ new_state->base.max_bpc = 8; -+ new_state->base.max_requested_bpc = 8; -+ new_state->output_format = VC4_HDMI_OUTPUT_RGB; - 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; ++ /* 200mA */ ++ .int_current_ctl = 8, + -+ new_state = kzalloc(sizeof(*new_state), GFP_KERNEL); -+ if (!new_state) -+ return NULL; ++ /* 17.6 mA */ ++ .main_tap_current_select = 7, ++ }, ++ }, ++ { ++ 222000001, 297000000, ++ { ++ { ++ /* 200mA and 180mA ?! */ ++ .ext_current_ctl = 12, + -+ new_state->pixel_rate = vc4_state->pixel_rate; -+ new_state->output_bpc = vc4_state->output_bpc; -+ new_state->output_format = vc4_state->output_format; -+ new_state->broadcast_rgb = vc4_state->broadcast_rgb; -+ __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, -+ .atomic_get_property = vc4_hdmi_connector_get_property, -+ .atomic_set_property = vc4_hdmi_connector_set_property, - }; - - 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 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" }, -+}; ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, + -+static void -+vc4_hdmi_attach_broadcast_rgb_property(struct drm_device *dev, -+ struct vc4_hdmi *vc4_hdmi) -+{ -+ struct drm_property *prop = vc4_hdmi->broadcast_rgb_property; ++ /* 100 Ohm */ ++ .term_ctl = 1, + -+ 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; ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, + -+ vc4_hdmi->broadcast_rgb_property = prop; -+ } ++ /* Enable Internal Current Source */ ++ .int_current_src_en = 1, ++ }, ++ { ++ /* 200mA and 180mA ?! */ ++ .ext_current_ctl = 12, + -+ drm_object_attach_property(&vc4_hdmi->connector.base, prop, 0); -+} ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, + - static int vc4_hdmi_connector_init(struct drm_device *dev, - struct vc4_hdmi *vc4_hdmi) - { -@@ -238,18 +514,37 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, - 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); ++ /* 100 Ohm */ ++ .term_ctl = 1, + - /* 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; ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, + -+ 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; ++ /* Enable Internal Current Source */ ++ .int_current_src_en = 1, ++ }, ++ { ++ /* 200mA and 180mA ?! */ ++ .ext_current_ctl = 12, + -+ if (vc4_hdmi->variant->supports_hdr) -+ drm_connector_attach_hdr_output_metadata_property(connector); ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, + -+ vc4_hdmi_attach_broadcast_rgb_property(dev, vc4_hdmi); - - drm_connector_attach_encoder(connector, encoder); - -@@ -257,13 +552,20 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, - } - - 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; -+ unsigned long flags; - -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, - HDMI_READ(HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id)); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ /* 100 Ohm */ ++ .term_ctl = 1, + -+ if (!poll) -+ return 0; - - return wait_for(!(HDMI_READ(HDMI_RAM_PACKET_STATUS) & - BIT(packet_id)), 100); -@@ -277,9 +579,12 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, - const struct vc4_hdmi_register *ram_packet_start = - &vc4_hdmi->variant->registersHDMI_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 bufferVC4_HDMI_PACKET_STRIDE; -+ uint8_t bufferVC4_HDMI_PACKET_STRIDE = {}; -+ unsigned long flags; - ssize_t len, i; - int ret; - -@@ -291,12 +596,14 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, - 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; - } - -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, + - for (i = 0; i < len; i += 7) { - writel(bufferi + 0 << 0 | - bufferi + 1 << 8 | -@@ -312,25 +619,62 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, - 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); ++ /* Enable Internal Current Source */ ++ .int_current_src_en = 1, ++ }, ++ }, ++ { ++ /* 200mA and 180mA ?! */ ++ .ext_current_ctl = 12, + - HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, - HDMI_READ(HDMI_RAM_PACKET_CONFIG) | BIT(packet_id)); ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, + -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ /* 100 Ohm */ ++ .term_ctl = 1, + - ret = wait_for((HDMI_READ(HDMI_RAM_PACKET_STATUS) & - BIT(packet_id)), 100); - if (ret) - DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret); - } - -+static void vc4_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, -+ enum vc4_hdmi_output_format fmt) -+{ -+ switch (fmt) { -+ case VC4_HDMI_OUTPUT_RGB: -+ frame->colorspace = HDMI_COLORSPACE_RGB; -+ break; ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, + -+ case VC4_HDMI_OUTPUT_YUV420: -+ frame->colorspace = HDMI_COLORSPACE_YUV420; -+ break; ++ /* Enable Internal Current Source */ ++ .int_current_src_en = 1, + -+ case VC4_HDMI_OUTPUT_YUV422: -+ frame->colorspace = HDMI_COLORSPACE_YUV422; -+ break; ++ /* Internal Current Source Half Swing Enable*/ ++ .int_current_src_hs_en = 1, ++ }, ++ }, ++ { ++ 297000001, 597000044, ++ { ++ { ++ /* 200mA */ ++ .ext_current_ctl = 8, + -+ case VC4_HDMI_OUTPUT_YUV444: -+ frame->colorspace = HDMI_COLORSPACE_YUV444; -+ break; ++ /* Normal Slew Rate Control */ ++ .slew_rate_ctl = 1, + -+ default: -+ break; -+ } -+} ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, + - static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) - { - struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); -- struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); - struct drm_connector *connector = &vc4_hdmi->connector; - struct drm_connector_state *cstate = connector->state; -- struct drm_crtc *crtc = encoder->crtc; -- const struct drm_display_mode *mode = &crtc->state->adjusted_mode; -+ struct vc4_hdmi_connector_state *vc4_state = -+ conn_state_to_vc4_hdmi_conn_state(cstate); -+ const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; - union hdmi_infoframe frame; - int ret; - -+ lockdep_assert_held(&vc4_hdmi->mutex); ++ /* 50 Ohms */ ++ .term_ctl = 3, + - ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, - connector, mode); - if (ret < 0) { -@@ -340,10 +684,11 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) - - drm_hdmi_avi_infoframe_quant_range(&frame.avi, - connector, mode, -- vc4_encoder->limited_rgb_range ? -- HDMI_QUANTIZATION_RANGE_LIMITED : -- HDMI_QUANTIZATION_RANGE_FULL); -- -+ vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode) ? -+ HDMI_QUANTIZATION_RANGE_FULL : -+ HDMI_QUANTIZATION_RANGE_LIMITED); -+ drm_hdmi_avi_infoframe_colorimetry(&frame.avi, cstate); -+ vc4_hdmi_avi_infoframe_colorspace(&frame.avi, vc4_state->output_format); - drm_hdmi_avi_infoframe_bars(&frame.avi, cstate); - - vc4_hdmi_write_infoframe(encoder, &frame); -@@ -368,15 +713,30 @@ static void vc4_hdmi_set_spd_infoframe(struct drm_encoder *encoder) - 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); -+} ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, + -+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; ++ /* Enable Internal Current Source */ ++ .int_current_src_en = 1, + -+ lockdep_assert_held(&vc4_hdmi->mutex); ++ /* 200mA */ ++ .int_current_ctl = 8, + -+ if (!vc4_hdmi->variant->supports_hdr) -+ return; ++ /* 17.6 mA */ ++ .main_tap_current_select = 7, ++ }, ++ { ++ /* 200mA */ ++ .ext_current_ctl = 8, + -+ if (!conn_state->hdr_output_metadata) -+ return; - -- 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; -+ if (drm_hdmi_infoframe_set_hdr_metadata(&frame.drm, conn_state)) -+ return; - - vc4_hdmi_write_infoframe(encoder, &frame); - } -@@ -385,6 +745,8 @@ static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) - { - struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); - -+ lockdep_assert_held(&vc4_hdmi->mutex); ++ /* Normal Slew Rate Control */ ++ .slew_rate_ctl = 1, + - vc4_hdmi_set_avi_infoframe(encoder); - vc4_hdmi_set_spd_infoframe(encoder); - /* -@@ -393,52 +755,176 @@ static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) - */ - if (vc4_hdmi->audio.streaming) - vc4_hdmi_set_audio_infoframe(encoder); ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, + -+ vc4_hdmi_set_hdr_infoframe(encoder); -+} ++ /* 50 Ohms */ ++ .term_ctl = 3, + -+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; ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, + -+ lockdep_assert_held(&vc4_hdmi->mutex); ++ /* Enable Internal Current Source */ ++ .int_current_src_en = 1, + -+ if (!vc4_encoder->hdmi_monitor) -+ return false; ++ /* 200mA */ ++ .int_current_ctl = 8, + -+ if (!display->hdmi.scdc.supported || -+ !display->hdmi.scdc.scrambling.supported) -+ return false; ++ /* 17.6 mA */ ++ .main_tap_current_select = 7, ++ }, ++ { ++ /* 200mA */ ++ .ext_current_ctl = 8, + -+ return true; -+} ++ /* Normal Slew Rate Control */ ++ .slew_rate_ctl = 1, + -+#define SCRAMBLING_POLLING_DELAY_MS 1000 ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, + -+static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) -+{ -+ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); -+ struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; -+ unsigned long flags; ++ /* 50 Ohms */ ++ .term_ctl = 3, + -+ lockdep_assert_held(&vc4_hdmi->mutex); ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, + -+ if (!encoder->crtc || !encoder->crtc->state) -+ return; ++ /* Enable Internal Current Source */ ++ .int_current_src_en = 1, + -+ if (!vc4_hdmi_supports_scrambling(encoder, mode)) -+ return; ++ /* 200mA */ ++ .int_current_ctl = 8, + -+ if (!vc4_hdmi_mode_needs_scrambling(mode, -+ vc4_hdmi->output_bpc, -+ vc4_hdmi->output_format)) -+ return; ++ /* 17.6 mA */ ++ .main_tap_current_select = 7, ++ }, ++ }, ++ { ++ /* 200mA */ ++ .ext_current_ctl = 8, + -+ drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true); -+ drm_scdc_set_scrambling(vc4_hdmi->ddc, true); ++ /* Normal Slew Rate Control */ ++ .slew_rate_ctl = 1, + -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) | -+ VC5_HDMI_SCRAMBLER_CTL_ENABLE); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, + -+ vc4_hdmi->scdc_enabled = true; ++ /* External Current Source Half Swing Enable*/ ++ .ext_current_src_hs_en = 1, + -+ queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work, -+ msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS)); -+} ++ /* 50 Ohms */ ++ .term_ctl = 3, + -+static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder) -+{ -+ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); -+ unsigned long flags; ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, + -+ lockdep_assert_held(&vc4_hdmi->mutex); ++ /* Enable Internal Current Source */ ++ .int_current_src_en = 1, + -+ if (!vc4_hdmi->scdc_enabled) -+ return; ++ /* 200mA */ ++ .int_current_ctl = 8, ++ ++ /* Internal Current Source Half Swing Enable*/ ++ .int_current_src_hs_en = 1, ++ ++ /* 17.6 mA */ ++ .main_tap_current_select = 7, ++ }, ++ }, ++}; + -+ vc4_hdmi->scdc_enabled = false; ++static const struct vc6_phy_settings * ++vc6_phy_get_settings(unsigned long long tmds_rate) ++{ ++ unsigned int count = ARRAY_SIZE(vc6_hdmi_phy_settings); ++ unsigned int i; + -+ if (delayed_work_pending(&vc4_hdmi->scrambling_work)) -+ cancel_delayed_work_sync(&vc4_hdmi->scrambling_work); ++ for (i = 0; i < count; i++) { ++ const struct vc6_phy_settings *s = &vc6_hdmi_phy_settingsi; + -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) & -+ ~VC5_HDMI_SCRAMBLER_CTL_ENABLE); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ if (tmds_rate >= s->min_rate && tmds_rate <= s->max_rate) ++ return s; ++ } + -+ drm_scdc_set_scrambling(vc4_hdmi->ddc, false); -+ drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, false); ++ /* ++ * If the pixel clock exceeds our max setting, try the max ++ * setting anyway. ++ */ ++ return &vc6_hdmi_phy_settingscount - 1; +} + -+static void vc4_hdmi_scrambling_wq(struct work_struct *work) ++static const struct vc6_phy_lane_settings * ++vc6_phy_get_channel_settings(enum vc4_hdmi_phy_channel chan, ++ unsigned long long tmds_rate) +{ -+ struct vc4_hdmi *vc4_hdmi = container_of(to_delayed_work(work), -+ struct vc4_hdmi, -+ scrambling_work); ++ const struct vc6_phy_settings *settings = vc6_phy_get_settings(tmds_rate); + -+ if (drm_scdc_get_scrambling_status(vc4_hdmi->ddc)) -+ return; ++ if (chan == PHY_LANE_CK) ++ return &settings->clock; + -+ drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true); -+ drm_scdc_set_scrambling(vc4_hdmi->ddc, true); ++ return &settings->channelchan; ++} + -+ 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) -+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); ++static void vc6_hdmi_reset_phy(struct vc4_hdmi *vc4_hdmi) ++{ ++ lockdep_assert_held(&vc4_hdmi->hw_lock); ++ ++ HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0); ++ HDMI_WRITE(HDMI_TX_PHY_POWERUP_CTL, 0); ++} ++ ++void vc6_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, ++ struct vc4_hdmi_connector_state *conn_state) ++{ ++ const struct vc6_phy_lane_settings *chan0_settings; ++ const struct vc6_phy_lane_settings *chan1_settings; ++ const struct vc6_phy_lane_settings *chan2_settings; ++ const struct vc6_phy_lane_settings *clock_settings; ++ const struct vc4_hdmi_variant *variant = vc4_hdmi->variant; ++ unsigned long long pixel_freq = conn_state->tmds_char_rate; ++ unsigned long long vco_freq; ++ unsigned char word_sel; + unsigned long flags; ++ unsigned int vco_div; + -+ mutex_lock(&vc4_hdmi->mutex); ++ vco_freq = vc6_phy_get_vco_freq(pixel_freq, &vco_div); + -+ vc4_hdmi->output_enabled = false; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - - 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); + -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); - -+ mdelay(1); ++ vc6_hdmi_reset_phy(vc4_hdmi); + -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - 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); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_0, 0x810c6000); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_1, 0x00b8c451); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_2, 0x46402e31); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_3, 0x00b8c005); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_4, 0x42410261); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_5, 0xcc021001); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_6, 0xc8301c80); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_7, 0xb0804444); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_8, 0xf80f8000); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_REFCLK, ++ VC6_HDMI_TX_PHY_PLL_REFCLK_REFCLK_SEL_CMOS | ++ VC4_SET_FIELD(54, VC6_HDMI_TX_PHY_PLL_REFCLK_REFFRQ)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0x7f); ++ ++ HDMI_WRITE(HDMI_RM_OFFSET, ++ VC4_HDMI_RM_OFFSET_ONLY | ++ VC4_SET_FIELD(phy_get_rm_offset(vco_freq), ++ VC4_HDMI_RM_OFFSET_OFFSET)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_VCOCLK_DIV, ++ VC6_HDMI_TX_PHY_PLL_VCOCLK_DIV_VCODIV_EN | ++ VC4_SET_FIELD(vco_div, ++ VC6_HDMI_TX_PHY_PLL_VCOCLK_DIV_VCODIV)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_CFG, ++ VC4_SET_FIELD(0, VC4_HDMI_TX_PHY_PLL_CFG_PDIV)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_POST_KDIV, ++ VC4_SET_FIELD(2, VC6_HDMI_TX_PHY_PLL_POST_KDIV_CLK0_SEL) | ++ VC4_SET_FIELD(1, VC6_HDMI_TX_PHY_PLL_POST_KDIV_KDIV)); ++ ++ chan0_settings = ++ vc6_phy_get_channel_settings(variant->phy_lane_mappingPHY_LANE_0, ++ pixel_freq); ++ HDMI_WRITE(HDMI_TX_PHY_CTL_0, ++ VC4_SET_FIELD(chan0_settings->ext_current_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_CTL) | ++ VC4_SET_FIELD(chan0_settings->ffe_enable, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_ENABLE) | ++ VC4_SET_FIELD(chan0_settings->slew_rate_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_RATE_CTL) | ++ VC4_SET_FIELD(chan0_settings->ffe_post_tap_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_POST_TAP_EN) | ++ VC4_SET_FIELD(chan0_settings->ldmos_bias_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_LDMOS_BIAS_CTL) | ++ VC4_SET_FIELD(chan0_settings->com_mode_ldmos_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_COM_MODE_LDMOS_EN) | ++ VC4_SET_FIELD(chan0_settings->edge_sel, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EDGE_SEL) | ++ VC4_SET_FIELD(chan0_settings->ext_current_src_hs_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_HS_EN) | ++ VC4_SET_FIELD(chan0_settings->term_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_TERM_CTL) | ++ VC4_SET_FIELD(chan0_settings->ext_current_src_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_EN) | ++ VC4_SET_FIELD(chan0_settings->int_current_src_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_EN) | ++ VC4_SET_FIELD(chan0_settings->int_current_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_CTL) | ++ VC4_SET_FIELD(chan0_settings->int_current_src_hs_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_HS_EN) | ++ VC4_SET_FIELD(chan0_settings->main_tap_current_select, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_MAIN_TAP_CURRENT_SELECT) | ++ VC4_SET_FIELD(chan0_settings->post_tap_current_select, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_POST_TAP_CURRENT_SELECT) | ++ VC4_SET_FIELD(chan0_settings->slew_ctl_slow_loading, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_LOADING) | ++ VC4_SET_FIELD(chan0_settings->slew_ctl_slow_driving, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_DRIVING) | ++ VC4_SET_FIELD(chan0_settings->ffe_pre_tap_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_PRE_TAP_EN)); ++ ++ chan1_settings = ++ vc6_phy_get_channel_settings(variant->phy_lane_mappingPHY_LANE_1, ++ pixel_freq); ++ HDMI_WRITE(HDMI_TX_PHY_CTL_1, ++ VC4_SET_FIELD(chan1_settings->ext_current_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_CTL) | ++ VC4_SET_FIELD(chan1_settings->ffe_enable, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_ENABLE) | ++ VC4_SET_FIELD(chan1_settings->slew_rate_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_RATE_CTL) | ++ VC4_SET_FIELD(chan1_settings->ffe_post_tap_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_POST_TAP_EN) | ++ VC4_SET_FIELD(chan1_settings->ldmos_bias_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_LDMOS_BIAS_CTL) | ++ VC4_SET_FIELD(chan1_settings->com_mode_ldmos_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_COM_MODE_LDMOS_EN) | ++ VC4_SET_FIELD(chan1_settings->edge_sel, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EDGE_SEL) | ++ VC4_SET_FIELD(chan1_settings->ext_current_src_hs_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_HS_EN) | ++ VC4_SET_FIELD(chan1_settings->term_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_TERM_CTL) | ++ VC4_SET_FIELD(chan1_settings->ext_current_src_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_EN) | ++ VC4_SET_FIELD(chan1_settings->int_current_src_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_EN) | ++ VC4_SET_FIELD(chan1_settings->int_current_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_CTL) | ++ VC4_SET_FIELD(chan1_settings->int_current_src_hs_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_HS_EN) | ++ VC4_SET_FIELD(chan1_settings->main_tap_current_select, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_MAIN_TAP_CURRENT_SELECT) | ++ VC4_SET_FIELD(chan1_settings->post_tap_current_select, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_POST_TAP_CURRENT_SELECT) | ++ VC4_SET_FIELD(chan1_settings->slew_ctl_slow_loading, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_LOADING) | ++ VC4_SET_FIELD(chan1_settings->slew_ctl_slow_driving, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_DRIVING) | ++ VC4_SET_FIELD(chan1_settings->ffe_pre_tap_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_PRE_TAP_EN)); ++ ++ chan2_settings = ++ vc6_phy_get_channel_settings(variant->phy_lane_mappingPHY_LANE_2, ++ pixel_freq); ++ HDMI_WRITE(HDMI_TX_PHY_CTL_2, ++ VC4_SET_FIELD(chan2_settings->ext_current_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_CTL) | ++ VC4_SET_FIELD(chan2_settings->ffe_enable, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_ENABLE) | ++ VC4_SET_FIELD(chan2_settings->slew_rate_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_RATE_CTL) | ++ VC4_SET_FIELD(chan2_settings->ffe_post_tap_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_POST_TAP_EN) | ++ VC4_SET_FIELD(chan2_settings->ldmos_bias_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_LDMOS_BIAS_CTL) | ++ VC4_SET_FIELD(chan2_settings->com_mode_ldmos_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_COM_MODE_LDMOS_EN) | ++ VC4_SET_FIELD(chan2_settings->edge_sel, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EDGE_SEL) | ++ VC4_SET_FIELD(chan2_settings->ext_current_src_hs_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_HS_EN) | ++ VC4_SET_FIELD(chan2_settings->term_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_TERM_CTL) | ++ VC4_SET_FIELD(chan2_settings->ext_current_src_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_EN) | ++ VC4_SET_FIELD(chan2_settings->int_current_src_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_EN) | ++ VC4_SET_FIELD(chan2_settings->int_current_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_CTL) | ++ VC4_SET_FIELD(chan2_settings->int_current_src_hs_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_HS_EN) | ++ VC4_SET_FIELD(chan2_settings->main_tap_current_select, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_MAIN_TAP_CURRENT_SELECT) | ++ VC4_SET_FIELD(chan2_settings->post_tap_current_select, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_POST_TAP_CURRENT_SELECT) | ++ VC4_SET_FIELD(chan2_settings->slew_ctl_slow_loading, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_LOADING) | ++ VC4_SET_FIELD(chan2_settings->slew_ctl_slow_driving, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_DRIVING) | ++ VC4_SET_FIELD(chan2_settings->ffe_pre_tap_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_PRE_TAP_EN)); ++ ++ clock_settings = ++ vc6_phy_get_channel_settings(variant->phy_lane_mappingPHY_LANE_CK, ++ pixel_freq); ++ HDMI_WRITE(HDMI_TX_PHY_CTL_CK, ++ VC4_SET_FIELD(clock_settings->ext_current_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_CTL) | ++ VC4_SET_FIELD(clock_settings->ffe_enable, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_ENABLE) | ++ VC4_SET_FIELD(clock_settings->slew_rate_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_RATE_CTL) | ++ VC4_SET_FIELD(clock_settings->ffe_post_tap_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_POST_TAP_EN) | ++ VC4_SET_FIELD(clock_settings->ldmos_bias_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_LDMOS_BIAS_CTL) | ++ VC4_SET_FIELD(clock_settings->com_mode_ldmos_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_COM_MODE_LDMOS_EN) | ++ VC4_SET_FIELD(clock_settings->edge_sel, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EDGE_SEL) | ++ VC4_SET_FIELD(clock_settings->ext_current_src_hs_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_HS_EN) | ++ VC4_SET_FIELD(clock_settings->term_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_TERM_CTL) | ++ VC4_SET_FIELD(clock_settings->ext_current_src_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_EN) | ++ VC4_SET_FIELD(clock_settings->int_current_src_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_EN) | ++ VC4_SET_FIELD(clock_settings->int_current_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_CTL) | ++ VC4_SET_FIELD(clock_settings->int_current_src_hs_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_HS_EN) | ++ VC4_SET_FIELD(clock_settings->main_tap_current_select, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_MAIN_TAP_CURRENT_SELECT) | ++ VC4_SET_FIELD(clock_settings->post_tap_current_select, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_POST_TAP_CURRENT_SELECT) | ++ VC4_SET_FIELD(clock_settings->slew_ctl_slow_loading, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_LOADING) | ++ VC4_SET_FIELD(clock_settings->slew_ctl_slow_driving, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_DRIVING) | ++ VC4_SET_FIELD(clock_settings->ffe_pre_tap_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_PRE_TAP_EN)); ++ ++ if (pixel_freq >= 340000000) ++ word_sel = 3; ++ else ++ word_sel = 0; ++ HDMI_WRITE(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, word_sel); + -+ vc4_hdmi_disable_scrambling(encoder); ++ HDMI_WRITE(HDMI_TX_PHY_POWERUP_CTL, ++ VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_BG_PWRUP | ++ VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_LDO_PWRUP | ++ VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_BIAS_PWRUP | ++ VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_TX_CK_PWRUP | ++ VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_TX_2_PWRUP | ++ VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_TX_1_PWRUP | ++ VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_TX_0_PWRUP); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_POWERUP_CTL, ++ VC6_HDMI_TX_PHY_PLL_POWERUP_CTL_PLL_PWRUP); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_RESET_CTL, ++ HDMI_READ(HDMI_TX_PHY_PLL_RESET_CTL) & ++ ~VC6_HDMI_TX_PHY_PLL_RESET_CTL_PLL_RESETB); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_RESET_CTL, ++ HDMI_READ(HDMI_TX_PHY_PLL_RESET_CTL) | ++ VC6_HDMI_TX_PHY_PLL_RESET_CTL_PLL_RESETB); + -+ mutex_unlock(&vc4_hdmi->mutex); - } - --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); -+ unsigned long flags; - int ret; - -- if (vc4_hdmi->variant->phy_disable) -- vc4_hdmi->variant->phy_disable(vc4_hdmi); -+ mutex_lock(&vc4_hdmi->mutex); - -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - HDMI_WRITE(HDMI_VID_CTL, -- HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); -+ HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++} + -+ if (vc4_hdmi->variant->phy_disable) -+ vc4_hdmi->variant->phy_disable(vc4_hdmi); - - 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); - if (ret < 0) - DRM_ERROR("Failed to release power domain: %d\n", ret); --} - --static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) --{ -+ mutex_unlock(&vc4_hdmi->mutex); - } - --static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) -+static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, -+ struct drm_connector_state *state, -+ const struct drm_display_mode *mode) - { -+ unsigned long flags; - u32 csc_ctl; - -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); ++void vc6_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi) ++{ ++} +diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h +index b04b2fc8d831..59bfd69f54d9 100644 +--- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h +@@ -111,13 +111,30 @@ enum vc4_hdmi_field { + HDMI_TX_PHY_CTL_1, + HDMI_TX_PHY_CTL_2, + HDMI_TX_PHY_CTL_3, ++ HDMI_TX_PHY_CTL_CK, + HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1, + HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2, + HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4, + HDMI_TX_PHY_PLL_CFG, ++ HDMI_TX_PHY_PLL_CFG_PDIV, + HDMI_TX_PHY_PLL_CTL_0, + HDMI_TX_PHY_PLL_CTL_1, ++ HDMI_TX_PHY_PLL_MISC_0, ++ HDMI_TX_PHY_PLL_MISC_1, ++ HDMI_TX_PHY_PLL_MISC_2, ++ HDMI_TX_PHY_PLL_MISC_3, ++ HDMI_TX_PHY_PLL_MISC_4, ++ HDMI_TX_PHY_PLL_MISC_5, ++ HDMI_TX_PHY_PLL_MISC_6, ++ HDMI_TX_PHY_PLL_MISC_7, ++ HDMI_TX_PHY_PLL_MISC_8, ++ HDMI_TX_PHY_PLL_POST_KDIV, ++ HDMI_TX_PHY_PLL_POWERUP_CTL, ++ HDMI_TX_PHY_PLL_REFCLK, ++ HDMI_TX_PHY_PLL_RESET_CTL, ++ HDMI_TX_PHY_PLL_VCOCLK_DIV, + HDMI_TX_PHY_POWERDOWN_CTL, ++ HDMI_TX_PHY_POWERUP_CTL, + HDMI_TX_PHY_RESET_CTL, + HDMI_TX_PHY_TMDS_CLK_WORD_SEL, + HDMI_VEC_INTERFACE_CFG, +@@ -411,6 +428,206 @@ static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi1_fields = { + VC5_CSC_REG(HDMI_CSC_CHANNEL_CTL, 0x02c), + }; + ++static const struct vc4_hdmi_register __maybe_unused vc6_hdmi_hdmi0_fields = { ++ VC4_HD_REG(HDMI_DVP_CTL, 0x0000), ++ VC4_HD_REG(HDMI_MAI_CTL, 0x0010), ++ VC4_HD_REG(HDMI_MAI_THR, 0x0014), ++ VC4_HD_REG(HDMI_MAI_FMT, 0x0018), ++ VC4_HD_REG(HDMI_MAI_DATA, 0x001c), ++ VC4_HD_REG(HDMI_MAI_SMP, 0x0020), ++ VC4_HD_REG(HDMI_VID_CTL, 0x0044), ++ VC4_HD_REG(HDMI_FRAME_COUNT, 0x0060), ++ ++ VC4_HDMI_REG(HDMI_FIFO_CTL, 0x07c), ++ VC4_HDMI_REG(HDMI_AUDIO_PACKET_CONFIG, 0x0c0), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_CONFIG, 0x0c4), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_STATUS, 0x0cc), ++ VC4_HDMI_REG(HDMI_CRP_CFG, 0x0d0), ++ VC4_HDMI_REG(HDMI_CTS_0, 0x0d4), ++ VC4_HDMI_REG(HDMI_CTS_1, 0x0d8), ++ VC4_HDMI_REG(HDMI_SCHEDULER_CONTROL, 0x0e8), ++ VC4_HDMI_REG(HDMI_HORZA, 0x0ec), ++ VC4_HDMI_REG(HDMI_HORZB, 0x0f0), ++ VC4_HDMI_REG(HDMI_VERTA0, 0x0f4), ++ VC4_HDMI_REG(HDMI_VERTB0, 0x0f8), ++ VC4_HDMI_REG(HDMI_VERTA1, 0x100), ++ VC4_HDMI_REG(HDMI_VERTB1, 0x104), ++ VC4_HDMI_REG(HDMI_MISC_CONTROL, 0x114), ++ VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x0a4), ++ VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a8), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_1, 0x148), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_2, 0x14c), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_3, 0x150), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_4, 0x158), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_5, 0x15c), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_6, 0x160), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_7, 0x164), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_8, 0x168), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_9, 0x16c), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_10, 0x170), ++ VC4_HDMI_REG(HDMI_DEEP_COLOR_CONFIG_1, 0x18c), ++ VC4_HDMI_REG(HDMI_GCP_CONFIG, 0x194), ++ VC4_HDMI_REG(HDMI_GCP_WORD_1, 0x198), ++ VC4_HDMI_REG(HDMI_HOTPLUG, 0x1c8), ++ VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1e4), ++ ++ VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc), ++ VC5_DVP_REG(HDMI_VEC_INTERFACE_CFG, 0x0f0), ++ VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f4), ++ ++ VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000), ++ VC5_PHY_REG(HDMI_TX_PHY_POWERUP_CTL, 0x004), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_0, 0x008), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_1, 0x00c), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_2, 0x010), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_CK, 0x014), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_REFCLK, 0x01c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_POST_KDIV, 0x028), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_VCOCLK_DIV, 0x02c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CFG, 0x044), ++ VC5_PHY_REG(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, 0x054), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_0, 0x060), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_1, 0x064), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_2, 0x068), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_3, 0x06c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_4, 0x070), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_5, 0x074), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_6, 0x078), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_7, 0x07c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_8, 0x080), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_RESET_CTL, 0x190), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_POWERUP_CTL, 0x194), ++ ++ VC5_RM_REG(HDMI_RM_CONTROL, 0x000), ++ VC5_RM_REG(HDMI_RM_OFFSET, 0x018), ++ VC5_RM_REG(HDMI_RM_FORMAT, 0x01c), ++ ++ VC5_RAM_REG(HDMI_RAM_PACKET_START, 0x000), ++ ++ VC5_CEC_REG(HDMI_CEC_CNTRL_1, 0x010), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_2, 0x014), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_3, 0x018), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_4, 0x01c), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_5, 0x020), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_1, 0x028), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_2, 0x02c), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_3, 0x030), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_4, 0x034), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_1, 0x038), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_2, 0x03c), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_3, 0x040), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_4, 0x044), ++ ++ VC5_CSC_REG(HDMI_CSC_CTL, 0x000), ++ VC5_CSC_REG(HDMI_CSC_12_11, 0x004), ++ VC5_CSC_REG(HDMI_CSC_14_13, 0x008), ++ VC5_CSC_REG(HDMI_CSC_22_21, 0x00c), ++ VC5_CSC_REG(HDMI_CSC_24_23, 0x010), ++ VC5_CSC_REG(HDMI_CSC_32_31, 0x014), ++ VC5_CSC_REG(HDMI_CSC_34_33, 0x018), ++ VC5_CSC_REG(HDMI_CSC_CHANNEL_CTL, 0x02c), ++}; + - csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, - VC4_HD_CSC_CTL_ORDER); - -- if (enable) { -+ if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) { - /* CEA VICs other than #1 requre limited range RGB - * output unless overridden by an AVI infoframe. - * Apply a colorspace conversion to squash 0-255 down -@@ -464,49 +950,147 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) - - /* The RGB order applies even when CSC is disabled. */ - HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); ++static const struct vc4_hdmi_register __maybe_unused vc6_hdmi_hdmi1_fields = { ++ VC4_HD_REG(HDMI_DVP_CTL, 0x0000), ++ VC4_HD_REG(HDMI_MAI_CTL, 0x0030), ++ VC4_HD_REG(HDMI_MAI_THR, 0x0034), ++ VC4_HD_REG(HDMI_MAI_FMT, 0x0038), ++ VC4_HD_REG(HDMI_MAI_DATA, 0x003c), ++ VC4_HD_REG(HDMI_MAI_SMP, 0x0040), ++ VC4_HD_REG(HDMI_VID_CTL, 0x0048), ++ VC4_HD_REG(HDMI_FRAME_COUNT, 0x0064), ++ ++ VC4_HDMI_REG(HDMI_FIFO_CTL, 0x07c), ++ VC4_HDMI_REG(HDMI_AUDIO_PACKET_CONFIG, 0x0c0), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_CONFIG, 0x0c4), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_STATUS, 0x0cc), ++ VC4_HDMI_REG(HDMI_CRP_CFG, 0x0d0), ++ VC4_HDMI_REG(HDMI_CTS_0, 0x0d4), ++ VC4_HDMI_REG(HDMI_CTS_1, 0x0d8), ++ VC4_HDMI_REG(HDMI_SCHEDULER_CONTROL, 0x0e8), ++ VC4_HDMI_REG(HDMI_HORZA, 0x0ec), ++ VC4_HDMI_REG(HDMI_HORZB, 0x0f0), ++ VC4_HDMI_REG(HDMI_VERTA0, 0x0f4), ++ VC4_HDMI_REG(HDMI_VERTB0, 0x0f8), ++ VC4_HDMI_REG(HDMI_VERTA1, 0x100), ++ VC4_HDMI_REG(HDMI_VERTB1, 0x104), ++ VC4_HDMI_REG(HDMI_MISC_CONTROL, 0x114), ++ VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x0a4), ++ VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a8), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_1, 0x148), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_2, 0x14c), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_3, 0x150), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_4, 0x158), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_5, 0x15c), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_6, 0x160), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_7, 0x164), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_8, 0x168), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_9, 0x16c), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_10, 0x170), ++ VC4_HDMI_REG(HDMI_DEEP_COLOR_CONFIG_1, 0x18c), ++ VC4_HDMI_REG(HDMI_GCP_CONFIG, 0x194), ++ VC4_HDMI_REG(HDMI_GCP_WORD_1, 0x198), ++ VC4_HDMI_REG(HDMI_HOTPLUG, 0x1c8), ++ VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1e4), ++ ++ VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc), ++ VC5_DVP_REG(HDMI_VEC_INTERFACE_CFG, 0x0f0), ++ VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f4), ++ ++ VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000), ++ VC5_PHY_REG(HDMI_TX_PHY_POWERUP_CTL, 0x004), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_0, 0x008), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_1, 0x00c), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_2, 0x010), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_CK, 0x014), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_REFCLK, 0x01c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_POST_KDIV, 0x028), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_VCOCLK_DIV, 0x02c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CFG, 0x044), ++ VC5_PHY_REG(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, 0x054), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_0, 0x060), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_1, 0x064), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_2, 0x068), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_3, 0x06c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_4, 0x070), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_5, 0x074), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_6, 0x078), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_7, 0x07c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_8, 0x080), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_RESET_CTL, 0x190), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_POWERUP_CTL, 0x194), ++ ++ VC5_RM_REG(HDMI_RM_CONTROL, 0x000), ++ VC5_RM_REG(HDMI_RM_OFFSET, 0x018), ++ VC5_RM_REG(HDMI_RM_FORMAT, 0x01c), ++ ++ VC5_RAM_REG(HDMI_RAM_PACKET_START, 0x000), ++ ++ VC5_CEC_REG(HDMI_CEC_CNTRL_1, 0x010), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_2, 0x014), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_3, 0x018), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_4, 0x01c), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_5, 0x020), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_1, 0x028), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_2, 0x02c), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_3, 0x030), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_4, 0x034), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_1, 0x038), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_2, 0x03c), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_3, 0x040), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_4, 0x044), ++ ++ VC5_CSC_REG(HDMI_CSC_CTL, 0x000), ++ VC5_CSC_REG(HDMI_CSC_12_11, 0x004), ++ VC5_CSC_REG(HDMI_CSC_14_13, 0x008), ++ VC5_CSC_REG(HDMI_CSC_22_21, 0x00c), ++ VC5_CSC_REG(HDMI_CSC_24_23, 0x010), ++ VC5_CSC_REG(HDMI_CSC_32_31, 0x014), ++ VC5_CSC_REG(HDMI_CSC_34_33, 0x018), ++ VC5_CSC_REG(HDMI_CSC_CHANNEL_CTL, 0x02c), ++}; + -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); - } + static inline + void __iomem *__vc4_hdmi_get_field_base(struct vc4_hdmi *hdmi, + enum vc4_hdmi_regs reg) +@@ -498,8 +715,11 @@ static inline void vc4_hdmi_write(struct vc4_hdmi *hdmi, + + field = &variant->registersreg; + base = __vc4_hdmi_get_field_base(hdmi, field->reg); +- if (!base) ++ if (!base) { ++ dev_warn(&hdmi->pdev->dev, ++ "Unknown register ID %u\n", reg); + return; ++ } --static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) --{ -- u32 csc_ctl; + writel(value, base + field->offset); + } +diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c +index 04af672caacb..e9b0a21e5707 100644 +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -33,7 +33,7 @@ + #include "vc4_drv.h" + #include "vc4_regs.h" -- csc_ctl = 0x07; /* RGB_CONVERT_MODE = custom matrix, || USE_RGB_TO_YCBCR */ -+/* -+ * If we need to output Full Range RGB, then use the unity matrix -+ * -+ * 1 0 0 0 -+ * 0 1 0 0 -+ * 0 0 1 0 -+ * -+ * Matrix is signed 2p13 fixed point, with signed 9p6 offsets -+ */ -+static const u16 vc5_hdmi_csc_full_rgb_unity34 = { -+ { 0x2000, 0x0000, 0x0000, 0x0000 }, -+ { 0x0000, 0x2000, 0x0000, 0x0000 }, -+ { 0x0000, 0x0000, 0x2000, 0x0000 }, -+}; - -- if (enable) { -- /* CEA VICs other than #1 requre limited range RGB -- * output unless overridden by an AVI infoframe. -- * Apply a colorspace conversion to squash 0-255 down -- * to 16-235. The matrix here is: -- * -- * 0.8594 0 0 16 -- * 0 0.8594 0 16 -- * 0 0 0.8594 16 -- * 0 0 0 1 -- * Matrix is signed 2p13 fixed point, with signed 9p6 offsets -- */ -- HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x1b80); -- HDMI_WRITE(HDMI_CSC_14_13, (0x0400 << 16) | 0x0000); -- HDMI_WRITE(HDMI_CSC_22_21, (0x1b80 << 16) | 0x0000); -- HDMI_WRITE(HDMI_CSC_24_23, (0x0400 << 16) | 0x0000); -- HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000); -- HDMI_WRITE(HDMI_CSC_34_33, (0x0400 << 16) | 0x1b80); -- } else { -- /* Still use the matrix for full range, but make it unity. -- * Matrix is signed 2p13 fixed point, with signed 9p6 offsets -- */ -- HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x2000); -- HDMI_WRITE(HDMI_CSC_14_13, (0x0000 << 16) | 0x0000); -- HDMI_WRITE(HDMI_CSC_22_21, (0x2000 << 16) | 0x0000); -- HDMI_WRITE(HDMI_CSC_24_23, (0x0000 << 16) | 0x0000); -- HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000); -- HDMI_WRITE(HDMI_CSC_34_33, (0x0000 << 16) | 0x2000); -- } -+/* -+ * CEA VICs other than #1 require limited range RGB output unless -+ * overridden by an AVI infoframe. Apply a colorspace conversion to -+ * squash 0-255 down to 16-235. The matrix here is: -+ * -+ * 0.8594 0 0 16 -+ * 0 0.8594 0 16 -+ * 0 0 0.8594 16 -+ * -+ * Matrix is signed 2p13 fixed point, with signed 9p6 offsets -+ */ -+static const u16 vc5_hdmi_csc_full_rgb_to_limited_rgb34 = { -+ { 0x1b80, 0x0000, 0x0000, 0x0400 }, -+ { 0x0000, 0x1b80, 0x0000, 0x0400 }, -+ { 0x0000, 0x0000, 0x1b80, 0x0400 }, +-static const struct debugfs_reg32 hvs_regs = { ++static const struct debugfs_reg32 vc4_hvs_regs = { + VC4_REG32(SCALER_DISPCTRL), + VC4_REG32(SCALER_DISPSTAT), + VC4_REG32(SCALER_DISPID), +@@ -67,6 +67,139 @@ static const struct debugfs_reg32 hvs_regs = { + VC4_REG32(SCALER_OLEDCOEF2), + }; + ++static const struct debugfs_reg32 vc6_hvs_regs = { ++ VC4_REG32(SCALER6_VERSION), ++ VC4_REG32(SCALER6_CXM_SIZE), ++ VC4_REG32(SCALER6_LBM_SIZE), ++ VC4_REG32(SCALER6_UBM_SIZE), ++ VC4_REG32(SCALER6_COBA_SIZE), ++ VC4_REG32(SCALER6_COB_SIZE), ++ VC4_REG32(SCALER6_CONTROL), ++ VC4_REG32(SCALER6_FETCHER_STATUS), ++ VC4_REG32(SCALER6_FETCH_STATUS), ++ VC4_REG32(SCALER6_HANDLE_ERROR), ++ VC4_REG32(SCALER6_DISP0_CTRL0), ++ VC4_REG32(SCALER6_DISP0_CTRL1), ++ VC4_REG32(SCALER6_DISP0_BGND), ++ VC4_REG32(SCALER6_DISP0_LPTRS), ++ VC4_REG32(SCALER6_DISP0_COB), ++ VC4_REG32(SCALER6_DISP0_STATUS), ++ VC4_REG32(SCALER6_DISP0_DL), ++ VC4_REG32(SCALER6_DISP0_RUN), ++ VC4_REG32(SCALER6_DISP1_CTRL0), ++ VC4_REG32(SCALER6_DISP1_CTRL1), ++ VC4_REG32(SCALER6_DISP1_BGND), ++ VC4_REG32(SCALER6_DISP1_LPTRS), ++ VC4_REG32(SCALER6_DISP1_COB), ++ VC4_REG32(SCALER6_DISP1_STATUS), ++ VC4_REG32(SCALER6_DISP1_DL), ++ VC4_REG32(SCALER6_DISP1_RUN), ++ VC4_REG32(SCALER6_DISP2_CTRL0), ++ VC4_REG32(SCALER6_DISP2_CTRL1), ++ VC4_REG32(SCALER6_DISP2_BGND), ++ VC4_REG32(SCALER6_DISP2_LPTRS), ++ VC4_REG32(SCALER6_DISP2_COB), ++ VC4_REG32(SCALER6_DISP2_STATUS), ++ VC4_REG32(SCALER6_DISP2_DL), ++ VC4_REG32(SCALER6_DISP2_RUN), ++ VC4_REG32(SCALER6_EOLN), ++ VC4_REG32(SCALER6_DL_STATUS), ++ VC4_REG32(SCALER6_QOS0), ++ VC4_REG32(SCALER6_PROF0), ++ VC4_REG32(SCALER6_QOS1), ++ VC4_REG32(SCALER6_PROF1), ++ VC4_REG32(SCALER6_QOS2), ++ VC4_REG32(SCALER6_PROF2), ++ VC4_REG32(SCALER6_PRI_MAP0), ++ VC4_REG32(SCALER6_PRI_MAP1), ++ VC4_REG32(SCALER6_HISTCTRL), ++ VC4_REG32(SCALER6_HISTBIN0), ++ VC4_REG32(SCALER6_HISTBIN1), ++ VC4_REG32(SCALER6_HISTBIN2), ++ VC4_REG32(SCALER6_HISTBIN3), ++ VC4_REG32(SCALER6_HISTBIN4), ++ VC4_REG32(SCALER6_HISTBIN5), ++ VC4_REG32(SCALER6_HISTBIN6), ++ VC4_REG32(SCALER6_HISTBIN7), ++ VC4_REG32(SCALER6_HDR_CFG_REMAP), ++ VC4_REG32(SCALER6_COL_SPACE), ++ VC4_REG32(SCALER6_HVS_ID), ++ VC4_REG32(SCALER6_CFC1), ++ VC4_REG32(SCALER6_DISP_UPM_ISO0), ++ VC4_REG32(SCALER6_DISP_UPM_ISO1), ++ VC4_REG32(SCALER6_DISP_UPM_ISO2), ++ VC4_REG32(SCALER6_DISP_LBM_ISO0), ++ VC4_REG32(SCALER6_DISP_LBM_ISO1), ++ VC4_REG32(SCALER6_DISP_LBM_ISO2), ++ VC4_REG32(SCALER6_DISP_COB_ISO0), ++ VC4_REG32(SCALER6_DISP_COB_ISO1), ++ VC4_REG32(SCALER6_DISP_COB_ISO2), ++ VC4_REG32(SCALER6_BAD_COB), ++ VC4_REG32(SCALER6_BAD_LBM), ++ VC4_REG32(SCALER6_BAD_UPM), ++ VC4_REG32(SCALER6_BAD_AXI), ++}; ++ ++static const struct debugfs_reg32 vc6_hvs_regs_d0 = { ++ VC4_REG32(SCALER6D0_VERSION), ++ VC4_REG32(SCALER6D0_CXM_SIZE), ++ VC4_REG32(SCALER6D0_LBM_SIZE), ++ VC4_REG32(SCALER6D0_UBM_SIZE), ++ VC4_REG32(SCALER6D0_COBA_SIZE), ++ VC4_REG32(SCALER6D0_COB_SIZE), ++ VC4_REG32(SCALER6D0_CONTROL), ++ VC4_REG32(SCALER6D0_FETCHER_STATUS), ++ VC4_REG32(SCALER6D0_FETCH_STATUS), ++ VC4_REG32(SCALER6D0_HANDLE_ERROR), ++ VC4_REG32(SCALER6D0_DISP0_CTRL0), ++ VC4_REG32(SCALER6D0_DISP0_CTRL1), ++ VC4_REG32(SCALER6D0_DISP0_BGND0), ++ VC4_REG32(SCALER6D0_DISP0_BGND1), ++ VC4_REG32(SCALER6D0_DISP0_LPTRS), ++ VC4_REG32(SCALER6D0_DISP0_COB), ++ VC4_REG32(SCALER6D0_DISP0_STATUS), ++ VC4_REG32(SCALER6D0_DISP0_DL), ++ VC4_REG32(SCALER6D0_DISP0_RUN), ++ VC4_REG32(SCALER6D0_DISP1_CTRL0), ++ VC4_REG32(SCALER6D0_DISP1_CTRL1), ++ VC4_REG32(SCALER6D0_DISP1_BGND0), ++ VC4_REG32(SCALER6D0_DISP1_BGND1), ++ VC4_REG32(SCALER6D0_DISP1_LPTRS), ++ VC4_REG32(SCALER6D0_DISP1_COB), ++ VC4_REG32(SCALER6D0_DISP1_STATUS), ++ VC4_REG32(SCALER6D0_DISP1_DL), ++ VC4_REG32(SCALER6D0_DISP1_RUN), ++ VC4_REG32(SCALER6D0_DISP2_CTRL0), ++ VC4_REG32(SCALER6D0_DISP2_CTRL1), ++ VC4_REG32(SCALER6D0_DISP2_BGND0), ++ VC4_REG32(SCALER6D0_DISP2_BGND1), ++ VC4_REG32(SCALER6D0_DISP2_LPTRS), ++ VC4_REG32(SCALER6D0_DISP2_COB), ++ VC4_REG32(SCALER6D0_DISP2_STATUS), ++ VC4_REG32(SCALER6D0_DISP2_DL), ++ VC4_REG32(SCALER6D0_DISP2_RUN), ++ VC4_REG32(SCALER6D0_EOLN), ++ VC4_REG32(SCALER6D0_DL_STATUS), ++ VC4_REG32(SCALER6D0_QOS0), ++ VC4_REG32(SCALER6D0_PROF0), ++ VC4_REG32(SCALER6D0_QOS1), ++ VC4_REG32(SCALER6D0_PROF1), ++ VC4_REG32(SCALER6D0_QOS2), ++ VC4_REG32(SCALER6D0_PROF2), ++ VC4_REG32(SCALER6D0_PRI_MAP0), ++ VC4_REG32(SCALER6D0_PRI_MAP1), ++ VC4_REG32(SCALER6D0_HISTCTRL), ++ VC4_REG32(SCALER6D0_HISTBIN0), ++ VC4_REG32(SCALER6D0_HISTBIN1), ++ VC4_REG32(SCALER6D0_HISTBIN2), ++ VC4_REG32(SCALER6D0_HISTBIN3), ++ VC4_REG32(SCALER6D0_HISTBIN4), ++ VC4_REG32(SCALER6D0_HISTBIN5), ++ VC4_REG32(SCALER6D0_HISTBIN6), ++ VC4_REG32(SCALER6D0_HISTBIN7), ++ VC4_REG32(SCALER6D0_HVS_ID), +}; ++ + void vc4_hvs_dump_state(struct vc4_hvs *hvs) + { + struct drm_device *drm = &hvs->vc4->base; +@@ -110,7 +243,8 @@ static int vc4_hvs_debugfs_dlist(struct seq_file *m, void *data) + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_hvs *hvs = vc4->hvs; + struct drm_printer p = drm_seq_file_printer(m); +- unsigned int next_entry_start = 0; ++ unsigned int dlist_mem_size = hvs->dlist_mem_size; ++ unsigned int next_entry_start; + unsigned int i, j; + u32 dlist_word, dispstat; -- HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); --} -+/* -+ * Conversion between Full Range RGB and Full Range YUV422 using the -+ * BT.709 Colorspace -+ * -+ * 0.212639 0.715169 0.072192 0 -+ * -0.117208 -0.394207 0.511416 128 -+ * 0.511416 -0.464524 -0.046891 128 -+ * -+ * Matrix is signed 2p13 fixed point, with signed 9p6 offsets -+ */ -+static const u16 vc5_hdmi_csc_full_rgb_to_full_yuv422_bt70934 = { -+ { 0x06ce, 0x16e3, 0x024f, 0x0000 }, -+ { 0xfc41, 0xf364, 0x105e, 0x2000 }, -+ { 0x105e, 0xf124, 0xfe81, 0x2000 }, -+}; +@@ -123,9 +257,59 @@ static int vc4_hvs_debugfs_dlist(struct seq_file *m, void *data) + continue; + } --static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, -- struct drm_display_mode *mode) -+/* -+ * Conversion between Full Range RGB and Full Range YUV444 using the -+ * BT.709 Colorspace -+ * -+ * -0.117208 -0.394207 0.511416 128 -+ * 0.511416 -0.464524 -0.046891 128 -+ * 0.212639 0.715169 0.072192 0 -+ * -+ * Matrix is signed 2p13 fixed point, with signed 9p6 offsets -+ */ -+static const u16 vc5_hdmi_csc_full_rgb_to_full_yuv444_bt70934 = { -+ { 0xfc41, 0xf364, 0x105e, 0x2000 }, -+ { 0x105e, 0xf124, 0xfe81, 0x2000 }, -+ { 0x06ce, 0x16e3, 0x024f, 0x0000 }, -+}; ++ drm_printf(&p, "HVS chan %u:\n", i); ++ next_entry_start = 0; + -+static void vc5_hdmi_set_csc_coeffs(struct vc4_hdmi *vc4_hdmi, -+ const u16 coeffs34) -+{ -+ lockdep_assert_held(&vc4_hdmi->hw_lock); ++ for (j = HVS_READ(SCALER_DISPLISTX(i)); j < dlist_mem_size; j++) { ++ dlist_word = readl((u32 __iomem *)vc4->hvs->dlist + j); ++ drm_printf(&p, "dlist: %02d: 0x%08x\n", j, ++ dlist_word); ++ 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); ++ } ++ } ++ } + -+ HDMI_WRITE(HDMI_CSC_12_11, (coeffs01 << 16) | coeffs00); -+ HDMI_WRITE(HDMI_CSC_14_13, (coeffs03 << 16) | coeffs02); -+ HDMI_WRITE(HDMI_CSC_22_21, (coeffs11 << 16) | coeffs10); -+ HDMI_WRITE(HDMI_CSC_24_23, (coeffs13 << 16) | coeffs12); -+ HDMI_WRITE(HDMI_CSC_32_31, (coeffs21 << 16) | coeffs20); -+ HDMI_WRITE(HDMI_CSC_34_33, (coeffs23 << 16) | coeffs22); ++ return 0; +} + -+static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, -+ struct drm_connector_state *state, -+ const struct drm_display_mode *mode) ++static int vc6_hvs_debugfs_dlist(struct seq_file *m, void *data) +{ -+ struct vc4_hdmi_connector_state *vc4_state = -+ conn_state_to_vc4_hdmi_conn_state(state); -+ unsigned long flags; -+ u32 if_cfg = 0; -+ u32 if_xbar = 0x543210; -+ u32 csc_chan_ctl = 0; -+ u32 csc_ctl = VC5_MT_CP_CSC_CTL_ENABLE | VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM, -+ VC5_MT_CP_CSC_CTL_MODE); ++ struct drm_debugfs_entry *entry = m->private; ++ struct drm_device *dev = entry->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_hvs *hvs = vc4->hvs; ++ struct drm_printer p = drm_seq_file_printer(m); ++ unsigned int dlist_mem_size = hvs->dlist_mem_size; ++ unsigned int next_entry_start; ++ unsigned int i; + -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); ++ for (i = 0; i < SCALER_CHANNELS_COUNT; i++) { ++ unsigned int active_dlist, dispstat; ++ unsigned int j; + -+ switch (vc4_state->output_format) { -+ case VC4_HDMI_OUTPUT_YUV444: -+ vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_full_yuv444_bt709); -+ break; ++ dispstat = VC4_GET_FIELD6(HVS_READ(SCALER6_DISPX_STATUS(i)), ++ DISPX_STATUS_MODE); ++ if (dispstat == SCALER6(DISPX_STATUS_MODE_DISABLED) || ++ dispstat == SCALER6(DISPX_STATUS_MODE_EOF)) { ++ drm_printf(&p, "HVS chan %u disabled\n", i); ++ continue; ++ } + -+ case VC4_HDMI_OUTPUT_YUV422: -+ csc_ctl |= VC4_SET_FIELD(VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD, -+ VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422) | -+ VC5_MT_CP_CSC_CTL_USE_444_TO_422 | -+ VC5_MT_CP_CSC_CTL_USE_RNG_SUPPRESSION; + drm_printf(&p, "HVS chan %u:\n", i); + +- for (j = HVS_READ(SCALER_DISPLISTX(i)); j < 256; j++) { ++ active_dlist = VC4_GET_FIELD6(HVS_READ(SCALER6_DISPX_DL(i)), ++ DISPX_DL_LACT); ++ next_entry_start = 0; ++ ++ for (j = active_dlist; j < dlist_mem_size; j++) { ++ u32 dlist_word; ++ + dlist_word = readl((u32 __iomem *)vc4->hvs->dlist + j); + drm_printf(&p, "dlist: %02d: 0x%08x\n", j, + dlist_word); +@@ -143,6 +327,115 @@ static int vc4_hvs_debugfs_dlist(struct seq_file *m, void *data) + return 0; + } + ++static int vc5_hvs_debugfs_gamma(struct seq_file *m, void *data) ++{ ++ struct drm_debugfs_entry *entry = m->private; ++ struct drm_device *dev = entry->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_hvs *hvs = vc4->hvs; ++ struct drm_printer p = drm_seq_file_printer(m); ++ unsigned int i, chan; ++ u32 dispstat, dispbkgndx; + -+ csc_chan_ctl |= VC4_SET_FIELD(VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_LEGACY_STYLE, -+ VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP); ++ for (chan = 0; chan < SCALER_CHANNELS_COUNT; chan++) { ++ u32 x_c, grad; ++ u32 offset = SCALER5_DSPGAMMA_START + ++ chan * SCALER5_DSPGAMMA_CHAN_OFFSET; + -+ if_cfg |= VC4_SET_FIELD(VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_FORMAT_422_LEGACY, -+ VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422); ++ dispstat = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTATX(chan)), ++ SCALER_DISPSTATX_MODE); ++ if (dispstat == SCALER_DISPSTATX_MODE_DISABLED || ++ dispstat == SCALER_DISPSTATX_MODE_EOF) { ++ drm_printf(&p, "HVS channel %u: Channel disabled\n", chan); ++ continue; ++ } + -+ vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_full_yuv422_bt709); -+ break; ++ dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(chan)); ++ if (!(dispbkgndx & SCALER_DISPBKGND_GAMMA)) { ++ drm_printf(&p, "HVS channel %u: Gamma disabled\n", chan); ++ continue; ++ } + -+ case VC4_HDMI_OUTPUT_RGB: -+ if_xbar = 0x354021; ++ drm_printf(&p, "HVS channel %u:\n", chan); ++ drm_printf(&p, " red:\n"); ++ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) { ++ x_c = HVS_READ(offset); ++ grad = HVS_READ(offset + 4); ++ drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n", ++ x_c, grad, ++ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X), ++ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C), ++ grad); ++ } ++ drm_printf(&p, " green:\n"); ++ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) { ++ x_c = HVS_READ(offset); ++ grad = HVS_READ(offset + 4); ++ drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n", ++ x_c, grad, ++ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X), ++ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C), ++ grad); ++ } ++ drm_printf(&p, " blue:\n"); ++ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) { ++ x_c = HVS_READ(offset); ++ grad = HVS_READ(offset + 4); ++ drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n", ++ x_c, grad, ++ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X), ++ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C), ++ grad); ++ } + -+ if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) -+ vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_rgb); -+ else -+ vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_unity); -+ break; ++ /* Alpha only valid on channel 2 */ ++ if (chan != 2) ++ continue; + -+ default: -+ break; ++ drm_printf(&p, " alpha:\n"); ++ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) { ++ x_c = HVS_READ(offset); ++ grad = HVS_READ(offset + 4); ++ drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n", ++ x_c, grad, ++ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X), ++ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C), ++ grad); ++ } + } -+ -+ HDMI_WRITE(HDMI_VEC_INTERFACE_CFG, if_cfg); -+ HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, if_xbar); -+ HDMI_WRITE(HDMI_CSC_CHANNEL_CTL, csc_chan_ctl); -+ HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); -+ -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ return 0; +} + -+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; - bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; -@@ -518,13 +1102,16 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, - 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)); ++static int vc4_hvs_debugfs_dlist_allocs(struct seq_file *m, void *data) ++{ ++ struct drm_debugfs_entry *entry = m->private; ++ struct drm_device *dev = entry->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_hvs *hvs = vc4->hvs; ++ struct drm_printer p = drm_seq_file_printer(m); ++ struct vc4_hvs_dlist_allocation *cur, *next; ++ struct drm_mm_node *mm_node; + unsigned long flags; + -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - - HDMI_WRITE(HDMI_HORZA, - (vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) | -@@ -548,10 +1135,16 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, - - HDMI_WRITE(HDMI_VERTB0, vertb_even); - HDMI_WRITE(HDMI_VERTB1, vertb); -+ -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); - } -+ - static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, -+ struct drm_connector_state *state, - struct drm_display_mode *mode) - { -+ const struct vc4_hdmi_connector_state *vc4_state = -+ conn_state_to_vc4_hdmi_conn_state(state); - bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; - bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; - bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE; -@@ -562,15 +1155,20 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, - 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 long flags; -+ unsigned char gcp; -+ bool gcp_en; -+ u32 reg; ++ spin_lock_irqsave(&hvs->mm_lock, flags); + -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - -- HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021); - HDMI_WRITE(HDMI_HORZA, - (vsync_pos ? VC5_HDMI_HORZA_VPOS : 0) | - (hsync_pos ? VC5_HDMI_HORZA_HPOS : 0) | -@@ -594,14 +1192,66 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, - HDMI_WRITE(HDMI_VERTB0, vertb_even); - HDMI_WRITE(HDMI_VERTB1, vertb); - -+ switch (vc4_state->output_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; ++ drm_printf(&p, "Allocated nodes:\n"); ++ list_for_each_entry(mm_node, drm_mm_nodes(&hvs->dlist_mm), node_list) { ++ drm_printf(&p, "node %08llx + %08llx\n", mm_node->start, mm_node->size); + } + -+ /* -+ * YCC422 is always 36-bit and not considered deep colour so -+ * doesn't signal in GCP -+ */ -+ if (vc4_state->output_format == VC4_HDMI_OUTPUT_YUV422) { -+ gcp = 4; -+ gcp_en = false; ++ drm_printf(&p, "Stale nodes:\n"); ++ list_for_each_entry_safe(cur, next, &hvs->stale_dlist_entries, node) { ++ drm_printf(&p, "node %08llx + %08llx channel %u frcnt %u\n", ++ cur->mm_node.start, cur->mm_node.size, cur->channel, ++ cur->target_frame_count); + } + -+ 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); ++ spin_unlock_irqrestore(&hvs->mm_lock, flags); + -+ 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); -+ -+ reg = HDMI_READ(HDMI_MISC_CONTROL); -+ reg &= ~VC5_HDMI_MISC_CONTROL_PIXEL_REP_MASK; -+ reg |= VC4_SET_FIELD(0, VC5_HDMI_MISC_CONTROL_PIXEL_REP); -+ HDMI_WRITE(HDMI_MISC_CONTROL, reg); ++ return 0; ++} + - HDMI_WRITE(HDMI_CLOCK_STOP, 0); + /* The filter kernel is composed of dwords each containing 3 9-bit + * signed integers packed next to each other. + */ +@@ -213,12 +506,15 @@ static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs, + static void vc4_hvs_lut_load(struct vc4_hvs *hvs, + struct vc4_crtc *vc4_crtc) + { +- struct drm_device *drm = &hvs->vc4->base; ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *drm = &vc4->base; + struct drm_crtc *crtc = &vc4_crtc->base; + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); + int idx; + u32 i; + ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_5); + -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); - } + if (!drm_dev_enter(drm, &idx)) + return; - static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi) +@@ -243,7 +539,8 @@ static void vc4_hvs_lut_load(struct vc4_hvs *hvs, + static void vc4_hvs_update_gamma_lut(struct vc4_hvs *hvs, + struct vc4_crtc *vc4_crtc) { -+ unsigned long flags; - u32 drift; - int ret; +- struct drm_crtc_state *crtc_state = vc4_crtc->base.state; ++ struct drm_crtc *crtc = &vc4_crtc->base; ++ struct drm_crtc_state *crtc_state = crtc->state; + struct drm_color_lut *lut = crtc_state->gamma_lut->data; + u32 length = drm_color_lut_size(crtc_state->gamma_lut); + u32 i; +@@ -257,233 +554,769 @@ static void vc4_hvs_update_gamma_lut(struct vc4_hvs *hvs, + vc4_hvs_lut_load(hvs, vc4_crtc); + } -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ - drift = HDMI_READ(HDMI_FIFO_CTL); - drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK; +-u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo) ++static void vc5_hvs_write_gamma_entry(struct vc4_hvs *hvs, ++ u32 offset, ++ struct vc5_gamma_entry *gamma) + { +- struct drm_device *drm = &hvs->vc4->base; +- u8 field = 0; +- int idx; ++ HVS_WRITE(offset, gamma->x_c_terms); ++ HVS_WRITE(offset + 4, gamma->grad_term); ++} -@@ -609,133 +1259,164 @@ static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi) - drift & ~VC4_HDMI_FIFO_CTL_RECENTER); - HDMI_WRITE(HDMI_FIFO_CTL, - drift | VC4_HDMI_FIFO_CTL_RECENTER); +- if (!drm_dev_enter(drm, &idx)) +- return 0; ++static void vc5_hvs_lut_load(struct vc4_hvs *hvs, ++ struct vc4_crtc *vc4_crtc) ++{ ++ struct drm_crtc *crtc = &vc4_crtc->base; ++ struct drm_crtc_state *crtc_state = crtc->state; ++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); ++ u32 i; ++ u32 offset = SCALER5_DSPGAMMA_START + ++ vc4_state->assigned_channel * SCALER5_DSPGAMMA_CHAN_OFFSET; + -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) ++ vc5_hvs_write_gamma_entry(hvs, offset, &vc4_crtc->pwl_ri); ++ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) ++ vc5_hvs_write_gamma_entry(hvs, offset, &vc4_crtc->pwl_gi); ++ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) ++ vc5_hvs_write_gamma_entry(hvs, offset, &vc4_crtc->pwl_bi); + - usleep_range(1000, 1100); ++ if (vc4_state->assigned_channel == 2) { ++ /* Alpha only valid on channel 2 */ ++ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) ++ vc5_hvs_write_gamma_entry(hvs, offset, &vc4_crtc->pwl_ai); ++ } ++} + +- switch (fifo) { +- case 0: +- field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1), +- SCALER_DISPSTAT1_FRCNT0); +- break; +- case 1: +- field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1), +- SCALER_DISPSTAT1_FRCNT1); +- break; +- case 2: +- field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT2), +- SCALER_DISPSTAT2_FRCNT2); +- break; ++static void vc5_hvs_update_gamma_lut(struct vc4_hvs *hvs, ++ struct vc4_crtc *vc4_crtc) ++{ ++ struct drm_crtc *crtc = &vc4_crtc->base; ++ struct drm_color_lut *lut = crtc->state->gamma_lut->data; ++ unsigned int step, i; ++ u32 start, end; + -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); ++#define VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl, chan) \ ++ start = drm_color_lut_extract(luti * step.chan, 12); \ ++ end = drm_color_lut_extract(lut(i + 1) * step - 1.chan, 12); \ ++ \ ++ /* Negative gradients not permitted by the hardware, so \ ++ * flatten such points out. \ ++ */ \ ++ if (end < start) \ ++ end = start; \ ++ \ ++ /* Assume 12bit pipeline. \ ++ * X evenly spread over full range (12 bit). \ ++ * C as U12.4 format. \ ++ * Gradient as U4.8 format. \ ++ */ \ ++ vc4_crtc->pwli = \ ++ VC5_HVS_SET_GAMMA_ENTRY(i << 8, start << 4, \ ++ ((end - start) << 4) / (step - 1)) + - HDMI_WRITE(HDMI_FIFO_CTL, - drift & ~VC4_HDMI_FIFO_CTL_RECENTER); - HDMI_WRITE(HDMI_FIFO_CTL, - drift | VC4_HDMI_FIFO_CTL_RECENTER); ++ /* HVS5 has a 16 point piecewise linear function for each colour ++ * channel (including alpha on channel 2) on each display channel. ++ * ++ * Currently take a crude subsample of the gamma LUT, but this could ++ * be improved to implement curve fitting. ++ */ ++ step = crtc->gamma_size / SCALER5_DSPGAMMA_NUM_POINTS; ++ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++) { ++ VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl_r, red); ++ VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl_g, green); ++ VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl_b, blue); + } -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); -+ - ret = wait_for(HDMI_READ(HDMI_FIFO_CTL) & - VC4_HDMI_FIFO_CTL_RECENTER_DONE, 1); - WARN_ONCE(ret, "Timeout waiting for " - "VC4_HDMI_FIFO_CTL_RECENTER_DONE"); +- drm_dev_exit(idx); +- return field; ++ vc5_hvs_lut_load(hvs, vc4_crtc); } --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) +-int vc4_hvs_get_fifo_from_output(struct vc4_hvs *hvs, unsigned int output) ++static void vc4_hvs_irq_enable_eof(struct vc4_hvs *hvs, ++ unsigned int channel) { -- 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 = &vc4_hdmi->saved_adjusted_mode; -+ unsigned long bvb_rate, pixel_rate, hsm_rate; -+ unsigned long flags; - int ret; + struct vc4_dev *vc4 = hvs->vc4; +- u32 reg; +- int ret; +- +- if (!vc4->is_vc5) +- return output; -+ mutex_lock(&vc4_hdmi->mutex); -+ - ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev); - if (ret < 0) { - DRM_ERROR("Failed to retain power domain: %d\n", ret); -- return; -+ goto out; - } +- /* +- * NOTE: We should probably use drm_dev_enter()/drm_dev_exit() +- * here, but this function is only used during the DRM device +- * initialization, so we should be fine. +- */ ++ if (hvs->eof_irqchannel.enabled) ++ 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); -- return; -+ goto err_runtime_pm; - } +- switch (output) { +- case 0: +- return 0; ++ switch (vc4->gen) { ++ case VC4_GEN_4: ++ HVS_WRITE(SCALER_DISPCTRL, ++ HVS_READ(SCALER_DISPCTRL) | ++ SCALER_DISPCTRL_DSPEIEOF(channel)); ++ break; - ret = clk_prepare_enable(vc4_hdmi->pixel_clock); - if (ret) { - DRM_ERROR("Failed to turn on pixel clock: %d\n", ret); -- return; -+ goto err_runtime_pm; - } +- case 1: +- return 1; ++ case VC4_GEN_5: ++ HVS_WRITE(SCALER_DISPCTRL, ++ HVS_READ(SCALER_DISPCTRL) | ++ SCALER5_DISPCTRL_DSPEIEOF(channel)); ++ break; -- /* -- * 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); -- return; -+ 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)); -+ goto err_disable_pixel_clk; +- case 2: +- reg = HVS_READ(SCALER_DISPECTRL); +- ret = FIELD_GET(SCALER_DISPECTRL_DSP2_MUX_MASK, reg); +- if (ret == 0) +- return 2; ++ case VC4_GEN_6: ++ enable_irq(hvs->eof_irqchannel.desc); ++ break; + +- return 0; ++ default: ++ break; ++ } + +- case 3: +- reg = HVS_READ(SCALER_DISPCTRL); +- ret = FIELD_GET(SCALER_DISPCTRL_DSP3_MUX_MASK, reg); +- if (ret == 3) +- return -EPIPE; ++ hvs->eof_irqchannel.enabled = true; ++} + +- return ret; ++static void vc4_hvs_irq_clear_eof(struct vc4_hvs *hvs, ++ unsigned int channel) ++{ ++ struct vc4_dev *vc4 = hvs->vc4; + +- case 4: +- reg = HVS_READ(SCALER_DISPEOLN); +- ret = FIELD_GET(SCALER_DISPEOLN_DSP4_MUX_MASK, reg); +- if (ret == 3) +- return -EPIPE; ++ if (!hvs->eof_irqchannel.enabled) ++ return; + +- return ret; ++ switch (vc4->gen) { ++ case VC4_GEN_4: ++ HVS_WRITE(SCALER_DISPCTRL, ++ HVS_READ(SCALER_DISPCTRL) & ++ ~SCALER_DISPCTRL_DSPEIEOF(channel)); ++ break; + +- case 5: +- reg = HVS_READ(SCALER_DISPDITHER); +- ret = FIELD_GET(SCALER_DISPDITHER_DSP5_MUX_MASK, reg); +- if (ret == 3) +- return -EPIPE; ++ case VC4_GEN_5: ++ HVS_WRITE(SCALER_DISPCTRL, ++ HVS_READ(SCALER_DISPCTRL) & ++ ~SCALER5_DISPCTRL_DSPEIEOF(channel)); ++ break; + +- return ret; ++ case VC4_GEN_6: ++ disable_irq_nosync(hvs->eof_irqchannel.desc); ++ break; + + default: +- return -EPIPE; ++ break; } ++ ++ hvs->eof_irqchannel.enabled = false; + } - vc4_hdmi_cec_update_clk_div(vc4_hdmi); +-static int vc4_hvs_init_channel(struct vc4_hvs *hvs, struct drm_crtc *crtc, +- struct drm_display_mode *mode, bool oneshot) ++static void vc4_hvs_free_dlist_entry_locked(struct vc4_hvs *hvs, ++ struct vc4_hvs_dlist_allocation *alloc); ++ ++static struct vc4_hvs_dlist_allocation * ++vc4_hvs_alloc_dlist_entry(struct vc4_hvs *hvs, ++ unsigned int channel, ++ size_t dlist_count) + { + struct vc4_dev *vc4 = hvs->vc4; +- struct drm_device *drm = &vc4->base; +- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); +- struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state); +- unsigned int chan = vc4_crtc_state->assigned_channel; +- bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE; +- u32 dispbkgndx; +- u32 dispctrl; +- int idx; ++ struct drm_device *dev = &vc4->base; ++ struct vc4_hvs_dlist_allocation *alloc; ++ struct vc4_hvs_dlist_allocation *cur, *next; ++ unsigned long flags; ++ int ret; -- /* -- * FIXME: When the pixel freq is 594MHz (4k60), this needs to be setup -- * at 300MHz. +- if (!drm_dev_enter(drm, &idx)) +- return -ENODEV; ++ if (channel == VC4_HVS_CHANNEL_DISABLED) ++ return NULL; + +- HVS_WRITE(SCALER_DISPCTRLX(chan), 0); +- HVS_WRITE(SCALER_DISPCTRLX(chan), SCALER_DISPCTRLX_RESET); +- HVS_WRITE(SCALER_DISPCTRLX(chan), 0); ++ alloc = kzalloc(sizeof(*alloc), GFP_KERNEL); ++ if (!alloc) ++ return ERR_PTR(-ENOMEM); + +- /* Turn on the scaler, which will wait for vstart to start +- * compositing. +- * When feeding the transposer, we should operate in oneshot +- * mode. - */ -- 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); -- clk_disable_unprepare(vc4_hdmi->pixel_clock); -- return; -+ if (pixel_rate > 297000000) -+ bvb_rate = 300000000; -+ else if (pixel_rate > 148500000) -+ bvb_rate = 150000000; -+ else -+ bvb_rate = 75000000; +- dispctrl = SCALER_DISPCTRLX_ENABLE; +- dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(chan)); ++ INIT_LIST_HEAD(&alloc->node); + +- if (!vc4->is_vc5) { +- dispctrl |= VC4_SET_FIELD(mode->hdisplay, +- SCALER_DISPCTRLX_WIDTH) | +- VC4_SET_FIELD(mode->vdisplay, +- SCALER_DISPCTRLX_HEIGHT) | +- (oneshot ? SCALER_DISPCTRLX_ONESHOT : 0); +- dispbkgndx |= SCALER_DISPBKGND_AUTOHS; +- } else { +- dispctrl |= VC4_SET_FIELD(mode->hdisplay, +- SCALER5_DISPCTRLX_WIDTH) | +- VC4_SET_FIELD(mode->vdisplay, +- SCALER5_DISPCTRLX_HEIGHT) | +- (oneshot ? SCALER5_DISPCTRLX_ONESHOT : 0); +- dispbkgndx &= ~SCALER5_DISPBKGND_BCK2BCK; +- } ++ spin_lock_irqsave(&hvs->mm_lock, flags); ++ ret = drm_mm_insert_node(&hvs->dlist_mm, &alloc->mm_node, ++ dlist_count); ++ spin_unlock_irqrestore(&hvs->mm_lock, flags); ++ if (ret) { ++ drm_err(dev, "Failed to allocate DLIST entry. Requested size=%zu. ret=%d. DISPCTRL is %08x\n", ++ dlist_count, ret, HVS_READ(SCALER_DISPCTRL)); + -+ 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)); -+ goto err_remove_hsm_req; -+ } - } ++ /* This should never happen as stale entries should get released ++ * as the frame counter interrupt triggers. ++ * However we've seen this fail for reasons currently unknown. ++ * Free all stale entries now so we should be able to complete ++ * this allocation. ++ */ ++ spin_lock_irqsave(&hvs->mm_lock, flags); ++ list_for_each_entry_safe(cur, next, &hvs->stale_dlist_entries, node) { ++ vc4_hvs_free_dlist_entry_locked(hvs, cur); ++ } + +- HVS_WRITE(SCALER_DISPCTRLX(chan), dispctrl); ++ ret = drm_mm_insert_node(&hvs->dlist_mm, &alloc->mm_node, ++ dlist_count); ++ spin_unlock_irqrestore(&hvs->mm_lock, flags); - ret = clk_prepare_enable(vc4_hdmi->pixel_bvb_clock); - if (ret) { - DRM_ERROR("Failed to turn on pixel bvb clock: %d\n", ret); -- clk_disable_unprepare(vc4_hdmi->pixel_clock); -- return; -+ goto err_remove_bvb_req; - } +- dispbkgndx &= ~SCALER_DISPBKGND_GAMMA; +- dispbkgndx &= ~SCALER_DISPBKGND_INTERLACE; ++ if (ret) ++ return ERR_PTR(ret); ++ } - if (vc4_hdmi->variant->phy_init) -- vc4_hdmi->variant->phy_init(vc4_hdmi, mode); -+ vc4_hdmi->variant->phy_init(vc4_hdmi, vc4_conn_state); -+ -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); +- HVS_WRITE(SCALER_DISPBKGNDX(chan), dispbkgndx | +- ((!vc4->is_vc5) ? SCALER_DISPBKGND_GAMMA : 0) | +- (interlace ? SCALER_DISPBKGND_INTERLACE : 0)); ++ alloc->channel = channel; - HDMI_WRITE(HDMI_SCHEDULER_CONTROL, - HDMI_READ(HDMI_SCHEDULER_CONTROL) | - VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT | - VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS); +- /* Reload the LUT, since the SRAMs would have been disabled if +- * all CRTCs had SCALER_DISPBKGND_GAMMA unset at once. +- */ +- vc4_hvs_lut_load(hvs, vc4_crtc); ++ return alloc; ++} -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); -+ - if (vc4_hdmi->variant->set_timings) -- vc4_hdmi->variant->set_timings(vc4_hdmi, mode); -+ vc4_hdmi->variant->set_timings(vc4_hdmi, conn_state, mode); -+ -+ mutex_unlock(&vc4_hdmi->mutex); -+ -+ return; +- drm_dev_exit(idx); ++static void vc4_hvs_free_dlist_entry_locked(struct vc4_hvs *hvs, ++ struct vc4_hvs_dlist_allocation *alloc) ++{ ++ lockdep_assert_held(&hvs->mm_lock); + +- return 0; ++ if (!list_empty(&alloc->node)) ++ list_del(&alloc->node); + -+err_remove_bvb_req: -+ if (vc4_hdmi->bvb_req) -+ clk_request_done(vc4_hdmi->bvb_req); -+err_remove_hsm_req: -+ clk_request_done(vc4_hdmi->hsm_req); -+err_disable_pixel_clk: -+ clk_disable_unprepare(vc4_hdmi->pixel_clock); -+err_runtime_pm: -+ pm_runtime_put(&vc4_hdmi->pdev->dev); -+out: -+ mutex_unlock(&vc4_hdmi->mutex); -+ return; ++ drm_mm_remove_node(&alloc->mm_node); ++ kfree(alloc); } --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) +-void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan) ++void vc4_hvs_mark_dlist_entry_stale(struct vc4_hvs *hvs, ++ struct vc4_hvs_dlist_allocation *alloc) { -- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; -- struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); - struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); -+ struct drm_connector *connector = &vc4_hdmi->connector; -+ struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; -+ struct drm_connector_state *conn_state = -+ drm_atomic_get_new_connector_state(state, connector); +- struct drm_device *drm = &hvs->vc4->base; +- int idx; + unsigned long flags; ++ u8 frcnt; -- if (vc4_encoder->hdmi_monitor && -- drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED) { -- if (vc4_hdmi->variant->csc_setup) -- vc4_hdmi->variant->csc_setup(vc4_hdmi, true); -- -- vc4_encoder->limited_rgb_range = true; -- } else { -- if (vc4_hdmi->variant->csc_setup) -- vc4_hdmi->variant->csc_setup(vc4_hdmi, false); -+ mutex_lock(&vc4_hdmi->mutex); +- if (!drm_dev_enter(drm, &idx)) ++ if (!alloc) + return; -- vc4_encoder->limited_rgb_range = false; -- } -+ if (vc4_hdmi->variant->csc_setup) -+ vc4_hdmi->variant->csc_setup(vc4_hdmi, conn_state, mode); +- if (HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_ENABLE) +- goto out; ++ if (!drm_mm_node_allocated(&alloc->mm_node)) ++ return; -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); +- HVS_WRITE(SCALER_DISPCTRLX(chan), +- HVS_READ(SCALER_DISPCTRLX(chan)) | SCALER_DISPCTRLX_RESET); +- HVS_WRITE(SCALER_DISPCTRLX(chan), +- HVS_READ(SCALER_DISPCTRLX(chan)) & ~SCALER_DISPCTRLX_ENABLE); ++ /* ++ * Kunit tests run with a mock device and we consider any hardware ++ * access a test failure. Let's free the dlist allocation right away if ++ * we're running under kunit, we won't risk a dlist corruption anyway. ++ * ++ * Likewise if the allocation was only checked and never programmed, we ++ * can destroy the allocation immediately. ++ */ ++ if (kunit_get_current_test() || !alloc->dlist_programmed) { ++ spin_lock_irqsave(&hvs->mm_lock, flags); ++ vc4_hvs_free_dlist_entry_locked(hvs, alloc); ++ spin_unlock_irqrestore(&hvs->mm_lock, flags); ++ return; ++ } + +- /* Once we leave, the scaler should be disabled and its fifo empty. */ +- WARN_ON_ONCE(HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_RESET); ++ frcnt = vc4_hvs_get_fifo_frame_count(hvs, alloc->channel); ++ alloc->target_frame_count = (frcnt + 1) & ((1 << 6) - 1); + +- WARN_ON_ONCE(VC4_GET_FIELD(HVS_READ(SCALER_DISPSTATX(chan)), +- SCALER_DISPSTATX_MODE) != +- SCALER_DISPSTATX_MODE_DISABLED); ++ spin_lock_irqsave(&hvs->mm_lock, flags); + +- WARN_ON_ONCE((HVS_READ(SCALER_DISPSTATX(chan)) & +- (SCALER_DISPSTATX_FULL | SCALER_DISPSTATX_EMPTY)) != +- SCALER_DISPSTATX_EMPTY); ++ list_add_tail(&alloc->node, &hvs->stale_dlist_entries); + +-out: +- drm_dev_exit(idx); ++ HVS_WRITE(SCALER_DISPSTAT, SCALER_DISPSTAT_EOF(alloc->channel)); ++ vc4_hvs_irq_enable_eof(hvs, alloc->channel); + -+ mutex_unlock(&vc4_hdmi->mutex); ++ spin_unlock_irqrestore(&hvs->mm_lock, flags); } --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) +-int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) ++static void vc4_hvs_schedule_dlist_sweep(struct vc4_hvs *hvs, ++ unsigned int channel) { -- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; - struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); -+ struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; - struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); - bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; - bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; -+ unsigned long flags; - int ret; +- 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; + unsigned long flags; +- const struct drm_plane_state *plane_state; +- u32 dlist_count = 0; +- int ret; -+ mutex_lock(&vc4_hdmi->mutex); -+ -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ - 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) | -@@ -749,6 +1430,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder) - HDMI_READ(HDMI_SCHEDULER_CONTROL) | - VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); +- /* The pixelvalve can only feed one encoder (and encoders are +- * 1:1 with connectors.) +- */ +- if (hweight32(crtc_state->connector_mask) > 1) +- return -EINVAL; ++ spin_lock_irqsave(&hvs->mm_lock, flags); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); -+ - ret = wait_for(HDMI_READ(HDMI_SCHEDULER_CONTROL) & - VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1000); - WARN_ONCE(ret, "Timeout waiting for " -@@ -761,6 +1444,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder) - HDMI_READ(HDMI_SCHEDULER_CONTROL) & - ~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); +- drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) +- dlist_count += vc4_plane_dlist_size(plane_state); ++ if (!list_empty(&hvs->stale_dlist_entries)) ++ queue_work(system_unbound_wq, &hvs->free_dlist_work); + +- dlist_count++; /* Account for SCALER_CTL0_END. */ ++ if (list_empty(&hvs->stale_dlist_entries)) ++ vc4_hvs_irq_clear_eof(hvs, channel); + +- spin_lock_irqsave(&vc4->hvs->mm_lock, flags); +- ret = drm_mm_insert_node(&vc4->hvs->dlist_mm, &vc4_state->mm, +- dlist_count); +- spin_unlock_irqrestore(&vc4->hvs->mm_lock, flags); +- if (ret) +- return ret; ++ spin_unlock_irqrestore(&hvs->mm_lock, flags); ++} -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); -+ - ret = wait_for(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) & - VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1000); - WARN_ONCE(ret, "Timeout waiting for " -@@ -768,6 +1453,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder) - } +- return 0; ++/* ++ * Frame counts are essentially sequence numbers over 6 bits, and we ++ * thus can use sequence number arithmetic and follow the RFC1982 to ++ * implement proper comparison between them. ++ */ ++static bool vc4_hvs_frcnt_lte(u8 cnt1, u8 cnt2) ++{ ++ return (s8)((cnt1 << 2) - (cnt2 << 2)) <= 0; + } - if (vc4_encoder->hdmi_monitor) { -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ - WARN_ON(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) & - VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE)); - HDMI_WRITE(HDMI_SCHEDULER_CONTROL, -@@ -777,14 +1464,245 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder) - HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, - VC4_HDMI_RAM_PACKET_ENABLE); +-static void vc4_hvs_install_dlist(struct drm_crtc *crtc) ++bool vc4_hvs_check_channel_active(struct vc4_hvs *hvs, unsigned int fifo) + { +- struct drm_device *dev = crtc->dev; +- struct vc4_dev *vc4 = to_vc4_dev(dev); +- struct vc4_hvs *hvs = vc4->hvs; +- struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *drm = &vc4->base; ++ bool enabled = false; + int idx; -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); -+ vc4_hdmi->output_enabled = true; +- if (!drm_dev_enter(dev, &idx)) +- return; +- +- HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel), +- vc4_state->mm.start); ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_6); + - vc4_hdmi_set_infoframes(encoder); - } - - vc4_hdmi_recenter_fifo(vc4_hdmi); -+ vc4_hdmi_enable_scrambling(encoder); ++ if (!drm_dev_enter(drm, &idx)) ++ return 0; + -+ mutex_unlock(&vc4_hdmi->mutex); ++ if (vc4->gen >= VC4_GEN_6) ++ enabled = HVS_READ(SCALER6_DISPX_CTRL0(fifo)) & SCALER6(DISPX_CTRL0_ENB); ++ else ++ enabled = HVS_READ(SCALER_DISPCTRLX(fifo)) & SCALER_DISPCTRLX_ENABLE; ++ ++ drm_dev_exit(idx); ++ return enabled; +} + -+static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state) ++/* ++ * Some atomic commits (legacy cursor updates, mostly) will not wait for ++ * the next vblank and will just return once the commit has been pushed ++ * to the hardware. ++ * ++ * On the hardware side, our HVS stores the planes parameters in its ++ * context RAM, and will use part of the RAM to store data during the ++ * frame rendering. ++ * ++ * This interacts badly if we get multiple commits before the next ++ * vblank since we could end up overwriting the DLIST entries used by ++ * previous commits if our dlist allocation reuses that entry. In such a ++ * case, we would overwrite the data currently being used by the ++ * hardware, resulting in a corrupted frame. ++ * ++ * In order to work around this, we'll queue the dlist entries in a list ++ * once the associated CRTC state is destroyed. The HVS only allows us ++ * to know which entry is being active, but not which one are no longer ++ * being used, so in order to avoid freeing entries that are still used ++ * by the hardware we add a guesstimate of the frame count where our ++ * entry will no longer be used, and thus will only free those entries ++ * when we will have reached that frame count. ++ */ ++static void vc4_hvs_dlist_free_work(struct work_struct *work) +{ -+ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); -+ struct vc4_hdmi_connector_state *vc4_state = -+ conn_state_to_vc4_hdmi_conn_state(conn_state); ++ struct vc4_hvs *hvs = container_of(work, struct vc4_hvs, free_dlist_work); ++ struct vc4_hvs_dlist_allocation *cur, *next; ++ unsigned long flags; ++ bool active3; ++ u8 frcnt3; ++ int i; ++ ++ ++ spin_lock_irqsave(&hvs->mm_lock, flags); ++ for (i = 0; i < 3; i++) { ++ frcnti = vc4_hvs_get_fifo_frame_count(hvs, i); ++ activei = vc4_hvs_check_channel_active(hvs, i); ++ } ++ list_for_each_entry_safe(cur, next, &hvs->stale_dlist_entries, node) { ++ if (activecur->channel && ++ !vc4_hvs_frcnt_lte(cur->target_frame_count, frcntcur->channel)) ++ continue; + -+ mutex_lock(&vc4_hdmi->mutex); -+ vc4_hdmi->output_bpc = vc4_state->output_bpc; -+ vc4_hdmi->output_format = vc4_state->output_format; -+ vc4_hdmi->broadcast_rgb = vc4_state->broadcast_rgb; -+ memcpy(&vc4_hdmi->saved_adjusted_mode, -+ &crtc_state->adjusted_mode, -+ sizeof(vc4_hdmi->saved_adjusted_mode)); -+ mutex_unlock(&vc4_hdmi->mutex); ++ vc4_hvs_free_dlist_entry_locked(hvs, cur); ++ } ++ spin_unlock_irqrestore(&hvs->mm_lock, flags); +} + -+static bool -+vc4_hdmi_sink_supports_format_bpc(const struct vc4_hdmi *vc4_hdmi, -+ const struct drm_display_info *info, -+ const struct drm_display_mode *mode, -+ unsigned int format, unsigned int bpc) ++u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo) +{ -+ struct drm_device *dev = vc4_hdmi->connector.dev; -+ u8 vic = drm_match_cea_mode(mode); ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *drm = &vc4->base; ++ u8 field = 0; ++ int idx; + -+ if (vic == 1 && bpc != 8) { -+ drm_dbg(dev, "VIC1 requires a bpc of 8, got %u\n", bpc); -+ return false; -+ } ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_6); + -+ if (!info->is_hdmi && -+ (format != VC4_HDMI_OUTPUT_RGB || bpc != 8)) { -+ drm_dbg(dev, "DVI Monitors require an RGB output at 8 bpc\n"); -+ return false; ++ if (!drm_dev_enter(drm, &idx)) ++ return 0; ++ ++ switch (vc4->gen) { ++ case VC4_GEN_6: ++ field = VC4_GET_FIELD6(HVS_READ(SCALER6_DISPX_STATUS(fifo)), ++ DISPX_STATUS_FRCNT); ++ break; ++ case VC4_GEN_5: ++ switch (fifo) { ++ case 0: ++ field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1), ++ SCALER5_DISPSTAT1_FRCNT0); ++ break; ++ case 1: ++ field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1), ++ SCALER5_DISPSTAT1_FRCNT1); ++ break; ++ case 2: ++ field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT2), ++ SCALER5_DISPSTAT2_FRCNT2); ++ break; ++ } ++ break; ++ case VC4_GEN_4: ++ switch (fifo) { ++ case 0: ++ field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1), ++ SCALER_DISPSTAT1_FRCNT0); ++ break; ++ case 1: ++ field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1), ++ SCALER_DISPSTAT1_FRCNT1); ++ break; ++ case 2: ++ field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT2), ++ SCALER_DISPSTAT2_FRCNT2); ++ break; ++ } ++ break; + } + -+ switch (format) { -+ case VC4_HDMI_OUTPUT_RGB: -+ drm_dbg(dev, "RGB Format, checking the constraints.\n"); ++ drm_dev_exit(idx); ++ return field; ++} + -+ if (bpc == 10 && !(info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30)) { -+ drm_dbg(dev, "10 BPC but sink doesn't support Deep Color 30.\n"); -+ return false; -+ } ++int vc4_hvs_get_fifo_from_output(struct vc4_hvs *hvs, unsigned int output) ++{ ++ struct vc4_dev *vc4 = hvs->vc4; ++ u32 reg; ++ int ret; + -+ if (bpc == 12 && !(info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_36)) { -+ drm_dbg(dev, "12 BPC but sink doesn't support Deep Color 36.\n"); -+ return false; -+ } ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_6); + -+ drm_dbg(dev, "RGB format supported in that configuration.\n"); ++ switch (vc4->gen) { ++ case VC4_GEN_4: ++ return output; + -+ return true; ++ case VC4_GEN_5: ++ /* ++ * NOTE: We should probably use ++ * drm_dev_enter()/drm_dev_exit() here, but this ++ * function is only used during the DRM device ++ * initialization, so we should be fine. ++ */ + -+ case VC4_HDMI_OUTPUT_YUV422: -+ drm_dbg(dev, "YUV422 format, checking the constraints.\n"); ++ switch (output) { ++ case 0: ++ return 0; + -+ if (!(info->color_formats & DRM_COLOR_FORMAT_YCRCB422)) { -+ drm_dbg(dev, "Sink doesn't support YUV422.\n"); -+ return false; -+ } ++ case 1: ++ return 1; + -+ if (bpc != 12) { -+ drm_dbg(dev, "YUV422 only supports 12 bpc.\n"); -+ return false; -+ } ++ case 2: ++ reg = HVS_READ(SCALER_DISPECTRL); ++ ret = FIELD_GET(SCALER_DISPECTRL_DSP2_MUX_MASK, reg); ++ if (ret == 0) ++ return 2; + -+ drm_dbg(dev, "YUV422 format supported in that configuration.\n"); ++ return 0; + -+ return true; ++ case 3: ++ reg = HVS_READ(SCALER_DISPCTRL); ++ ret = FIELD_GET(SCALER_DISPCTRL_DSP3_MUX_MASK, reg); ++ if (ret == 3) ++ return -EPIPE; + -+ case VC4_HDMI_OUTPUT_YUV444: -+ drm_dbg(dev, "YUV444 format, checking the constraints.\n"); ++ return ret; + -+ if (!(info->color_formats & DRM_COLOR_FORMAT_YCRCB444)) { -+ drm_dbg(dev, "Sink doesn't support YUV444.\n"); -+ return false; -+ } ++ case 4: ++ reg = HVS_READ(SCALER_DISPEOLN); ++ ret = FIELD_GET(SCALER_DISPEOLN_DSP4_MUX_MASK, reg); ++ if (ret == 3) ++ return -EPIPE; + -+ if (bpc == 10 && !(info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30)) { -+ drm_dbg(dev, "10 BPC but sink doesn't support Deep Color 30.\n"); -+ return false; -+ } ++ return ret; + -+ if (bpc == 12 && !(info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_36)) { -+ drm_dbg(dev, "12 BPC but sink doesn't support Deep Color 36.\n"); -+ return false; ++ case 5: ++ reg = HVS_READ(SCALER_DISPDITHER); ++ ret = FIELD_GET(SCALER_DISPDITHER_DSP5_MUX_MASK, reg); ++ if (ret == 3) ++ return -EPIPE; ++ ++ return ret; ++ ++ default: ++ return -EPIPE; + } + -+ drm_dbg(dev, "YUV444 format supported in that configuration.\n"); ++ case VC4_GEN_6: ++ switch (output) { ++ case 0: ++ return 0; + -+ return true; ++ case 2: ++ return 2; ++ ++ case 1: ++ case 3: ++ case 4: ++ return 1; ++ ++ default: ++ return -EPIPE; ++ } + } + -+ return false; ++ return -EPIPE; +} + -+static enum drm_mode_status -+vc4_hdmi_encoder_clock_valid(const struct vc4_hdmi *vc4_hdmi, -+ unsigned long long clock) ++static int vc4_hvs_init_channel(struct vc4_hvs *hvs, struct drm_crtc *crtc, ++ struct drm_display_mode *mode, bool oneshot) +{ -+ const struct drm_connector *connector = &vc4_hdmi->connector; -+ const struct drm_display_info *info = &connector->display_info; ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *drm = &vc4->base; ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state); ++ unsigned int chan = vc4_crtc_state->assigned_channel; ++ bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE; ++ u32 dispbkgndx; ++ u32 dispctrl; ++ int idx; ++ ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_5); ++ ++ if (!drm_dev_enter(drm, &idx)) ++ return -ENODEV; ++ ++ HVS_WRITE(SCALER_DISPCTRLX(chan), 0); ++ HVS_WRITE(SCALER_DISPCTRLX(chan), SCALER_DISPCTRLX_RESET); ++ HVS_WRITE(SCALER_DISPCTRLX(chan), 0); ++ ++ /* Turn on the scaler, which will wait for vstart to start ++ * compositing. ++ * When feeding the transposer, we should operate in oneshot ++ * mode. ++ */ ++ dispctrl = SCALER_DISPCTRLX_ENABLE; ++ dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(chan)); + -+ if (clock > vc4_hdmi->variant->max_pixel_clock) -+ return MODE_CLOCK_HIGH; ++ if (vc4->gen == VC4_GEN_4) { ++ dispctrl |= VC4_SET_FIELD(mode->hdisplay, ++ SCALER_DISPCTRLX_WIDTH) | ++ VC4_SET_FIELD(mode->vdisplay, ++ SCALER_DISPCTRLX_HEIGHT) | ++ (oneshot ? SCALER_DISPCTRLX_ONESHOT : 0); ++ dispbkgndx |= SCALER_DISPBKGND_AUTOHS; ++ } else { ++ dispctrl |= VC4_SET_FIELD(mode->hdisplay, ++ SCALER5_DISPCTRLX_WIDTH) | ++ VC4_SET_FIELD(mode->vdisplay, ++ SCALER5_DISPCTRLX_HEIGHT) | ++ (oneshot ? SCALER5_DISPCTRLX_ONESHOT : 0); ++ dispbkgndx &= ~SCALER5_DISPBKGND_BCK2BCK; ++ } + -+ if (vc4_hdmi->disable_4kp60 && clock > HDMI_14_MAX_TMDS_CLK) -+ return MODE_CLOCK_HIGH; ++ HVS_WRITE(SCALER_DISPCTRLX(chan), dispctrl); + -+ if (info->max_tmds_clock && clock > (info->max_tmds_clock * 1000)) -+ return MODE_CLOCK_HIGH; ++ dispbkgndx &= ~SCALER_DISPBKGND_GAMMA; ++ dispbkgndx &= ~SCALER_DISPBKGND_INTERLACE; + -+ return MODE_OK; ++ if (crtc->state->gamma_lut) ++ /* Enable gamma on if required */ ++ dispbkgndx |= SCALER_DISPBKGND_GAMMA; ++ ++ HVS_WRITE(SCALER_DISPBKGNDX(chan), dispbkgndx | ++ (interlace ? SCALER_DISPBKGND_INTERLACE : 0)); ++ ++ /* Reload the LUT, since the SRAMs would have been disabled if ++ * all CRTCs had SCALER_DISPBKGND_GAMMA unset at once. ++ */ ++ if (vc4->gen == VC4_GEN_4) ++ vc4_hvs_lut_load(hvs, vc4_crtc); ++ else ++ vc5_hvs_lut_load(hvs, vc4_crtc); ++ ++ drm_dev_exit(idx); ++ ++ return 0; +} + -+static unsigned long long -+vc4_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode, -+ unsigned int bpc, -+ enum vc4_hdmi_output_format fmt) ++static int vc6_hvs_init_channel(struct vc4_hvs *hvs, struct drm_crtc *crtc, ++ struct drm_display_mode *mode, bool oneshot) +{ -+ unsigned long long clock = mode->clock * 1000; ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *drm = &vc4->base; ++ struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state); ++ unsigned int chan = vc4_crtc_state->assigned_channel; ++ bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE; ++ u32 disp_ctrl1; ++ int idx; + -+ if (mode->flags & DRM_MODE_FLAG_DBLCLK) -+ clock = clock * 2; ++ WARN_ON_ONCE(vc4->gen != VC4_GEN_6); ++ ++ if (!drm_dev_enter(drm, &idx)) ++ return -ENODEV; ++ ++ HVS_WRITE(SCALER6_DISPX_CTRL0(chan), SCALER6(DISPX_CTRL0_RESET)); + -+ if (fmt == VC4_HDMI_OUTPUT_YUV422) -+ bpc = 8; ++ disp_ctrl1 = HVS_READ(SCALER6_DISPX_CTRL1(chan)); ++ disp_ctrl1 &= ~SCALER6(DISPX_CTRL1_INTLACE); ++ HVS_WRITE(SCALER6_DISPX_CTRL1(chan), ++ disp_ctrl1 | (interlace ? SCALER6(DISPX_CTRL1_INTLACE) : 0)); ++ ++ HVS_WRITE(SCALER6_DISPX_CTRL0(chan), ++ SCALER6(DISPX_CTRL0_ENB) | ++ VC4_SET_FIELD6(mode->hdisplay - 1, ++ DISPX_CTRL0_FWIDTH) | ++ (oneshot ? SCALER6(DISPX_CTRL0_ONESHOT) : 0) | ++ VC4_SET_FIELD6(mode->vdisplay - 1, ++ DISPX_CTRL0_LINES)); + -+ return clock * bpc / 8; ++ drm_dev_exit(idx); ++ ++ return 0; +} + -+static int -+vc4_hdmi_encoder_compute_clock(const struct vc4_hdmi *vc4_hdmi, -+ struct vc4_hdmi_connector_state *vc4_state, -+ const struct drm_display_mode *mode, -+ unsigned int bpc, unsigned int fmt) ++static void __vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan) +{ -+ unsigned long long clock; ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *drm = &vc4->base; ++ int idx; + -+ clock = vc4_hdmi_encoder_compute_mode_clock(mode, bpc, fmt); -+ if (vc4_hdmi_encoder_clock_valid(vc4_hdmi, clock) != MODE_OK) -+ return -EINVAL; ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_5); ++ ++ if (!drm_dev_enter(drm, &idx)) ++ return; ++ ++ if (!(HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_ENABLE)) ++ goto out; + -+ vc4_state->pixel_rate = clock; ++ HVS_WRITE(SCALER_DISPCTRLX(chan), SCALER_DISPCTRLX_RESET); ++ HVS_WRITE(SCALER_DISPCTRLX(chan), 0); + -+ return 0; ++ /* Once we leave, the scaler should be disabled and its fifo empty. */ ++ WARN_ON_ONCE(HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_RESET); ++ ++ WARN_ON_ONCE(VC4_GET_FIELD(HVS_READ(SCALER_DISPSTATX(chan)), ++ SCALER_DISPSTATX_MODE) != ++ SCALER_DISPSTATX_MODE_DISABLED); ++ ++out: ++ drm_dev_exit(idx); +} + -+static int -+vc4_hdmi_encoder_compute_format(const struct vc4_hdmi *vc4_hdmi, -+ struct vc4_hdmi_connector_state *vc4_state, -+ const struct drm_display_mode *mode, -+ unsigned int bpc) -+{ -+ struct drm_device *dev = vc4_hdmi->connector.dev; -+ const struct drm_connector *connector = &vc4_hdmi->connector; -+ const struct drm_display_info *info = &connector->display_info; -+ unsigned int format; ++static void __vc6_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan) ++{ ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *drm = &vc4->base; ++ int idx; + -+ drm_dbg(dev, "Trying with an RGB output\n"); ++ WARN_ON_ONCE(vc4->gen != VC4_GEN_6); + -+ format = VC4_HDMI_OUTPUT_RGB; -+ if (vc4_hdmi_sink_supports_format_bpc(vc4_hdmi, info, mode, format, bpc)) { -+ int ret; ++ if (!drm_dev_enter(drm, &idx)) ++ return; + -+ ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state, -+ mode, bpc, format); -+ if (!ret) { -+ vc4_state->output_format = format; -+ return 0; -+ } -+ } ++ if (!(HVS_READ(SCALER6_DISPX_CTRL0(chan)) & SCALER6(DISPX_CTRL0_ENB))) ++ goto out; + -+ drm_dbg(dev, "Failed, Trying with an YUV422 output\n"); ++ HVS_WRITE(SCALER6_DISPX_CTRL0(chan), ++ HVS_READ(SCALER6_DISPX_CTRL0(chan)) | SCALER6(DISPX_CTRL0_RESET)); + -+ format = VC4_HDMI_OUTPUT_YUV422; -+ if (vc4_hdmi_sink_supports_format_bpc(vc4_hdmi, info, mode, format, bpc)) { -+ int ret; ++ HVS_WRITE(SCALER6_DISPX_CTRL0(chan), ++ HVS_READ(SCALER6_DISPX_CTRL0(chan)) & ~SCALER6(DISPX_CTRL0_ENB)); + -+ ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state, -+ mode, bpc, format); -+ if (!ret) { -+ vc4_state->output_format = format; -+ return 0; -+ } -+ } ++ WARN_ON_ONCE(VC4_GET_FIELD6(HVS_READ(SCALER6_DISPX_STATUS(chan)), ++ DISPX_STATUS_MODE) != ++ SCALER6(DISPX_STATUS_MODE_DISABLED)); + -+ drm_dbg(dev, "Failed. No Format Supported for that bpc count.\n"); ++out: ++ drm_dev_exit(idx); ++} + -+ return -EINVAL; - } - --static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) -+static int -+vc4_hdmi_encoder_compute_config(const struct vc4_hdmi *vc4_hdmi, -+ struct vc4_hdmi_connector_state *vc4_state, -+ const struct drm_display_mode *mode) - { -+ struct drm_device *dev = vc4_hdmi->connector.dev; -+ struct drm_connector_state *conn_state = &vc4_state->base; -+ unsigned int max_bpc = clamp_t(unsigned int, conn_state->max_bpc, 8, 12); -+ unsigned int bpc; -+ int ret; ++void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan) ++{ ++ struct vc4_dev *vc4 = hvs->vc4; + -+ for (bpc = max_bpc; bpc >= 8; bpc -= 2) { -+ drm_dbg(dev, "Trying with a %d bpc output\n", bpc); ++ if (vc4->gen >= VC4_GEN_6) ++ __vc6_hvs_stop_channel(hvs, chan); ++ else ++ __vc4_hvs_stop_channel(hvs, chan); ++} + -+ ret = vc4_hdmi_encoder_compute_format(vc4_hdmi, vc4_state, -+ mode, bpc); -+ if (ret) -+ continue; ++static int vc4_hvs_gamma_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 drm_connector_state *conn_state; ++ struct drm_connector *connector; ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ if (vc4->gen == VC4_GEN_4) ++ return 0; + -+ vc4_state->output_bpc = bpc; ++ if (!crtc_state->color_mgmt_changed) ++ return 0; + -+ drm_dbg(dev, -+ "Mode %ux%u @ %uHz: Found configuration: bpc: %u, fmt: %s, clock: %llu\n", -+ mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode), -+ vc4_state->output_bpc, -+ vc4_hdmi_output_fmt_str(vc4_state->output_format), -+ vc4_state->pixel_rate); ++ if (crtc_state->gamma_lut) { ++ unsigned int len = drm_color_lut_size(crtc_state->gamma_lut); + -+ break; ++ if (len != crtc->gamma_size) { ++ DRM_DEBUG_KMS("Invalid LUT size; got %u, expected %u\n", ++ len, crtc->gamma_size); ++ return -EINVAL; ++ } + } + -+ return ret; - } - - #define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL -@@ -794,10 +1712,12 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder, - 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; -+ int ret; - - if (vc4_hdmi->variant->unsupported_odd_h_timings && - !(mode->flags & DRM_MODE_FLAG_DBLCLK) && -@@ -819,11 +1739,9 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder, - pixel_rate = mode->clock * 1000; - } - -- if (mode->flags & DRM_MODE_FLAG_DBLCLK) -- pixel_rate = pixel_rate * 2; -- -- if (pixel_rate > vc4_hdmi->variant->max_pixel_clock) -- return -EINVAL; -+ ret = vc4_hdmi_encoder_compute_config(vc4_hdmi, vc4_state, mode); -+ if (ret) -+ return ret; - - return 0; - } -@@ -840,19 +1758,48 @@ vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder, - (mode->hsync_end % 2) || (mode->htotal % 2))) - return MODE_H_ILLEGAL; - -- if ((mode->clock * 1000) > vc4_hdmi->variant->max_pixel_clock) -- return MODE_CLOCK_HIGH; -- -- return MODE_OK; -+ return vc4_hdmi_encoder_clock_valid(vc4_hdmi, mode->clock * 1000); - } - - static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = { - .atomic_check = vc4_hdmi_encoder_atomic_check, -+ .atomic_mode_set = vc4_hdmi_encoder_atomic_mode_set, - .mode_valid = vc4_hdmi_encoder_mode_valid, -- .disable = vc4_hdmi_encoder_disable, -- .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. -+ */ ++ connector = vc4_get_crtc_connector(crtc, crtc_state); ++ if (!connector) ++ return -EINVAL; ++ ++ if (!(connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)) ++ return 0; ++ ++ conn_state = drm_atomic_get_connector_state(state, connector); ++ if (!conn_state) ++ return -EINVAL; + -+ return 163682864; ++ crtc_state->mode_changed = true; ++ return 0; +} + -+static u32 vc5_hdmi_calc_hsm_clock(struct vc4_hdmi *vc4_hdmi, unsigned long pixel_rate) ++int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) +{ -+ /* -+ * 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. ++ 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 vc4_hvs_dlist_allocation *alloc; ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct drm_plane *plane; ++ const struct drm_plane_state *plane_state; ++ u32 dlist_count = 0; ++ u32 lbm_count = 0; ++ ++ /* The pixelvalve can only feed one encoder (and encoders are ++ * 1:1 with connectors.) + */ ++ if (hweight32(crtc_state->connector_mask) > 1) ++ return -EINVAL; ++ ++ drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) { ++ const struct vc4_plane_state *vc4_plane_state = ++ to_vc4_plane_state(plane_state); ++ u32 plane_dlist_count = vc4_plane_dlist_size(plane_state); ++ ++ drm_dbg_driver(dev, "CRTC:%d:%s Found PLANE:%d:%s with DLIST size: %u\n", ++ crtc->base.id, crtc->name, ++ plane->base.id, plane->name, ++ plane_dlist_count); ++ ++ dlist_count += plane_dlist_count; ++ lbm_count += vc4_plane_state->lbm_size; ++ } ++ ++ dlist_count++; /* Account for SCALER_CTL0_END. */ + -+ return max_t(unsigned long, HSM_MIN_CLOCK_FREQ, (pixel_rate / 100) * 101); ++ drm_dbg_driver(dev, "CRTC:%d:%s Allocating DLIST block with size: %u\n", ++ crtc->base.id, crtc->name, dlist_count); ++ ++ alloc = vc4_hvs_alloc_dlist_entry(vc4->hvs, vc4_state->assigned_channel, dlist_count); ++ if (IS_ERR(alloc)) ++ return PTR_ERR(alloc); ++ ++ vc4_state->mm = alloc; ++ ++ /* FIXME: Check total lbm allocation here */ ++ ++ return vc4_hvs_gamma_check(crtc, state); +} + - static u32 vc4_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask) - { - int i; -@@ -877,33 +1824,49 @@ static u32 vc5_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask) - return channel_map; - } - -+static bool vc5_hdmi_hp_detect(struct vc4_hdmi *vc4_hdmi) ++static void vc4_hvs_install_dlist(struct drm_crtc *crtc) +{ -+ unsigned long flags; -+ u32 hotplug; ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_hvs *hvs = vc4->hvs; ++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); ++ int idx; + -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ hotplug = HDMI_READ(HDMI_HOTPLUG); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ if (!drm_dev_enter(dev, &idx)) ++ return; + -+ return !!(hotplug & VC4_HDMI_HOTPLUG_CONNECTED); -+} ++ WARN_ON(!vc4_state->mm); ++ vc4_state->mm->dlist_programmed = true; + - /* 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 flags; - unsigned long n, m; ++ if (vc4->gen >= VC4_GEN_6) ++ HVS_WRITE(SCALER6_DISPX_LPTRS(vc4_state->assigned_channel), ++ VC4_SET_FIELD6(vc4_state->mm->mm_node.start, ++ DISPX_LPTRS_HEADE)); ++ else ++ HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel), ++ vc4_state->mm->mm_node.start); -- 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 >> - VC4_HD_MAI_SMP_M_SHIFT) + 1, - &n, &m); + drm_dev_exit(idx); + } +@@ -510,8 +1343,10 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc) + spin_unlock_irqrestore(&dev->event_lock, flags); + } -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - HDMI_WRITE(HDMI_MAI_SMP, - VC4_SET_FIELD(n, VC4_HD_MAI_SMP_N) | - VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M)); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ WARN_ON(!vc4_state->mm); ++ + spin_lock_irqsave(&vc4_crtc->irq_lock, flags); +- vc4_crtc->current_dlist = vc4_state->mm.start; ++ vc4_crtc->current_dlist = vc4_state->mm->mm_node.start; + spin_unlock_irqrestore(&vc4_crtc->irq_lock, flags); } --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; -+ const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; - u32 n, cts; - u64 tmp; +@@ -538,7 +1373,11 @@ void vc4_hvs_atomic_enable(struct drm_crtc *crtc, -+ lockdep_assert_held(&vc4_hdmi->mutex); -+ lockdep_assert_held(&vc4_hdmi->hw_lock); + vc4_hvs_install_dlist(crtc); + vc4_hvs_update_dlist(crtc); +- vc4_hvs_init_channel(vc4->hvs, crtc, mode, oneshot); + - n = 128 * samplerate / 1000; - tmp = (u64)(mode->clock * 1000) * n; - do_div(tmp, 128 * samplerate); -@@ -929,36 +1892,48 @@ static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai) - return snd_soc_card_get_drvdata(card); ++ if (vc4->gen >= VC4_GEN_6) ++ vc6_hvs_init_channel(vc4->hvs, crtc, mode, oneshot); ++ else ++ vc4_hvs_init_channel(vc4->hvs, crtc, mode, oneshot); } --static int vc4_hdmi_audio_startup(struct snd_pcm_substream *substream, -- struct snd_soc_dai *dai) -+static bool vc4_hdmi_audio_can_stream(struct vc4_hdmi *vc4_hdmi) - { -- struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai); -- 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; -+ lockdep_assert_held(&vc4_hdmi->mutex); - - /* -- * If the HDMI encoder hasn't probed, or the encoder is -- * currently in DVI mode, treat the codec dai as missing. -+ * If the encoder is currently in DVI mode, treat the codec DAI -+ * as missing. - */ -- if (!encoder->crtc || !(HDMI_READ(HDMI_RAM_PACKET_CONFIG) & -- VC4_HDMI_RAM_PACKET_ENABLE)) -- return -ENODEV; -+ if (!vc4_hdmi->encoder.hdmi_monitor) -+ return false; + void vc4_hvs_atomic_disable(struct drm_crtc *crtc, +@@ -567,13 +1406,17 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, + struct drm_plane *plane; + struct vc4_plane_state *vc4_plane_state; + bool debug_dump_regs = false; +- bool enable_bg_fill = false; +- u32 __iomem *dlist_start = vc4->hvs->dlist + vc4_state->mm.start; +- u32 __iomem *dlist_next = dlist_start; ++ bool enable_bg_fill = true; ++ u32 __iomem *dlist_start, *dlist_next; ++ unsigned long irqflags; + unsigned int zpos = 0; ++ u32 lbm_offset = 0; ++ u32 lbm_size = 0; + bool found = false; + int idx; -- ret = snd_pcm_hw_constraint_eld(substream->runtime, connector->eld); -- if (ret) -- return ret; -- -- return 0; -+ return true; - } ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_6); ++ + if (!drm_dev_enter(dev, &idx)) { + vc4_crtc_send_vblank(crtc); + return; +@@ -587,6 +1430,38 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, + vc4_hvs_dump_state(hvs); + } --static int vc4_hdmi_audio_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) -+static int vc4_hdmi_audio_startup(struct device *dev, void *data) - { -+ struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); -+ unsigned long flags; ++ drm_atomic_crtc_for_each_plane(plane, crtc) { ++ vc4_plane_state = to_vc4_plane_state(plane->state); ++ lbm_size += vc4_plane_state->lbm_size; ++ } ++ ++ if (drm_mm_node_allocated(&vc4_crtc->lbm)) { ++ spin_lock_irqsave(&vc4_crtc->irq_lock, irqflags); ++ drm_mm_remove_node(&vc4_crtc->lbm); ++ spin_unlock_irqrestore(&vc4_crtc->irq_lock, irqflags); ++ } ++ ++ if (lbm_size) { ++ int ret; + -+ mutex_lock(&vc4_hdmi->mutex); ++ spin_lock_irqsave(&vc4_crtc->irq_lock, irqflags); ++ ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, ++ &vc4_crtc->lbm, ++ lbm_size, 1, ++ 0, 0); ++ spin_unlock_irqrestore(&vc4_crtc->irq_lock, irqflags); + -+ if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) { -+ mutex_unlock(&vc4_hdmi->mutex); -+ return -ENODEV; ++ if (ret) { ++ pr_err("Failed to allocate LBM ret %d\n", ret); ++ return; ++ } + } + -+ vc4_hdmi->audio.streaming = true; ++ lbm_offset = vc4_crtc->lbm.start; + -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ 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); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ dlist_start = vc4->hvs->dlist + vc4_state->mm->mm_node.start; ++ dlist_next = dlist_start; + -+ if (vc4_hdmi->variant->phy_rng_enable) -+ vc4_hdmi->variant->phy_rng_enable(vc4_hdmi); + /* Copy all the active planes' dlist contents to the hardware dlist. */ + do { + found = false; +@@ -595,6 +1470,8 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, + if (plane->state->normalized_zpos != zpos) + continue; + ++ vc4_plane_state = to_vc4_plane_state(plane->state); + -+ mutex_unlock(&vc4_hdmi->mutex); + /* Is this the first active plane? */ + if (dlist_next == dlist_start) { + /* We need to enable background fill when a plane +@@ -605,10 +1482,15 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, + * already needs it or all planes on top blend from + * the first or a lower plane. + */ +- vc4_plane_state = to_vc4_plane_state(plane->state); + enable_bg_fill = vc4_plane_state->needs_bg_fill; + } + ++ if (vc4_plane_state->lbm_size) { ++ vc4_plane_state->dlistvc4_plane_state->lbm_offset = ++ lbm_offset; ++ lbm_offset += vc4_plane_state->lbm_size; ++ } ++ + dlist_next += vc4_plane_write_dlist(plane, dlist_next); + + found = true; +@@ -620,15 +1502,29 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, + writel(SCALER_CTL0_END, dlist_next); + dlist_next++; + +- WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm.size); ++ WARN_ON(!vc4_state->mm); ++ WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm->mm_node.size); + +- if (enable_bg_fill) ++ if (vc4->gen >= VC4_GEN_6) { + /* This sets a black background color fill, as is the case + * with other DRM drivers. + */ ++ if (enable_bg_fill) ++ HVS_WRITE(SCALER6_DISPX_CTRL1(channel), ++ HVS_READ(SCALER6_DISPX_CTRL1(channel)) | ++ SCALER6(DISPX_CTRL1_BGENB)); ++ else ++ HVS_WRITE(SCALER6_DISPX_CTRL1(channel), ++ HVS_READ(SCALER6_DISPX_CTRL1(channel)) & ++ ~SCALER6(DISPX_CTRL1_BGENB)); ++ } else { ++ /* we can actually run with a lower core clock when background ++ * fill is enabled on VC4_GEN_5 so leave it enabled always. ++ */ + HVS_WRITE(SCALER_DISPBKGNDX(channel), + HVS_READ(SCALER_DISPBKGNDX(channel)) | + SCALER_DISPBKGND_FILL); ++ } + + /* Only update DISPLIST if the CRTC was already running and is not + * being disabled. +@@ -645,15 +1541,28 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, + if (crtc->state->color_mgmt_changed) { + u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(channel)); + ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_5); + - return 0; - } + if (crtc->state->gamma_lut) { +- vc4_hvs_update_gamma_lut(hvs, vc4_crtc); +- dispbkgndx |= SCALER_DISPBKGND_GAMMA; ++ if (vc4->gen == VC4_GEN_4) { ++ vc4_hvs_update_gamma_lut(hvs, vc4_crtc); ++ dispbkgndx |= SCALER_DISPBKGND_GAMMA; ++ } else { ++ vc5_hvs_update_gamma_lut(hvs, vc4_crtc); ++ } + } else { + /* Unsetting DISPBKGND_GAMMA skips the gamma lut step + * in hardware, which is the same as a linear lut that + * DRM expects us to use in absence of a user lut. ++ * ++ * Do NOT change state dynamically for hvs5 as it ++ * inserts a delay in the pipeline that will cause ++ * stalls if enabled/disabled whilst running. The other ++ * should already be disabling/enabling the pipeline ++ * when gamma changes. + */ +- dispbkgndx &= ~SCALER_DISPBKGND_GAMMA; ++ if (vc4->gen == VC4_GEN_4) ++ dispbkgndx &= ~SCALER_DISPBKGND_GAMMA; + } + HVS_WRITE(SCALER_DISPBKGNDX(channel), dispbkgndx); + } +@@ -668,16 +1577,20 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, -@@ -966,60 +1941,133 @@ static void vc4_hdmi_audio_reset(struct vc4_hdmi *vc4_hdmi) + void vc4_hvs_mask_underrun(struct vc4_hvs *hvs, int channel) { - struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; - struct device *dev = &vc4_hdmi->pdev->dev; -+ unsigned long flags; - int ret; +- struct drm_device *drm = &hvs->vc4->base; ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *drm = &vc4->base; + u32 dispctrl; + int idx; -+ lockdep_assert_held(&vc4_hdmi->mutex); ++ WARN_ON(vc4->gen > VC4_GEN_5); + - 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); + if (!drm_dev_enter(drm, &idx)) + return; -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ - HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_RESET); - HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_ERRORF); - HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_FLUSH); -+ -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); - } + dispctrl = HVS_READ(SCALER_DISPCTRL); +- dispctrl &= ~(hvs->vc4->is_vc5 ? SCALER5_DISPCTRL_DSPEISLUR(channel) : +- SCALER_DISPCTRL_DSPEISLUR(channel)); ++ dispctrl &= ~((vc4->gen == VC4_GEN_5) ? ++ SCALER5_DISPCTRL_DSPEISLUR(channel) : ++ SCALER_DISPCTRL_DSPEISLUR(channel)); + + HVS_WRITE(SCALER_DISPCTRL, dispctrl); --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) +@@ -686,16 +1599,20 @@ void vc4_hvs_mask_underrun(struct vc4_hvs *hvs, int channel) + + void vc4_hvs_unmask_underrun(struct vc4_hvs *hvs, int channel) { -- struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai); -+ struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); -+ unsigned long flags; +- struct drm_device *drm = &hvs->vc4->base; ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *drm = &vc4->base; + u32 dispctrl; + int idx; -- if (substream != vc4_hdmi->audio.substream) -- return; -+ mutex_lock(&vc4_hdmi->mutex); ++ WARN_ON(vc4->gen > VC4_GEN_5); + -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + if (!drm_dev_enter(drm, &idx)) + return; -+ HDMI_WRITE(HDMI_MAI_CTL, -+ VC4_HD_MAI_CTL_DLATE | -+ VC4_HD_MAI_CTL_ERRORE | -+ VC4_HD_MAI_CTL_ERRORF); + dispctrl = HVS_READ(SCALER_DISPCTRL); +- dispctrl |= (hvs->vc4->is_vc5 ? SCALER5_DISPCTRL_DSPEISLUR(channel) : +- SCALER_DISPCTRL_DSPEISLUR(channel)); ++ dispctrl |= ((vc4->gen == VC4_GEN_5) ? ++ SCALER5_DISPCTRL_DSPEISLUR(channel) : ++ SCALER_DISPCTRL_DSPEISLUR(channel)); + + HVS_WRITE(SCALER_DISPSTAT, + SCALER_DISPSTAT_EUFLOW(channel)); +@@ -723,6 +1640,8 @@ static irqreturn_t vc4_hvs_irq_handler(int irq, void *data) + u32 status; + u32 dspeislur; + ++ WARN_ON(vc4->gen > VC4_GEN_5); + -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + /* + * NOTE: We don't need to protect the register access using + * drm_dev_enter() there because the interrupt handler lifetime +@@ -738,24 +1657,54 @@ static irqreturn_t vc4_hvs_irq_handler(int irq, void *data) + control = HVS_READ(SCALER_DISPCTRL); + + for (channel = 0; channel < SCALER_CHANNELS_COUNT; channel++) { +- dspeislur = vc4->is_vc5 ? SCALER5_DISPCTRL_DSPEISLUR(channel) : +- SCALER_DISPCTRL_DSPEISLUR(channel); ++ dspeislur = (vc4->gen == VC4_GEN_5) ? ++ SCALER5_DISPCTRL_DSPEISLUR(channel) : ++ SCALER_DISPCTRL_DSPEISLUR(channel); ++ + /* Interrupt masking is not always honored, so check it here. */ + if (status & SCALER_DISPSTAT_EUFLOW(channel) && + control & dspeislur) { + vc4_hvs_mask_underrun(hvs, channel); + vc4_hvs_report_underrun(dev); + +- irqret = IRQ_HANDLED; +- } ++ irqret = IRQ_HANDLED; ++ } ++ ++ if (status & SCALER_DISPSTAT_EOF(channel)) { ++ vc4_hvs_schedule_dlist_sweep(hvs, channel); ++ irqret = IRQ_HANDLED; ++ } ++ } + -+ if (vc4_hdmi->variant->phy_rng_disable) -+ vc4_hdmi->variant->phy_rng_disable(vc4_hdmi); ++ /* Clear every per-channel interrupt flag. */ ++ HVS_WRITE(SCALER_DISPSTAT, SCALER_DISPSTAT_IRQMASK(0) | ++ SCALER_DISPSTAT_IRQMASK(1) | ++ SCALER_DISPSTAT_IRQMASK(2)); + -+ vc4_hdmi->audio.streaming = false; - vc4_hdmi_audio_reset(vc4_hdmi); - -- vc4_hdmi->audio.substream = NULL; -+ mutex_unlock(&vc4_hdmi->mutex); ++ return irqret; +} + -+static int sample_rate_to_mai_fmt(int samplerate) ++static irqreturn_t vc6_hvs_eof_irq_handler(int irq, void *data) +{ -+ 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; -+ } - } ++ struct drm_device *dev = data; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_hvs *hvs = vc4->hvs; ++ unsigned int i; ++ ++ WARN_ON(vc4->gen < VC4_GEN_6); ++ ++ for (i = 0; i < HVS_NUM_CHANNELS; i++) { ++ if (!hvs->eof_irqi.enabled) ++ continue; ++ ++ if (hvs->eof_irqi.desc != irq) ++ continue; ++ ++ vc4_hvs_schedule_dlist_sweep(hvs, i); ++ return IRQ_HANDLED; + } - /* 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; -+ unsigned long flags; - u32 audio_packet_config, channel_mask; - u32 channel_map; +- /* Clear every per-channel interrupt flag. */ +- HVS_WRITE(SCALER_DISPSTAT, SCALER_DISPSTAT_IRQMASK(0) | +- SCALER_DISPSTAT_IRQMASK(1) | +- SCALER_DISPSTAT_IRQMASK(2)); - -- if (substream != vc4_hdmi->audio.substream) -- return -EINVAL; -+ u32 mai_audio_format; -+ u32 mai_sample_rate; +- return irqret; ++ return IRQ_NONE; + } - dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__, -- params_rate(params), params_width(params), -- params_channels(params)); -+ sample_rate, params->sample_width, channels); - -- vc4_hdmi->audio.channels = params_channels(params); -- vc4_hdmi->audio.samplerate = params_rate(params); -+ mutex_lock(&vc4_hdmi->mutex); - -- 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_audio_can_stream(vc4_hdmi)) { -+ mutex_unlock(&vc4_hdmi->mutex); -+ return -EINVAL; -+ } + int vc4_hvs_debugfs_init(struct drm_minor *minor) +@@ -764,136 +1713,153 @@ int vc4_hvs_debugfs_init(struct drm_minor *minor) + struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_hvs *hvs = vc4->hvs; -- vc4_hdmi_audio_set_mai_clock(vc4_hdmi); -+ vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate); ++ if (vc4->firmware_kms) ++ return 0; + -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ HDMI_WRITE(HDMI_MAI_CTL, -+ VC4_SET_FIELD(channels, VC4_HD_MAI_CTL_CHNUM) | -+ VC4_HD_MAI_CTL_WHOLSMP | -+ VC4_HD_MAI_CTL_CHALIGN | -+ VC4_HD_MAI_CTL_ENABLE); -+ -+ mai_sample_rate = sample_rate_to_mai_fmt(sample_rate); -+ if (params->iec.status0 & 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 = -@@ -1027,124 +2075,39 @@ static int vc4_hdmi_audio_hw_params(struct snd_pcm_substream *substream, - 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)); + if (!vc4->hvs) + return -ENODEV; - 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_audio_infoframe(encoder); -- -- return 0; --} +- if (!vc4->is_vc5) ++ if (vc4->gen == VC4_GEN_4) { + debugfs_create_bool("hvs_load_tracker", S_IRUGO | S_IWUSR, + minor->debugfs_root, + &vc4->load_tracker_enabled); --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_WHOLSMP | -- VC4_HD_MAI_CTL_CHALIGN | -- 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); -+ vc4_hdmi_set_n_cts(vc4_hdmi, sample_rate); +- drm_debugfs_add_file(drm, "hvs_dlists", vc4_hvs_debugfs_dlist, NULL); ++ drm_debugfs_add_file(drm, "hvs_gamma", vc5_hvs_debugfs_gamma, ++ NULL); ++ } ++ ++ if (vc4->gen >= VC4_GEN_6) ++ drm_debugfs_add_file(drm, "hvs_dlists", vc6_hvs_debugfs_dlist, NULL); ++ else ++ drm_debugfs_add_file(drm, "hvs_dlists", vc4_hvs_debugfs_dlist, NULL); -- if (vc4_hdmi->variant->phy_rng_disable) -- vc4_hdmi->variant->phy_rng_disable(vc4_hdmi); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + drm_debugfs_add_file(drm, "hvs_underrun", vc4_hvs_debugfs_underrun, NULL); -- 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(&vc4_hdmi->audio.infoframe, ¶ms->cea, sizeof(params->cea)); -+ if (vc4_hdmi->output_enabled) -+ vc4_hdmi_set_audio_infoframe(encoder); - -- memcpy(ucontrol->value.bytes.data, connector->eld, -- sizeof(connector->eld)); -+ mutex_unlock(&vc4_hdmi->mutex); ++ drm_debugfs_add_file(drm, "hvs_dlist_allocs", vc4_hvs_debugfs_dlist_allocs, NULL); ++ + vc4_debugfs_add_regset32(drm, "hvs_regs", &hvs->regset); 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"), - }; -@@ -1154,39 +2117,15 @@ static const struct snd_soc_dapm_route vc4_hdmi_audio_routes = { - }; - - 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, -- .num_dapm_routes = ARRAY_SIZE(vc4_hdmi_audio_routes), -- .idle_bias_on = 1, -- .use_pmdown_time = 1, -- .endianness = 1, -- .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, -- }, -+ .name = "vc4-hdmi-codec-dai-component", -+ .dapm_widgets = vc4_hdmi_audio_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(vc4_hdmi_audio_widgets), -+ .dapm_routes = vc4_hdmi_audio_routes, -+ .num_dapm_routes = ARRAY_SIZE(vc4_hdmi_audio_routes), -+ .idle_bias_on = 1, -+ .use_pmdown_time = 1, -+ .endianness = 1, -+ .non_legacy_dai_naming = 1, - }; - - static const struct snd_soc_component_driver vc4_hdmi_audio_cpu_dai_comp = { -@@ -1215,7 +2154,6 @@ static struct snd_soc_dai_driver vc4_hdmi_audio_cpu_dai_drv = { - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, - }, -- .ops = &vc4_hdmi_audio_dai_ops, - }; +-struct vc4_hvs *__vc4_hvs_alloc(struct vc4_dev *vc4, struct platform_device *pdev) ++struct vc4_hvs *__vc4_hvs_alloc(struct vc4_dev *vc4, ++ void __iomem *regs, ++ struct platform_device *pdev) + { + struct drm_device *drm = &vc4->base; + struct vc4_hvs *hvs; ++ unsigned int dlist_start; ++ size_t dlist_size; ++ size_t lbm_size; - static const struct snd_dmaengine_pcm_config pcm_conf = { -@@ -1223,6 +2161,33 @@ static const struct snd_dmaengine_pcm_config pcm_conf = { - .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, - }; + hvs = drmm_kzalloc(drm, sizeof(*hvs), GFP_KERNEL); + if (!hvs) + return ERR_PTR(-ENOMEM); + hvs->vc4 = vc4; ++ hvs->regs = regs; + hvs->pdev = pdev; + + spin_lock_init(&hvs->mm_lock); + +- /* Set up the HVS display list memory manager. We never +- * overwrite the setup from the bootloader (just 128b out of +- * our 16K), since we don't want to scramble the screen when +- * transitioning from the firmware's boot setup to runtime. +- */ +- drm_mm_init(&hvs->dlist_mm, +- HVS_BOOTLOADER_DLIST_END, +- (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END); ++ INIT_LIST_HEAD(&hvs->stale_dlist_entries); ++ INIT_WORK(&hvs->free_dlist_work, vc4_hvs_dlist_free_work); ++ ++ switch (vc4->gen) { ++ case VC4_GEN_4: ++ case VC4_GEN_5: ++ /* Set up the HVS display list memory manager. We never ++ * overwrite the setup from the bootloader (just 128b ++ * out of our 16K), since we don't want to scramble the ++ * screen when transitioning from the firmware's boot ++ * setup to runtime. ++ */ ++ dlist_start = HVS_BOOTLOADER_DLIST_END; ++ dlist_size = (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END; ++ break; + -+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; ++ case VC4_GEN_6: ++ dlist_start = HVS_BOOTLOADER_DLIST_END; + -+ mutex_lock(&vc4_hdmi->mutex); -+ memcpy(buf, connector->eld, min(sizeof(connector->eld), len)); -+ mutex_unlock(&vc4_hdmi->mutex); ++ /* ++ * If we are running a test, it means that we can't ++ * access a register. Use a plausible size then. ++ */ ++ if (!kunit_get_current_test()) ++ dlist_size = HVS_READ(SCALER6(CXM_SIZE)); ++ else ++ dlist_size = 4096; + -+ return 0; -+} ++ break; + -+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, -+}; ++ default: ++ drm_err(drm, "Unknown VC4 generation: %d", vc4->gen); ++ return ERR_PTR(-ENODEV); ++ } + -+struct hdmi_codec_pdata vc4_hdmi_codec_pdata = { -+ .ops = &vc4_hdmi_codec_ops, -+ .max_i2s_channels = 8, -+ .i2s = 1, -+}; ++ drm_mm_init(&hvs->dlist_mm, dlist_start, dlist_size); + - static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) - { - const struct vc4_hdmi_register *mai_data = -@@ -1230,13 +2195,16 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) - 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; ++ hvs->dlist_mem_size = dlist_size; -- 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; - } + /* Set up the HVS LBM memory manager. We could have some more + * complicated data structure that allowed reuse of LBM areas + * between planes when they don't overlap on the screen, but + * for now we just allocate globally. + */ +- if (!vc4->is_vc5) +- /* 48k words of 2x12-bit pixels */ +- drm_mm_init(&hvs->lbm_mm, 0, 48 * 1024); +- else +- /* 60k words of 4x12-bit pixels */ +- drm_mm_init(&hvs->lbm_mm, 0, 60 * 1024); +- +- vc4->hvs = hvs; +- +- return hvs; +-} +- +-static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) +-{ +- struct platform_device *pdev = to_platform_device(dev); +- struct drm_device *drm = dev_get_drvdata(master); +- struct vc4_dev *vc4 = to_vc4_dev(drm); +- struct vc4_hvs *hvs = NULL; +- int ret; +- u32 dispctrl; +- u32 reg, top; +- +- hvs = __vc4_hvs_alloc(vc4, NULL); +- if (IS_ERR(hvs)) +- return PTR_ERR(hvs); + +- hvs->regs = vc4_ioremap_regs(pdev, 0); +- if (IS_ERR(hvs->regs)) +- return PTR_ERR(hvs->regs); ++ switch (vc4->gen) { ++ case VC4_GEN_4: ++ /* 48k words of 2x12-bit pixels */ ++ lbm_size = 48 * SZ_1K; ++ break; + +- hvs->regset.base = hvs->regs; +- hvs->regset.regs = hvs_regs; +- hvs->regset.nregs = ARRAY_SIZE(hvs_regs); ++ case VC4_GEN_5: ++ /* 60k words of 4x12-bit pixels */ ++ lbm_size = 60 * SZ_1K; ++ break; + +- if (vc4->is_vc5) { +- struct rpi_firmware *firmware; +- struct device_node *node; +- unsigned int max_rate; ++ case VC4_GEN_6: ++ /* ++ * If we are running a test, it means that we can't ++ * access a register. Use a plausible size then. ++ */ ++ lbm_size = 1024; ++ break; -@@ -1276,12 +2244,13 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) - return ret; - } +- node = rpi_firmware_find_node(); +- if (!node) +- return -EINVAL; ++ default: ++ drm_err(drm, "Unknown VC4 generation: %d", vc4->gen); ++ return ERR_PTR(-ENODEV); ++ } -- /* 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; -@@ -1294,9 +2263,9 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) - - 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); +- firmware = rpi_firmware_get(node); +- of_node_put(node); +- if (!firmware) +- return -EPROBE_DEFER; ++ drm_mm_init(&hvs->lbm_mm, 0, lbm_size); + +- hvs->core_clk = devm_clk_get(&pdev->dev, NULL); +- if (IS_ERR(hvs->core_clk)) { +- dev_err(&pdev->dev, "Couldn't get core clock\n"); +- return PTR_ERR(hvs->core_clk); +- } ++ if (vc4->gen >= VC4_GEN_6) { ++ ida_init(&hvs->upm_handles); - card->dai_link = dai_link; -@@ -1316,22 +2285,83 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) - snd_soc_card_set_drvdata(card, vc4_hdmi); - ret = devm_snd_soc_register_card(dev, card); - if (ret) -- dev_err(dev, "Could not register sound card: %d\n", ret); -+ dev_err_probe(dev, ret, "Could not register sound card.\n"); +- max_rate = rpi_firmware_clk_get_max_rate(firmware, +- RPI_FIRMWARE_CORE_CLK_ID); +- rpi_firmware_put(firmware); +- if (max_rate >= 550000000) +- hvs->vc5_hdmi_enable_hdmi_20 = true; ++ /* ++ * NOTE: On BCM2712, the size can also be read through ++ * the SCALER_UBM_SIZE register. We would need to do a ++ * register access though, which we can't do with kunit ++ * that also uses this function to create its mock ++ * device. ++ */ ++ drm_mm_init(&hvs->upm_mm, 0, 1024 * HVS_UBM_WORD_SIZE); ++ } - return ret; +- if (max_rate >= 600000000) +- hvs->vc5_hdmi_enable_4096by2160 = true; - } +- hvs->max_core_rate = max_rate; ++ vc4->hvs = hvs; -+static irqreturn_t vc4_hdmi_hpd_irq_thread(int irq, void *priv) -+{ -+ struct vc4_hdmi *vc4_hdmi = priv; -+ struct drm_connector *connector = &vc4_hdmi->connector; -+ struct drm_device *dev = connector->dev; -+ -+ if (dev && dev->registered) -+ drm_connector_helper_hpd_irq_event(connector); -+ -+ return IRQ_HANDLED; +- ret = clk_prepare_enable(hvs->core_clk); +- if (ret) { +- dev_err(&pdev->dev, "Couldn't enable the core clock\n"); +- return ret; +- } +- } ++ return hvs; +} -+ -+static int vc4_hdmi_hotplug_init(struct vc4_hdmi *vc4_hdmi) + +- if (!vc4->is_vc5) +- hvs->dlist = hvs->regs + SCALER_DLIST_START; +- else +- hvs->dlist = hvs->regs + SCALER5_DLIST_START; ++static int vc4_hvs_hw_init(struct vc4_hvs *hvs) +{ -+ struct platform_device *pdev = vc4_hdmi->pdev; -+ struct drm_connector *connector = &vc4_hdmi->connector; -+ int ret; ++ struct vc4_dev *vc4 = hvs->vc4; ++ u32 dispctrl, reg; + +- /* Upload filter kernels. We only have the one for now, so we +- * keep it around for the lifetime of the driver. +- */ +- ret = vc4_hvs_upload_linear_kernel(hvs, +- &hvs->mitchell_netravali_filter, +- mitchell_netravali_1_3_1_3_kernel); +- if (ret) +- return ret; ++ dispctrl = HVS_READ(SCALER_DISPCTRL); ++ dispctrl |= SCALER_DISPCTRL_ENABLE; ++ HVS_WRITE(SCALER_DISPCTRL, dispctrl); + + reg = HVS_READ(SCALER_DISPECTRL); + reg &= ~SCALER_DISPECTRL_DSP2_MUX_MASK; +@@ -916,13 +1882,11 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) + reg | VC4_SET_FIELD(3, SCALER_DISPDITHER_DSP5_MUX)); + + dispctrl = HVS_READ(SCALER_DISPCTRL); +- +- dispctrl |= SCALER_DISPCTRL_ENABLE; + dispctrl |= SCALER_DISPCTRL_DISPEIRQ(0) | + SCALER_DISPCTRL_DISPEIRQ(1) | + SCALER_DISPCTRL_DISPEIRQ(2); + +- if (!vc4->is_vc5) ++ if (vc4->gen == VC4_GEN_4) + dispctrl &= ~(SCALER_DISPCTRL_DMAEIRQ | + SCALER_DISPCTRL_SLVWREIRQ | + SCALER_DISPCTRL_SLVRDEIRQ | +@@ -951,6 +1915,17 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) + SCALER_DISPCTRL_SCLEIRQ); + + ++ /* Set AXI panic mode. ++ * VC4 panics when < 2 lines in FIFO. ++ * VC5 panics when less than 1 line in the FIFO. ++ */ ++ dispctrl &= ~(SCALER_DISPCTRL_PANIC0_MASK | ++ SCALER_DISPCTRL_PANIC1_MASK | ++ SCALER_DISPCTRL_PANIC2_MASK); ++ dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_PANIC0); ++ dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_PANIC1); ++ dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_PANIC2); ++ + /* Set AXI panic mode. + * VC4 panics when < 2 lines in FIFO. + * VC5 panics when less than 1 line in the FIFO. +@@ -964,9 +1939,160 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) + + HVS_WRITE(SCALER_DISPCTRL, dispctrl); + +- /* Recompute Composite Output Buffer (COB) allocations for the displays ++ return 0; ++} ++ ++#define CFC1_N_NL_CSC_CTRL(x) (0xa000 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C00(x) (0xa008 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C01(x) (0xa00c + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C02(x) (0xa010 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C03(x) (0xa014 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C04(x) (0xa018 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C10(x) (0xa01c + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C11(x) (0xa020 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C12(x) (0xa024 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C13(x) (0xa028 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C14(x) (0xa02c + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C20(x) (0xa030 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C21(x) (0xa034 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C22(x) (0xa038 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C23(x) (0xa03c + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C24(x) (0xa040 + ((x) * 0x3000)) ++ ++#define SCALER_PI_CMP_CSC_RED0(x) (0x200 + ((x) * 0x40)) ++#define SCALER_PI_CMP_CSC_RED1(x) (0x204 + ((x) * 0x40)) ++#define SCALER_PI_CMP_CSC_RED_CLAMP(x) (0x208 + ((x) * 0x40)) ++#define SCALER_PI_CMP_CSC_CFG(x) (0x20c + ((x) * 0x40)) ++#define SCALER_PI_CMP_CSC_GREEN0(x) (0x210 + ((x) * 0x40)) ++#define SCALER_PI_CMP_CSC_GREEN1(x) (0x214 + ((x) * 0x40)) ++#define SCALER_PI_CMP_CSC_GREEN_CLAMP(x) (0x218 + ((x) * 0x40)) ++#define SCALER_PI_CMP_CSC_BLUE0(x) (0x220 + ((x) * 0x40)) ++#define SCALER_PI_CMP_CSC_BLUE1(x) (0x224 + ((x) * 0x40)) ++#define SCALER_PI_CMP_CSC_BLUE_CLAMP(x) (0x228 + ((x) * 0x40)) ++ ++/* 4 S2.22 multiplication factors, and 1 S9.15 addititive element for each of 3 ++ * output components ++ */ ++struct vc6_csc_coeff_entry { ++ u32 csc35; ++}; ++ ++static const struct vc6_csc_coeff_entry csc_coeffs23 = { ++ DRM_COLOR_YCBCR_LIMITED_RANGE = { ++ DRM_COLOR_YCBCR_BT601 = { ++ .csc = { ++ { 0x004A8542, 0x0, 0x0066254A, 0x0, 0xFF908A0D }, ++ { 0x004A8542, 0xFFE6ED5D, 0xFFCBF856, 0x0, 0x0043C9A3 }, ++ { 0x004A8542, 0x00811A54, 0x0, 0x0, 0xFF759502 } ++ } ++ }, ++ DRM_COLOR_YCBCR_BT709 = { ++ .csc = { ++ { 0x004A8542, 0x0, 0x0072BC44, 0x0, 0xFF83F312 }, ++ { 0x004A8542, 0xFFF25A22, 0xFFDDE4D0, 0x0, 0x00267064 }, ++ { 0x004A8542, 0x00873197, 0x0, 0x0, 0xFF6F7DC0 } ++ } ++ }, ++ DRM_COLOR_YCBCR_BT2020 = { ++ .csc = { ++ { 0x004A8542, 0x0, 0x006B4A17, 0x0, 0xFF8B653F }, ++ { 0x004A8542, 0xFFF402D9, 0xFFDDE4D0, 0x0, 0x0024C7AE }, ++ { 0x004A8542, 0x008912CC, 0x0, 0x0, 0xFF6D9C8B } ++ } ++ } ++ }, ++ DRM_COLOR_YCBCR_FULL_RANGE = { ++ DRM_COLOR_YCBCR_BT601 = { ++ .csc = { ++ { 0x00400000, 0x0, 0x0059BA5E, 0x0, 0xFFA645A1 }, ++ { 0x00400000, 0xFFE9F9AC, 0xFFD24B97, 0x0, 0x0043BABB }, ++ { 0x00400000, 0x00716872, 0x0, 0x0, 0xFF8E978D } ++ } ++ }, ++ DRM_COLOR_YCBCR_BT709 = { ++ .csc = { ++ { 0x00400000, 0x0, 0x0064C985, 0x0, 0xFF9B367A }, ++ { 0x00400000, 0xFFF402E1, 0xFFE20A40, 0x0, 0x0029F2DE }, ++ { 0x00400000, 0x0076C226, 0x0, 0x0, 0xFF893DD9 } ++ } ++ }, ++ DRM_COLOR_YCBCR_BT2020 = { ++ .csc = { ++ { 0x00400000, 0x0, 0x005E3F14, 0x0, 0xFFA1C0EB }, ++ { 0x00400000, 0xFFF577F6, 0xFFDB580F, 0x0, 0x002F2FFA }, ++ { 0x00400000, 0x007868DB, 0x0, 0x0, 0xFF879724 } ++ } ++ } ++ } ++}; + -+ 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"); ++static int vc6_hvs_hw_init(struct vc4_hvs *hvs) ++{ ++ const struct vc6_csc_coeff_entry *coeffs; ++ unsigned int i; + -+ ret = request_threaded_irq(hpd_con, -+ NULL, -+ vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT, -+ "vc4 hdmi hpd connected", vc4_hdmi); -+ if (ret) -+ return ret; ++ HVS_WRITE6(CONTROL, ++ SCALER6_CONTROL_HVS_EN | ++ VC4_SET_FIELD(8, SCALER6_CONTROL_PF_LINES)| ++ VC4_SET_FIELD(15, SCALER6_CONTROL_MAX_REQS)); ++ ++ /* Set HVS arbiter priority to max */ ++ HVS_WRITE(SCALER6(PRI_MAP0), 0xffffffff); ++ HVS_WRITE(SCALER6(PRI_MAP1), 0xffffffff); + -+ 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; ++ if (hvs->vc4->step_d0) { ++ for (i = 0; i < 8; i++) { ++ HVS_WRITE(SCALER_PI_CMP_CSC_RED0(i), 0x1f002566); ++ HVS_WRITE(SCALER_PI_CMP_CSC_RED1(i), 0x3994); ++ HVS_WRITE(SCALER_PI_CMP_CSC_RED_CLAMP(i), 0xfff00000); ++ HVS_WRITE(SCALER_PI_CMP_CSC_CFG(i), 0x1); ++ HVS_WRITE(SCALER_PI_CMP_CSC_GREEN0(i), 0x18002566); ++ HVS_WRITE(SCALER_PI_CMP_CSC_GREEN1(i), 0xf927eee2); ++ HVS_WRITE(SCALER_PI_CMP_CSC_GREEN_CLAMP(i), 0xfff00000); ++ HVS_WRITE(SCALER_PI_CMP_CSC_BLUE0(i), 0x18002566); ++ HVS_WRITE(SCALER_PI_CMP_CSC_BLUE1(i), 0x43d80000); ++ HVS_WRITE(SCALER_PI_CMP_CSC_BLUE_CLAMP(i), 0xfff00000); + } ++ } else { ++ for (i = 0; i < 6; i++) { ++ coeffs = &csc_coeffsi / 3i % 3; + -+ connector->polled = DRM_CONNECTOR_POLL_HPD; -+ } ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C00(i), coeffs->csc00); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C01(i), coeffs->csc01); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C02(i), coeffs->csc02); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C03(i), coeffs->csc03); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C04(i), coeffs->csc04); + -+ return 0; -+} ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C10(i), coeffs->csc10); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C11(i), coeffs->csc11); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C12(i), coeffs->csc12); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C13(i), coeffs->csc13); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C14(i), coeffs->csc14); + -+static void vc4_hdmi_hotplug_exit(struct vc4_hdmi *vc4_hdmi) -+{ -+ struct platform_device *pdev = vc4_hdmi->pdev; ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C20(i), coeffs->csc20); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C21(i), coeffs->csc21); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C22(i), coeffs->csc22); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C23(i), coeffs->csc23); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C24(i), coeffs->csc24); + -+ 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); ++ HVS_WRITE(CFC1_N_NL_CSC_CTRL(i), BIT(15)); ++ } + } -+} -+ - #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; ++ return 0; +} + -+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 { -@@ -1345,12 +2375,27 @@ static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv) - return IRQ_HANDLED; - } - -+static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv) ++static int vc4_hvs_cob_init(struct vc4_hvs *hvs) +{ -+ struct vc4_hdmi *vc4_hdmi = priv; -+ irqreturn_t ret; ++ struct vc4_dev *vc4 = hvs->vc4; ++ u32 reg, top, base; + -+ 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); ++ /* ++ * Recompute Composite Output Buffer (COB) allocations for the ++ * displays + */ +- if (!vc4->is_vc5) { ++ switch (vc4->gen) { ++ case VC4_GEN_4: + /* The COB is 20736 pixels, or just over 10 lines at 2048 wide. + * The bottom 2048 pixels are full 32bpp RGBA (intended for the + * TXP composing RGBA to memory), whilst the remainder are only +@@ -990,7 +2116,9 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) + top = VC4_COB_SIZE; + reg |= (top - 1) << 16; + HVS_WRITE(SCALER_DISPBASE0, reg); +- } else { ++ break; + -+ return ret; -+} ++ case VC4_GEN_5: + /* The COB is 44416 pixels, or 10.8 lines at 4096 wide. + * The bottom 4096 pixels are full RGBA (intended for the TXP + * composing RGBA to memory), whilst the remainder are only +@@ -1016,13 +2144,182 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) + top = VC5_COB_SIZE; + reg |= top << 16; + HVS_WRITE(SCALER_DISPBASE0, reg); ++ break; + - static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1) - { - struct drm_device *dev = vc4_hdmi->connector.dev; - struct cec_msg *msg = &vc4_hdmi->cec_rx_msg; - unsigned int i; - -+ lockdep_assert_held(&vc4_hdmi->hw_lock); ++ case VC4_GEN_6: ++ #define VC6_COB_LINE_WIDTH 3840 ++ #define VC6_COB_NUM_LINES 4 ++ reg = 0; ++ top = 3840; + - msg->len = 1 + ((cntrl1 & VC4_HDMI_CEC_REC_WRD_CNT_MASK) >> - VC4_HDMI_CEC_REC_WRD_CNT_SHIFT); - -@@ -1369,83 +2414,208 @@ static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1) - } - } - -+static irqreturn_t vc4_cec_irq_handler_tx_bare_locked(struct vc4_hdmi *vc4_hdmi) -+{ -+ u32 cntrl1; ++ HVS_WRITE(SCALER6(DISP2_COB), ++ VC4_SET_FIELD(top, SCALER6_DISPX_COB_TOP) | ++ VC4_SET_FIELD(base, SCALER6_DISPX_COB_BASE)); + -+ lockdep_assert_held(&vc4_hdmi->hw_lock); ++ base = top + 16; ++ top += VC6_COB_LINE_WIDTH * VC6_COB_NUM_LINES; + -+ 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); ++ HVS_WRITE(SCALER6(DISP1_COB), ++ VC4_SET_FIELD(top, SCALER6_DISPX_COB_TOP) | ++ VC4_SET_FIELD(base, SCALER6_DISPX_COB_BASE)); + -+ return IRQ_WAKE_THREAD; -+} ++ base = top + 16; ++ top += VC6_COB_LINE_WIDTH * VC6_COB_NUM_LINES; + -+static irqreturn_t vc4_cec_irq_handler_tx_bare(int irq, void *priv) -+{ -+ struct vc4_hdmi *vc4_hdmi = priv; -+ irqreturn_t ret; ++ HVS_WRITE(SCALER6(DISP0_COB), ++ VC4_SET_FIELD(top, SCALER6_DISPX_COB_TOP) | ++ VC4_SET_FIELD(base, SCALER6_DISPX_COB_BASE)); ++ break; + -+ spin_lock(&vc4_hdmi->hw_lock); -+ ret = vc4_cec_irq_handler_tx_bare_locked(vc4_hdmi); -+ spin_unlock(&vc4_hdmi->hw_lock); ++ default: ++ return -EINVAL; ++ } + -+ return ret; ++ return 0; +} + -+static irqreturn_t vc4_cec_irq_handler_rx_bare_locked(struct vc4_hdmi *vc4_hdmi) ++static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) +{ -+ u32 cntrl1; ++ struct platform_device *pdev = to_platform_device(dev); ++ struct drm_device *drm = dev_get_drvdata(master); ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_hvs *hvs = NULL; ++ void __iomem *regs; ++ int ret; + -+ lockdep_assert_held(&vc4_hdmi->hw_lock); ++ regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(regs)) ++ return PTR_ERR(regs); ++ ++ hvs = __vc4_hvs_alloc(vc4, regs, pdev); ++ if (IS_ERR(hvs)) ++ return PTR_ERR(hvs); ++ ++ hvs->regset.base = hvs->regs; ++ ++ if (vc4->gen >= VC4_GEN_6 && vc4->step_d0) { ++ hvs->regset.regs = vc6_hvs_regs_d0; ++ hvs->regset.nregs = ARRAY_SIZE(vc6_hvs_regs_d0); ++ } else if (vc4->gen >= VC4_GEN_6) { ++ hvs->regset.regs = vc6_hvs_regs; ++ hvs->regset.nregs = ARRAY_SIZE(vc6_hvs_regs); ++ } else { ++ hvs->regset.regs = vc4_hvs_regs; ++ hvs->regset.nregs = ARRAY_SIZE(vc4_hvs_regs); ++ } ++ ++ if (vc4->gen >= VC4_GEN_5) { ++ struct rpi_firmware *firmware; ++ struct device_node *node; ++ unsigned int max_rate; + -+ 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; ++ node = rpi_firmware_find_node(); ++ if (!node) ++ return -EINVAL; + -+ HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1); ++ firmware = rpi_firmware_get(node); ++ of_node_put(node); ++ if (!firmware) ++ return -EPROBE_DEFER; + -+ return IRQ_WAKE_THREAD; -+} ++ hvs->core_clk = devm_clk_get(&pdev->dev, ++ (vc4->gen >= VC4_GEN_6) ? "core" : NULL); ++ if (IS_ERR(hvs->core_clk)) { ++ dev_err(&pdev->dev, "Couldn't get core clock\n"); ++ return PTR_ERR(hvs->core_clk); ++ } + -+static irqreturn_t vc4_cec_irq_handler_rx_bare(int irq, void *priv) -+{ -+ struct vc4_hdmi *vc4_hdmi = priv; -+ irqreturn_t ret; ++ hvs->disp_clk = devm_clk_get(&pdev->dev, ++ (vc4->gen >= VC4_GEN_6) ? "disp" : NULL); ++ if (IS_ERR(hvs->disp_clk)) { ++ dev_err(&pdev->dev, "Couldn't get disp clock\n"); ++ return PTR_ERR(hvs->disp_clk); ++ } + -+ spin_lock(&vc4_hdmi->hw_lock); -+ ret = vc4_cec_irq_handler_rx_bare_locked(vc4_hdmi); -+ spin_unlock(&vc4_hdmi->hw_lock); ++ max_rate = rpi_firmware_clk_get_max_rate(firmware, ++ RPI_FIRMWARE_CORE_CLK_ID); ++ rpi_firmware_put(firmware); ++ if (max_rate >= 550000000) ++ hvs->vc5_hdmi_enable_hdmi_20 = true; + -+ return ret; -+} ++ if (max_rate >= 600000000) ++ hvs->vc5_hdmi_enable_4096by2160 = true; + - 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); ++ hvs->max_core_rate = max_rate; + -+ spin_lock(&vc4_hdmi->hw_lock); - 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); -+ if (vc4_hdmi->cec_irq_was_rx) -+ ret = vc4_cec_irq_handler_rx_bare_locked(vc4_hdmi); -+ else -+ ret = vc4_cec_irq_handler_tx_bare_locked(vc4_hdmi); ++ ret = clk_prepare_enable(hvs->core_clk); ++ if (ret) { ++ dev_err(&pdev->dev, "Couldn't enable the core clock\n"); ++ return ret; ++ } + - HDMI_WRITE(HDMI_CEC_CPU_CLEAR, VC4_HDMI_CPU_CEC); -+ spin_unlock(&vc4_hdmi->hw_lock); - -- return IRQ_WAKE_THREAD; -+ 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); -+ unsigned long flags; -+ u32 val; -+ int ret; ++ ret = clk_prepare_enable(hvs->disp_clk); ++ if (ret) { ++ dev_err(&pdev->dev, "Couldn't enable the disp clock\n"); ++ return ret; ++ } ++ } + -+ /* -+ * NOTE: This function should really take vc4_hdmi->mutex, but doing so -+ * results in a reentrancy since cec_s_phys_addr_from_edid() called in -+ * .detect or .get_modes might call .adap_enable, which leads to this -+ * function being called with that mutex held. -+ * -+ * Concurrency is not an issue for the moment since we don't share any -+ * state with KMS, so we can ignore the lock for now, but we need to -+ * keep it in mind if we were to change that assumption. -+ */ ++ if (vc4->gen >= VC4_GEN_6) { ++ unsigned int i; + -+ ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev); -+ if (ret) -+ return ret; - -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); ++ for (i = 0; i < HVS_NUM_CHANNELS; i++) { ++ char irq_name16; ++ int irq; + -+ 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)); ++ snprintf(irq_name, sizeof(irq_name), "ch%u-eof", i); + -+ if (!vc4_hdmi->variant->external_irq_controller) - HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC); -- } else { ++ irq = platform_get_irq_byname(pdev, irq_name); ++ if (irq < 0) { ++ dev_err(&pdev->dev, ++ "Couldn't get %s interrupt: %d\n", ++ irq_name, irq); ++ return irq; ++ } + -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ ret = devm_request_irq(&pdev->dev, ++ irq, ++ vc6_hvs_eof_irq_handler, ++ IRQF_NO_AUTOEN, ++ dev_name(&pdev->dev), ++ drm); + -+ return 0; -+} ++ hvs->eof_irqi.desc = irq; ++ } + } + +- ret = devm_request_irq(dev, platform_get_irq(pdev, 0), +- vc4_hvs_irq_handler, 0, "vc4 hvs", drm); ++ if (vc4->gen >= VC4_GEN_5) ++ hvs->dlist = hvs->regs + SCALER5_DLIST_START; ++ else ++ hvs->dlist = hvs->regs + SCALER_DLIST_START; + -+static int vc4_hdmi_cec_disable(struct cec_adapter *adap) -+{ -+ struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); -+ unsigned long flags; ++ if (vc4->gen >= VC4_GEN_6) ++ ret = vc6_hvs_hw_init(hvs); ++ else ++ ret = vc4_hvs_hw_init(hvs); ++ if (ret) ++ return ret; + -+ /* -+ * NOTE: This function should really take vc4_hdmi->mutex, but doing so -+ * results in a reentrancy since cec_s_phys_addr_from_edid() called in -+ * .detect or .get_modes might call .adap_enable, which leads to this -+ * function being called with that mutex held. -+ * -+ * Concurrency is not an issue for the moment since we don't share any -+ * state with KMS, so we can ignore the lock for now, but we need to -+ * keep it in mind if we were to change that assumption. ++ /* Upload filter kernels. We only have the one for now, so we ++ * keep it around for the lifetime of the driver. + */ ++ ret = vc4_hvs_upload_linear_kernel(hvs, ++ &hvs->mitchell_netravali_filter, ++ mitchell_netravali_1_3_1_3_kernel); ++ if (ret) ++ return ret; + -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ -+ 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); -+ -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); -+ -+ pm_runtime_put(&vc4_hdmi->pdev->dev); ++ ret = vc4_hvs_cob_init(hvs); + if (ret) + return ret; + ++ if (vc4->gen < VC4_GEN_6) { ++ ret = devm_request_irq(dev, platform_get_irq(pdev, 0), ++ vc4_hvs_irq_handler, 0, "vc4 hvs", drm); ++ if (ret) ++ return ret; ++ } + return 0; } -+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) +@@ -1046,6 +2343,7 @@ static void vc4_hvs_unbind(struct device *dev, struct device *master, + drm_mm_remove_node(node); + drm_mm_takedown(&vc4->hvs->lbm_mm); + ++ clk_disable_unprepare(hvs->disp_clk); + clk_disable_unprepare(hvs->core_clk); + + vc4->hvs = NULL; +@@ -1068,6 +2366,8 @@ static void vc4_hvs_dev_remove(struct platform_device *pdev) + + static const struct of_device_id vc4_hvs_dt_match = { + { .compatible = "brcm,bcm2711-hvs" }, ++ { .compatible = "brcm,bcm2712-hvs" }, ++ { .compatible = "brcm,bcm2712d0-hvs" }, + { .compatible = "brcm,bcm2835-hvs" }, + {} + }; +diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c +index 563b3dfeb9b9..8581cc212a12 100644 +--- a/drivers/gpu/drm/vc4/vc4_irq.c ++++ b/drivers/gpu/drm/vc4/vc4_irq.c +@@ -263,7 +263,7 @@ vc4_irq_enable(struct drm_device *dev) { - struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); -+ unsigned long flags; -+ -+ /* -+ * NOTE: This function should really take vc4_hdmi->mutex, but doing so -+ * results in a reentrancy since cec_s_phys_addr_from_edid() called in -+ * .detect or .get_modes might call .adap_enable, which leads to this -+ * function being called with that mutex held. -+ * -+ * Concurrency is not an issue for the moment since we don't share any -+ * state with KMS, so we can ignore the lock for now, but we need to -+ * keep it in mind if we were to change that assumption. -+ */ + struct vc4_dev *vc4 = to_vc4_dev(dev); -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - HDMI_WRITE(HDMI_CEC_CNTRL_1, - (HDMI_READ(HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) | - (log_addr & 0xf) << VC4_HDMI_CEC_ADDR_SHIFT); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); -+ - return 0; - } +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; -@@ -1454,14 +2624,28 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, + if (!vc4->v3d) +@@ -280,7 +280,7 @@ vc4_irq_disable(struct drm_device *dev) { - struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); - struct drm_device *dev = vc4_hdmi->connector.dev; -+ unsigned long flags; - u32 val; - unsigned int i; + struct vc4_dev *vc4 = to_vc4_dev(dev); -+ /* -+ * NOTE: This function should really take vc4_hdmi->mutex, but doing so -+ * results in a reentrancy since cec_s_phys_addr_from_edid() called in -+ * .detect or .get_modes might call .adap_enable, which leads to this -+ * function being called with that mutex held. -+ * -+ * Concurrency is not an issue for the moment since we don't share any -+ * state with KMS, so we can ignore the lock for now, but we need to -+ * keep it in mind if we were to change that assumption. -+ */ -+ - if (msg->len > 16) { - drm_err(dev, "Attempting to transmit too much data (%d)\n", msg->len); - return -ENOMEM; - } +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ - for (i = 0; i < msg->len; i += 4) - HDMI_WRITE(HDMI_CEC_TX_DATA_1 + (i >> 2), - (msg->msgi) | -@@ -1477,6 +2661,9 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, - val |= VC4_HDMI_CEC_START_XMIT_BEGIN; + if (!vc4->v3d) +@@ -303,7 +303,7 @@ int vc4_irq_install(struct drm_device *dev, int irq) + struct vc4_dev *vc4 = to_vc4_dev(dev); + int ret; - HDMI_WRITE(HDMI_CEC_CNTRL_1, val); -+ -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); -+ - return 0; - } +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; -@@ -1490,11 +2677,14 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) + if (irq == IRQ_NOTCONNECTED) +@@ -324,7 +324,7 @@ void vc4_irq_uninstall(struct drm_device *dev) { - struct cec_connector_info conn_info; - struct platform_device *pdev = vc4_hdmi->pdev; -- u32 value; -+ struct device *dev = &pdev->dev; -+ unsigned long flags; - int ret; + struct vc4_dev *vc4 = to_vc4_dev(dev); -- 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; -+ } +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; - vc4_hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops, - vc4_hdmi, "vc4", -@@ -1507,28 +2697,49 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) - cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector); - cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info); + vc4_irq_disable(dev); +@@ -337,7 +337,7 @@ void vc4_irq_reset(struct drm_device *dev) + struct vc4_dev *vc4 = to_vc4_dev(dev); + unsigned long irqflags; -- 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; -- HDMI_WRITE(HDMI_CEC_CNTRL_1, value); -- -- 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; +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + /* Acknowledge any stale IRQs. */ +diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c +index 5495f2a94fa9..ea66914ed5ea 100644 +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -138,6 +138,11 @@ vc4_ctm_commit(struct vc4_dev *vc4, struct drm_atomic_state *state) + 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; + -+ 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 { -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_5); + -+ 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; -+ } + if (ctm_state->fifo) { + HVS_WRITE(SCALER_OLEDCOEF2, + VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix0), +@@ -213,6 +218,8 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4, + struct drm_crtc *crtc; + unsigned int i; - ret = cec_register_adapter(vc4_hdmi->cec_adap, &pdev->dev); - if (ret < 0) -- goto err_delete_cec_adap; -+ goto err_remove_handlers; ++ WARN_ON_ONCE(vc4->gen != VC4_GEN_4); ++ + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); +@@ -256,6 +263,8 @@ static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4, + unsigned int i; + u32 reg; - return 0; ++ WARN_ON_ONCE(vc4->gen != VC4_GEN_5); ++ + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); +@@ -320,17 +329,59 @@ static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4, + } + } -+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); ++static void vc6_hvs_pv_muxing_commit(struct vc4_dev *vc4, ++ struct drm_atomic_state *state) ++{ ++ struct vc4_hvs *hvs = vc4->hvs; ++ struct drm_crtc_state *crtc_state; ++ struct drm_crtc *crtc; ++ unsigned int i; + -+err_remove_cec_rx_handler: -+ if (vc4_hdmi->variant->external_irq_controller) -+ free_irq(platform_get_irq_byname(pdev, "cec-rx"), vc4_hdmi); ++ WARN_ON_ONCE(vc4->gen != VC4_GEN_6); + - err_delete_cec_adap: - cec_delete_adapter(vc4_hdmi->cec_adap); - -@@ -1537,8 +2748,40 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) - - static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi) - { -+ struct platform_device *pdev = vc4_hdmi->pdev; ++ for_each_new_crtc_in_state(state, crtc, crtc_state, i) { ++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); ++ struct vc4_encoder *vc4_encoder; ++ struct drm_encoder *encoder; ++ unsigned char mux; ++ u32 reg; + -+ if (vc4_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); -+ } ++ if (!vc4_state->update_muxing) ++ continue; + - cec_unregister_adapter(vc4_hdmi->cec_adap); - } ++ if (vc4_state->assigned_channel != 1) ++ continue; + -+static int vc4_hdmi_cec_resume(struct vc4_hdmi *vc4_hdmi) -+{ -+ unsigned long flags; -+ u32 value; ++ encoder = vc4_get_crtc_encoder(crtc, crtc_state); ++ vc4_encoder = to_vc4_encoder(encoder); ++ switch (vc4_encoder->type) { ++ case VC4_ENCODER_TYPE_HDMI1: ++ mux = 0; ++ break; + -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ value = HDMI_READ(HDMI_CEC_CNTRL_1); -+ /* Set the logical address to Unregistered */ -+ value |= VC4_HDMI_CEC_ADDR_MASK; -+ HDMI_WRITE(HDMI_CEC_CNTRL_1, value); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ case VC4_ENCODER_TYPE_TXP1: ++ mux = 2; ++ break; + -+ vc4_hdmi_cec_update_clk_div(vc4_hdmi); ++ default: ++ break; ++ } + -+ if (!vc4_hdmi->variant->external_irq_controller) { -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ reg = HVS_READ(SCALER6_CONTROL); ++ HVS_WRITE(SCALER6_CONTROL, ++ (reg & ~SCALER6_CONTROL_DSP1_TARGET_MASK) | ++ VC4_SET_FIELD(mux, SCALER6_CONTROL_DSP1_TARGET)); + } -+ -+ return 0; +} - #else - static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) ++ + static void vc4_atomic_commit_tail(struct drm_atomic_state *state) { -@@ -1547,6 +2790,10 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) + struct drm_device *dev = state->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_hvs *hvs = vc4->hvs; +- struct drm_crtc_state *new_crtc_state; + struct vc4_hvs_state *new_hvs_state; +- struct drm_crtc *crtc; + struct vc4_hvs_state *old_hvs_state; + unsigned int channel; +- int i; - static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi) {}; + old_hvs_state = vc4_hvs_get_old_global_state(state); + if (WARN_ON(IS_ERR(old_hvs_state))) +@@ -340,14 +391,23 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) + if (WARN_ON(IS_ERR(new_hvs_state))) + return; -+static int vc4_hdmi_cec_resume(struct vc4_hdmi *vc4_hdmi) -+{ -+ return 0; -+} - #endif +- for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { +- struct vc4_crtc_state *vc4_crtc_state; ++ if (0 && vc4->gen < VC4_GEN_6) { ++ struct drm_crtc_state *new_crtc_state; ++ struct drm_crtc *crtc; ++ int i; - static int vc4_hdmi_build_regset(struct vc4_hdmi *vc4_hdmi, -@@ -1621,6 +2868,7 @@ static int vc4_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi) - return PTR_ERR(vc4_hdmi->hsm_clock); - } - vc4_hdmi->audio_clock = vc4_hdmi->hsm_clock; -+ vc4_hdmi->cec_clock = vc4_hdmi->hsm_clock; +- if (!new_crtc_state->commit) +- continue; ++ for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { ++ struct vc4_crtc_state *vc4_crtc_state; - return 0; - } -@@ -1630,6 +2878,7 @@ static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi) - struct platform_device *pdev = vc4_hdmi->pdev; - struct device *dev = &pdev->dev; - struct resource *res; -+ int ret; +- vc4_crtc_state = to_vc4_crtc_state(new_crtc_state); +- vc4_hvs_mask_underrun(hvs, vc4_crtc_state->assigned_channel); ++ if (vc4->firmware_kms) ++ continue; ++ ++ if (!new_crtc_state->commit) ++ continue; ++ ++ vc4_crtc_state = to_vc4_crtc_state(new_crtc_state); ++ vc4_hvs_mask_underrun(hvs, vc4_crtc_state->assigned_channel); ++ } + } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi"); - if (!res) -@@ -1714,12 +2963,50 @@ static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi) - return PTR_ERR(vc4_hdmi->audio_clock); + for (channel = 0; channel < HVS_NUM_CHANNELS; channel++) { +@@ -369,7 +429,7 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) + old_hvs_state->fifo_statechannel.pending_commit = NULL; } -+ 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); +- if (vc4->is_vc5) { ++ if (vc4->gen == VC4_GEN_5 && !vc4->firmware_kms) { + unsigned long state_rate = max(old_hvs_state->core_clock_rate, + new_hvs_state->core_clock_rate); + unsigned long core_rate = clamp_t(unsigned long, state_rate, +@@ -382,16 +442,33 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) + * modeset. + */ + WARN_ON(clk_set_min_rate(hvs->core_clk, core_rate)); ++ WARN_ON(clk_set_min_rate(hvs->disp_clk, core_rate)); } -+ 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; - } + drm_atomic_helper_commit_modeset_disables(dev, state); -@@ -1742,6 +3029,15 @@ static int vc4_hdmi_runtime_resume(struct device *dev) - if (ret) - return ret; +- vc4_ctm_commit(vc4, state); ++ if (vc4->gen <= VC4_GEN_5) ++ vc4_ctm_commit(vc4, state); -+ if (vc4_hdmi->variant->reset) -+ vc4_hdmi->variant->reset(vc4_hdmi); -+ -+ ret = vc4_hdmi_cec_resume(vc4_hdmi); -+ if (ret) { -+ clk_disable_unprepare(vc4_hdmi->hsm_clock); -+ return ret; -+ } +- if (vc4->is_vc5) +- vc5_hvs_pv_muxing_commit(vc4, state); +- else +- vc4_hvs_pv_muxing_commit(vc4, state); ++ if (!vc4->firmware_kms) { ++ switch (vc4->gen) { ++ case VC4_GEN_4: ++ vc4_hvs_pv_muxing_commit(vc4, state); ++ break; + - return 0; - } - #endif -@@ -1760,6 +3056,9 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) - vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL); - if (!vc4_hdmi) - return -ENOMEM; -+ mutex_init(&vc4_hdmi->mutex); -+ spin_lock_init(&vc4_hdmi->hw_lock); -+ INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq); - - dev_set_drvdata(dev, vc4_hdmi); - encoder = &vc4_hdmi->encoder.base.base; -@@ -1772,6 +3071,15 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) - vc4_hdmi->pdev = pdev; - vc4_hdmi->variant = variant; - -+ /* -+ * Since we don't know the state of the controller and its -+ * display (if any), let's assume it's always enabled. -+ * vc4_hdmi_disable_scrambling() will thus run at boot, make -+ * sure it's disabled, and avoid any inconsistency. -+ */ -+ if (variant->max_pixel_clock > HDMI_14_MAX_TMDS_CLK) -+ vc4_hdmi->scdc_enabled = true; ++ case VC4_GEN_5: ++ vc5_hvs_pv_muxing_commit(vc4, state); ++ break; + - ret = variant->init_resources(vc4_hdmi); - if (ret) - return ret; -@@ -1809,6 +3117,14 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) - 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); ++ case VC4_GEN_6: ++ vc6_hvs_pv_muxing_commit(vc4, state); ++ break; + -+ if (max_rate < 550000000) -+ vc4_hdmi->disable_4kp60 = true; ++ default: ++ drm_err(dev, "Unknown VC4 generation: %d", vc4->gen); ++ break; ++ } + } -+ - /* - * If we boot without any cable connected to the HDMI connector, - * the firmware will skip the HSM initialization and leave it -@@ -1817,13 +3133,29 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) - * - * Let's put a sensible default at runtime_resume so that we - * don't end up in this situation. -+ * -+ * Strictly speaking we should be using clk_set_min_rate. -+ * However, the clk-bcm2835 clock driver favors clock rates -+ * under the expected rate, which in the case where we set the -+ * minimum clock rate will be rejected by the clock framework. -+ * -+ * However, even for the two HDMI controllers found on the -+ * BCM2711, using clk_set_rate doesn't cause any issue. Indeed, -+ * the bind callbacks are called in sequence, and before the DRM -+ * device is registered and therefore a mode is set. As such, -+ * we're not at risk of having the first controller set a -+ * different mode and then the second overriding the HSM clock -+ * frequency in its bind. - */ -- ret = clk_set_min_rate(vc4_hdmi->hsm_clock, HSM_MIN_CLOCK_FREQ); -+ ret = clk_set_rate(vc4_hdmi->hsm_clock, HSM_MIN_CLOCK_FREQ); - if (ret) - goto err_put_ddc; -- if (vc4_hdmi->variant->reset) -- vc4_hdmi->variant->reset(vc4_hdmi); -+ pm_runtime_enable(dev); -+ -+ ret = pm_runtime_resume_and_get(dev); -+ if (ret) -+ goto err_put_ddc; + drm_atomic_helper_commit_planes(dev, state, + DRM_PLANE_COMMIT_ACTIVE_ONLY); +@@ -406,7 +483,7 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) - if ((of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi0") || - of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi1")) && -@@ -1833,8 +3165,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) - clk_prepare_enable(vc4_hdmi->pixel_bvb_clock); - } + drm_atomic_helper_cleanup_planes(dev, state); -- pm_runtime_enable(dev); -- - drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); - drm_encoder_helper_add(encoder, &vc4_hdmi_encoder_helper_funcs); +- if (vc4->is_vc5) { ++ if (vc4->gen == VC4_GEN_5 && !vc4->firmware_kms) { + unsigned long core_rate = min_t(unsigned long, + hvs->max_core_rate, + new_hvs_state->core_clock_rate); +@@ -418,6 +495,7 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) + * requirements. + */ + WARN_ON(clk_set_min_rate(hvs->core_clk, core_rate)); ++ WARN_ON(clk_set_min_rate(hvs->disp_clk, core_rate)); -@@ -1842,10 +3172,14 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) - if (ret) - goto err_destroy_encoder; + drm_dbg(dev, "Core clock actual rate: %lu Hz\n", + clk_get_rate(hvs->core_clk)); +@@ -426,11 +504,21 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) -- ret = vc4_hdmi_cec_init(vc4_hdmi); -+ ret = vc4_hdmi_hotplug_init(vc4_hdmi); - if (ret) - goto err_destroy_conn; + 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); + struct drm_crtc_state *crtc_state; + struct vc4_hvs_state *hvs_state; + struct drm_crtc *crtc; + unsigned int i; -+ ret = vc4_hdmi_cec_init(vc4_hdmi); -+ if (ret) -+ goto err_free_hotplug; ++ /* 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. ++ */ ++ if (!vc4->firmware_kms) ++ state->legacy_cursor_update = false; + - ret = vc4_hdmi_audio_init(vc4_hdmi); - if (ret) - goto err_free_cec; -@@ -1854,14 +3188,19 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) - vc4_hdmi_debugfs_regs, - vc4_hdmi); + hvs_state = vc4_hvs_get_new_global_state(state); + if (WARN_ON(IS_ERR(hvs_state))) + return PTR_ERR(hvs_state); +@@ -461,7 +549,7 @@ static struct drm_framebuffer *vc4_fb_create(struct drm_device *dev, + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct drm_mode_fb_cmd2 mode_cmd_local; -+ pm_runtime_put_sync(dev); +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return ERR_PTR(-ENODEV); + + /* If the user didn't specify a modifier, use the +@@ -799,6 +887,7 @@ static int cmp_vc4_crtc_hvs_output(const void *a, const void *b) + 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 **sorted_crtcs; + struct drm_crtc *crtc; +@@ -806,6 +895,9 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev, + unsigned int i; + int ret; + ++ if (vc4->firmware_kms) ++ return 0; + - return 0; + hvs_new_state = vc4_hvs_get_global_state(state); + if (IS_ERR(hvs_new_state)) + return PTR_ERR(hvs_new_state); +@@ -1040,7 +1132,7 @@ int vc4_kms_load(struct drm_device *dev) + * the BCM2711, but the load tracker computations are used for + * the core clock rate calculation. + */ +- if (!vc4->is_vc5) { ++ if (vc4->gen == VC4_GEN_4) { + /* Start with the load tracker enabled. Can be + * disabled through the debugfs load_tracker file. + */ +@@ -1056,7 +1148,10 @@ int vc4_kms_load(struct drm_device *dev) + return ret; + } - 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); -@@ -1899,6 +3238,7 @@ static void vc4_hdmi_unbind(struct device *dev, struct device *master, - 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); - -@@ -1928,7 +3268,6 @@ static const struct vc4_hdmi_variant bcm2835_variant = { - .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), - -@@ -1940,14 +3279,16 @@ static const struct vc4_hdmi_variant bcm2835_variant = { - .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 = { -@@ -1957,6 +3298,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = { - PHY_LANE_CK, - }, - .unsupported_odd_h_timings = true, -+ .external_irq_controller = true, +- if (vc4->is_vc5) { ++ if (vc4->gen >= VC4_GEN_6) { ++ dev->mode_config.max_width = 8192; ++ dev->mode_config.max_height = 8192; ++ } else if (vc4->gen >= VC4_GEN_5) { + dev->mode_config.max_width = 7680; + dev->mode_config.max_height = 7680; + } else { +@@ -1064,7 +1159,7 @@ int vc4_kms_load(struct drm_device *dev) + dev->mode_config.max_height = 2048; + } - .init_resources = vc5_hdmi_init_resources, - .csc_setup = vc5_hdmi_csc_setup, -@@ -1966,14 +3308,17 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = { - .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, -+ .hp_detect = vc5_hdmi_hp_detect, - }; +- dev->mode_config.funcs = vc4->is_vc5 ? &vc5_mode_funcs : &vc4_mode_funcs; ++ dev->mode_config.funcs = (vc4->gen > VC4_GEN_4) ? &vc5_mode_funcs : &vc4_mode_funcs; + dev->mode_config.helper_private = &vc4_mode_config_helpers; + dev->mode_config.preferred_depth = 24; + dev->mode_config.async_page_flip = true; +diff --git a/drivers/gpu/drm/vc4/vc4_perfmon.c b/drivers/gpu/drm/vc4/vc4_perfmon.c +index c4ac2c946238..4cd3643c3ba7 100644 +--- a/drivers/gpu/drm/vc4/vc4_perfmon.c ++++ b/drivers/gpu/drm/vc4/vc4_perfmon.c +@@ -23,7 +23,7 @@ void vc4_perfmon_get(struct vc4_perfmon *perfmon) + return; - 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 = { -@@ -1983,6 +3328,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = { - PHY_LANE_2, - }, - .unsupported_odd_h_timings = true, -+ .external_irq_controller = true, + vc4 = perfmon->dev; +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; - .init_resources = vc5_hdmi_init_resources, - .csc_setup = vc5_hdmi_csc_setup, -@@ -1992,7 +3338,10 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = { - .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, -+ .hp_detect = vc5_hdmi_hp_detect, - }; + refcount_inc(&perfmon->refcnt); +@@ -37,7 +37,7 @@ void vc4_perfmon_put(struct vc4_perfmon *perfmon) + return; - static const struct of_device_id vc4_hdmi_dt_match = { -diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h -index 0526a9cf608a..fa57d853b100 100644 ---- a/drivers/gpu/drm/vc4/vc4_hdmi.h -+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h -@@ -12,7 +12,6 @@ - struct vc4_hdmi_encoder { - struct vc4_encoder base; - bool hdmi_monitor; -- bool limited_rgb_range; - }; + vc4 = perfmon->dev; +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; - static inline struct vc4_hdmi_encoder * -@@ -21,10 +20,9 @@ to_vc4_hdmi_encoder(struct drm_encoder *encoder) - return container_of(encoder, struct vc4_hdmi_encoder, base.base); - } + if (refcount_dec_and_test(&perfmon->refcnt)) +@@ -49,7 +49,7 @@ void vc4_perfmon_start(struct vc4_dev *vc4, struct vc4_perfmon *perfmon) + unsigned int i; + u32 mask; --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, -@@ -43,9 +41,6 @@ struct vc4_hdmi_variant { - /* Filename to expose the registers in debugfs */ - const char *debugfs_name; +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; -- /* 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; + if (WARN_ON_ONCE(!perfmon || vc4->active_perfmon)) +@@ -69,7 +69,7 @@ void vc4_perfmon_stop(struct vc4_dev *vc4, struct vc4_perfmon *perfmon, + { + unsigned int i; -@@ -65,6 +60,13 @@ struct vc4_hdmi_variant { - /* The BCM2711 cannot deal with odd horizontal pixel timings */ - bool unsupported_odd_h_timings; +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; -+ /* -+ * 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. - */ -@@ -74,15 +76,18 @@ struct vc4_hdmi_variant { - void (*reset)(struct vc4_hdmi *vc4_hdmi); + if (WARN_ON_ONCE(!vc4->active_perfmon || +@@ -90,7 +90,7 @@ struct vc4_perfmon *vc4_perfmon_find(struct vc4_file *vc4file, int id) + struct vc4_dev *vc4 = vc4file->dev; + struct vc4_perfmon *perfmon; - /* Callback to enable / disable the CSC */ -- void (*csc_setup)(struct vc4_hdmi *vc4_hdmi, bool enable); -+ void (*csc_setup)(struct vc4_hdmi *vc4_hdmi, -+ struct drm_connector_state *state, -+ const struct drm_display_mode *mode); - - /* 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); -@@ -93,8 +98,17 @@ struct vc4_hdmi_variant { - /* 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; -+ -+ /* Callback for hardware specific hotplug detect */ -+ bool (*hp_detect)(struct vc4_hdmi *vc4_hdmi); - }; - - /* HDMI audio information */ -@@ -104,14 +118,18 @@ struct vc4_hdmi_audio { - 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; - }; +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return NULL; -+enum vc4_hdmi_output_format { -+ VC4_HDMI_OUTPUT_RGB, -+ VC4_HDMI_OUTPUT_YUV422, -+ VC4_HDMI_OUTPUT_YUV444, -+ VC4_HDMI_OUTPUT_YUV420, -+}; -+ - /* General HDMI hardware state. */ - struct vc4_hdmi { - struct vc4_hdmi_audio audio; -@@ -122,6 +140,10 @@ struct vc4_hdmi { - struct vc4_hdmi_encoder encoder; - struct drm_connector connector; + mutex_lock(&vc4file->perfmon.lock); +@@ -105,7 +105,7 @@ void vc4_perfmon_open_file(struct vc4_file *vc4file) + { + struct vc4_dev *vc4 = vc4file->dev; -+ struct delayed_work scrambling_work; -+ -+ struct drm_property *broadcast_rgb_property; -+ - struct i2c_adapter *ddc; - void __iomem *hdmicore_regs; - void __iomem *hd_regs; -@@ -150,11 +172,20 @@ struct vc4_hdmi { - */ - bool disable_wifi_frequencies; +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; -+ /* -+ * 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; -@@ -162,8 +193,75 @@ struct vc4_hdmi { + mutex_init(&vc4file->perfmon.lock); +@@ -126,7 +126,7 @@ void vc4_perfmon_close_file(struct vc4_file *vc4file) + { + struct vc4_dev *vc4 = vc4file->dev; - struct reset_control *reset; +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; -+ 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; -+ -+ /** -+ * @hw_lock: Spinlock protecting device register access. -+ */ -+ spinlock_t hw_lock; -+ -+ /** -+ * @mutex: Mutex protecting the driver access across multiple -+ * frameworks (KMS, ALSA). -+ * -+ * NOTE: While supported, CEC has been left out since -+ * cec_s_phys_addr_from_edid() might call .adap_enable and lead to a -+ * reentrancy issue between .get_modes (or .detect) and .adap_enable. -+ * Since we don't share any state between the CEC hooks and KMS', it's -+ * not a big deal. The only trouble might come from updating the CEC -+ * clock divider which might be affected by a modeset, but CEC should -+ * be resilient to that. -+ */ -+ struct mutex mutex; -+ -+ /** -+ * @saved_adjusted_mode: Copy of @drm_crtc_state.adjusted_mode -+ * for use by ALSA hooks and interrupt handlers. Protected by @mutex. -+ */ -+ struct drm_display_mode saved_adjusted_mode; -+ -+ /** -+ * @output_enabled: Is the HDMI controller currently active? -+ * Protected by @mutex. -+ */ -+ bool output_enabled; -+ -+ /** -+ * @scdc_enabled: Is the HDMI controller currently running with -+ * the scrambler on? Protected by @mutex. -+ */ -+ bool scdc_enabled; -+ -+ /** -+ * @output_bpc: Copy of @vc4_connector_state.output_bpc for use -+ * outside of KMS hooks. Protected by @mutex. -+ */ -+ unsigned int output_bpc; -+ -+ /** -+ * @output_format: Copy of @vc4_connector_state.output_format -+ * for use outside of KMS hooks. Protected by @mutex. -+ */ -+ enum vc4_hdmi_output_format output_format; -+ -+ /** -+ * @broadcast_rgb: Copy of @vc4_connector_state.broadcast_rgb -+ * for use outside of KMS hooks. Protected by @mutex. -+ */ -+ int broadcast_rgb; - }; + mutex_lock(&vc4file->perfmon.lock); +@@ -146,7 +146,7 @@ int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data, + unsigned int i; + int ret; - static inline struct vc4_hdmi * -@@ -180,14 +278,34 @@ encoder_to_vc4_hdmi(struct drm_encoder *encoder) - return container_of(_encoder, struct vc4_hdmi, encoder); - } +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; -+struct vc4_hdmi_connector_state { -+ struct drm_connector_state base; -+ unsigned long long pixel_rate; -+ unsigned int output_bpc; -+ enum vc4_hdmi_output_format output_format; -+ int broadcast_rgb; -+}; -+ -+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); -+} -+ -+static inline const struct vc4_hdmi_connector_state * -+const_conn_state_to_vc4_hdmi_conn_state(const 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); + if (!vc4->v3d) { +@@ -200,7 +200,7 @@ int vc4_perfmon_destroy_ioctl(struct drm_device *dev, void *data, + struct drm_vc4_perfmon_destroy *req = data; + struct vc4_perfmon *perfmon; - 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 --git a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c -index 057796b54c51..62148f0dc284 100644 ---- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c -+++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c -@@ -127,33 +127,52 @@ +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; - #define OSCILLATOR_FREQUENCY 54000000 + if (!vc4->v3d) { +@@ -228,7 +228,7 @@ int vc4_perfmon_get_values_ioctl(struct drm_device *dev, void *data, + struct vc4_perfmon *perfmon; + int ret; --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) - { -+ unsigned long flags; -+ - /* PHY should be in reset, like - * vc4_hdmi_encoder_disable() does. - */ +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ - HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16); - HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0); -+ -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + if (!vc4->v3d) { +diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c +index 00e713faecd5..2d1039aa2dcf 100644 +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -109,6 +109,18 @@ static const struct hvs_format { + .pixel_order = HVS_PIXEL_ORDER_XYCRCB, + .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB, + }, ++ { ++ .drm = DRM_FORMAT_YUV444, ++ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE, ++ .pixel_order = HVS_PIXEL_ORDER_XYCBCR, ++ .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR, ++ }, ++ { ++ .drm = DRM_FORMAT_YVU444, ++ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE, ++ .pixel_order = HVS_PIXEL_ORDER_XYCRCB, ++ .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB, ++ }, + { + .drm = DRM_FORMAT_YUV420, + .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE, +@@ -251,9 +263,9 @@ static const struct hvs_format *vc4_get_hvs_format(u32 drm_format) + + static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst) + { +- if (dst == src) ++ if (dst == src >> 16) + return VC4_SCALING_NONE; +- if (3 * dst >= 2 * src) ++ if (3 * dst >= 2 * (src >> 16)) + return VC4_SCALING_PPF; + else + return VC4_SCALING_TPZ; +@@ -264,9 +276,10 @@ static bool plane_enabled(struct drm_plane_state *state) + return state->fb && !WARN_ON(!state->crtc); } - void vc4_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi) +-static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) ++struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) { -+ unsigned long flags; -+ -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); - } + struct vc4_plane_state *vc4_state; ++ unsigned int i; - void vc4_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi) - { -+ unsigned long flags; + if (WARN_ON(!plane->state)) + return NULL; +@@ -275,7 +288,11 @@ static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane + if (!vc4_state) + return NULL; + +- memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm)); ++ memset(&vc4_state->upm, 0, sizeof(vc4_state->upm)); + -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - HDMI_WRITE(HDMI_TX_PHY_CTL_0, - HDMI_READ(HDMI_TX_PHY_CTL_0) & - ~VC4_HDMI_TX_PHY_RNG_PWRDN); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) ++ vc4_state->upm_handlei = 0; ++ + vc4_state->dlist_initialized = 0; + + __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base); +@@ -294,18 +311,26 @@ static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane + return &vc4_state->base; } - void vc4_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi) +-static void vc4_plane_destroy_state(struct drm_plane *plane, +- struct drm_plane_state *state) ++void vc4_plane_destroy_state(struct drm_plane *plane, ++ struct drm_plane_state *state) { -+ unsigned long flags; + struct vc4_dev *vc4 = to_vc4_dev(plane->dev); ++ struct vc4_hvs *hvs = vc4->hvs; + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ unsigned int i; + +- if (drm_mm_node_allocated(&vc4_state->lbm)) { ++ for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) { + unsigned long irqflags; + +- spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); +- drm_mm_remove_node(&vc4_state->lbm); +- spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); ++ if (!drm_mm_node_allocated(&vc4_state->upmi)) ++ continue; + -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - HDMI_WRITE(HDMI_TX_PHY_CTL_0, - HDMI_READ(HDMI_TX_PHY_CTL_0) | - VC4_HDMI_TX_PHY_RNG_PWRDN); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); - } ++ spin_lock_irqsave(&hvs->mm_lock, irqflags); ++ drm_mm_remove_node(&vc4_state->upmi); ++ spin_unlock_irqrestore(&hvs->mm_lock, irqflags); ++ ++ if (vc4_state->upm_handlei > 0) ++ ida_free(&hvs->upm_handles, vc4_state->upm_handlei); + } - static unsigned long long -@@ -335,21 +354,27 @@ phy_get_channel_settings(enum vc4_hdmi_phy_channel chan, + kfree(vc4_state->dlist); +@@ -314,7 +339,7 @@ static void vc4_plane_destroy_state(struct drm_plane *plane, + } - static void vc5_hdmi_reset_phy(struct vc4_hdmi *vc4_hdmi) + /* Called during init to allocate the plane's atomic state. */ +-static void vc4_plane_reset(struct drm_plane *plane) ++void vc4_plane_reset(struct drm_plane *plane) { -+ lockdep_assert_held(&vc4_hdmi->hw_lock); -+ - HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0x0f); - HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, BIT(10)); - } + struct vc4_plane_state *vc4_state; --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) +@@ -438,12 +463,11 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *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; -+ unsigned long flags; - u8 vco_sel, vco_div; + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + struct drm_framebuffer *fb = state->fb; +- struct drm_gem_dma_object *bo; + int num_planes = fb->format->num_planes; + struct drm_crtc_state *crtc_state; + u32 h_subsample = fb->format->hsub; + u32 v_subsample = fb->format->vsub; +- int i, ret; ++ int ret; - vco_freq = phy_get_vco_freq(pixel_freq, &vco_sel, &vco_div); + crtc_state = drm_atomic_get_existing_crtc_state(state->state, + state->crtc); +@@ -457,26 +481,21 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) + if (ret) + return ret; -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -+ - vc5_hdmi_reset_phy(vc4_hdmi); +- for (i = 0; i < num_planes; i++) { +- bo = drm_fb_dma_get_gem_obj(fb, i); +- vc4_state->offsetsi = bo->dma_addr + fb->offsetsi; +- } +- +- /* +- * 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_w0 = DIV_ROUND_CLOSEST(state->src.x2, 1 << 16) - vc4_state->src_x; +- vc4_state->src_h0 = DIV_ROUND_CLOSEST(state->src.y2, 1 << 16) - vc4_state->src_y; ++ vc4_state->src_x = state->src.x1; ++ vc4_state->src_y = state->src.y1; ++ vc4_state->src_w0 = state->src.x2 - vc4_state->src_x; ++ vc4_state->src_h0 = state->src.y2 - vc4_state->src_y; - HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, -@@ -499,23 +524,37 @@ void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct drm_display_mode *mode) - HDMI_READ(HDMI_TX_PHY_RESET_CTL) | - VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB | - VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB); -+ -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); - } + vc4_state->crtc_x = state->dst.x1; + vc4_state->crtc_y = state->dst.y1; + vc4_state->crtc_w = state->dst.x2 - state->dst.x1; + vc4_state->crtc_h = state->dst.y2 - state->dst.y1; - void vc5_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi) - { -+ unsigned long flags; ++ if (!vc4_state->crtc_w) ++ vc4_state->crtc_w = state->crtc->mode.hdisplay; ++ if (!vc4_state->crtc_h) ++ vc4_state->crtc_h = state->crtc->mode.vdisplay; + -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - vc5_hdmi_reset_phy(vc4_hdmi); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); - } - - void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi) - { -+ unsigned long flags; + ret = vc4_plane_margins_adj(state); + if (ret) + return ret; +@@ -510,6 +529,12 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) + */ + if (vc4_state->x_scaling1 == VC4_SCALING_NONE) + vc4_state->x_scaling1 = VC4_SCALING_PPF; + -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, - HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) & - ~VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); - } ++ /* Similarly UV needs vertical scaling to be enabled. ++ * Without this a 1:1 scaled YUV422 plane isn't rendered. ++ */ ++ if (vc4_state->y_scaling1 == VC4_SCALING_NONE) ++ vc4_state->y_scaling1 = VC4_SCALING_PPF; + } else { + vc4_state->is_yuv = false; + vc4_state->x_scaling1 = VC4_SCALING_NONE; +@@ -521,9 +546,12 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) - void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi) + static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst) { -+ unsigned long flags; -+ -+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, - HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) | - VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN); -+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); - } -diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h -index 6c0dfbbe1a7e..0198de96c7b2 100644 ---- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h -+++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h -@@ -1,6 +1,8 @@ - #ifndef _VC4_HDMI_REGS_H_ - #define _VC4_HDMI_REGS_H_ ++ struct vc4_dev *vc4 = to_vc4_dev(vc4_state->base.plane->dev); + u32 scale, recip; -+#include <linux/pm_runtime.h> +- scale = (1 << 16) * src / dst; ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_6); + - #include "vc4_hdmi.h" ++ scale = src / dst; - #define VC4_HDMI_PACKET_STRIDE 0x24 -@@ -52,6 +54,7 @@ enum vc4_hdmi_field { - HDMI_CSC_24_23, - HDMI_CSC_32_31, - HDMI_CSC_34_33, -+ HDMI_CSC_CHANNEL_CTL, - HDMI_CSC_CTL, + /* The specs note that while the reciprocal would be defined + * as (1<<32)/scale, ~0 is close enough. +@@ -531,23 +559,70 @@ static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst) + recip = ~0 / scale; - /* -@@ -60,9 +63,12 @@ enum vc4_hdmi_field { - */ - 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, -@@ -97,6 +103,7 @@ enum vc4_hdmi_field { - 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, -@@ -113,12 +120,14 @@ enum vc4_hdmi_field { - HDMI_TX_PHY_POWERDOWN_CTL, - HDMI_TX_PHY_RESET_CTL, - HDMI_TX_PHY_TMDS_CLK_WORD_SEL, -+ HDMI_VEC_INTERFACE_CFG, - HDMI_VEC_INTERFACE_XBAR, - HDMI_VERTA0, - HDMI_VERTA1, - HDMI_VERTB0, - HDMI_VERTB1, - HDMI_VID_CTL, -+ HDMI_MISC_CONTROL, - }; - - struct vc4_hdmi_register { -@@ -143,7 +152,7 @@ struct vc4_hdmi_register { - #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), -@@ -205,7 +214,7 @@ static const struct vc4_hdmi_register vc4_hdmi_fields = { - 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), -@@ -229,11 +238,17 @@ static const struct vc4_hdmi_register vc5_hdmi_hdmi0_fields = { - VC4_HDMI_REG(HDMI_VERTB0, 0x0f0), - VC4_HDMI_REG(HDMI_VERTA1, 0x0f4), - VC4_HDMI_REG(HDMI_VERTB1, 0x0f8), -+ VC4_HDMI_REG(HDMI_MISC_CONTROL, 0x100), - 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_CFG, 0x0ec), - VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0), - - VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000), -@@ -279,9 +294,10 @@ static const struct vc4_hdmi_register vc5_hdmi_hdmi0_fields = { - VC5_CSC_REG(HDMI_CSC_24_23, 0x010), - VC5_CSC_REG(HDMI_CSC_32_31, 0x014), - VC5_CSC_REG(HDMI_CSC_34_33, 0x018), -+ VC5_CSC_REG(HDMI_CSC_CHANNEL_CTL, 0x02c), - }; + vc4_dlist_write(vc4_state, ++ /* ++ * The BCM2712 is lacking BIT(31) compared to ++ * the previous generations, but we don't use ++ * it. ++ */ + VC4_SET_FIELD(scale, SCALER_TPZ0_SCALE) | + VC4_SET_FIELD(0, SCALER_TPZ0_IPHASE)); + vc4_dlist_write(vc4_state, + VC4_SET_FIELD(recip, SCALER_TPZ1_RECIP)); + } + +-static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst) ++/* phase magnitude bits */ ++#define PHASE_BITS 6 ++ ++static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst, u32 xy, int channel, int chroma_offset) + { +- u32 scale = (1 << 16) * src / dst; ++ struct vc4_dev *vc4 = to_vc4_dev(vc4_state->base.plane->dev); ++ u32 scale = src / dst; ++ s32 offset, offset2; ++ s32 phase; ++ ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_6); ++ ++ /* Start the phase at 1/2 pixel from the 1st pixel at src_x. ++ 1/4 pixel for YUV, plus the offset for chroma siting */ ++ if (channel) { ++ /* the phase is relative to scale_src->x, so shift it for display list's x value */ ++ offset = (xy & 0x1ffff) >> (16 - PHASE_BITS) >> 1; ++ offset -= chroma_offset >> (17 - PHASE_BITS); ++ offset += -(1 << PHASE_BITS >> 2); ++ } else { ++ /* the phase is relative to scale_src->x, so shift it for display list's x value */ ++ offset = (xy & 0xffff) >> (16 - PHASE_BITS); ++ offset += -(1 << PHASE_BITS >> 1); ++ ++ /* This is a kludge to make sure the scaling factors are consitent with YUV's luma scaling. ++ we lose 1bit precision because of this. */ ++ scale &= ~1; ++ } ++ ++ /* There may be a also small error introduced by precision of scale. ++ Add half of that as a compromise */ ++ offset2 = src - dst * scale; ++ offset2 >>= 16 - PHASE_BITS; ++ phase = offset + (offset2 >> 1); ++ ++ /* Ensure +ve values don't touch the sign bit, then truncate negative values */ ++ if (phase >= 1 << PHASE_BITS) ++ phase = (1 << PHASE_BITS) - 1; ++ ++ phase &= SCALER_PPF_IPHASE_MASK; + + vc4_dlist_write(vc4_state, + SCALER_PPF_AGC | + VC4_SET_FIELD(scale, SCALER_PPF_SCALE) | +- VC4_SET_FIELD(0, SCALER_PPF_IPHASE)); ++ /* ++ * The register layout documentation is slightly ++ * different to setup the phase in the BCM2712, ++ * but they seem equivalent. ++ */ ++ VC4_SET_FIELD(phase, SCALER_PPF_IPHASE)); + } --static 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), -@@ -305,11 +321,17 @@ static const struct vc4_hdmi_register vc5_hdmi_hdmi1_fields = { - VC4_HDMI_REG(HDMI_VERTB0, 0x0f0), - VC4_HDMI_REG(HDMI_VERTA1, 0x0f4), - VC4_HDMI_REG(HDMI_VERTB1, 0x0f8), -+ VC4_HDMI_REG(HDMI_MISC_CONTROL, 0x100), - 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_CFG, 0x0ec), - VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0), - - VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000), -@@ -355,6 +377,7 @@ static const struct vc4_hdmi_register vc5_hdmi_hdmi1_fields = { - VC5_CSC_REG(HDMI_CSC_24_23, 0x010), - VC5_CSC_REG(HDMI_CSC_32_31, 0x014), - VC5_CSC_REG(HDMI_CSC_34_33, 0x018), -+ VC5_CSC_REG(HDMI_CSC_CHANNEL_CTL, 0x02c), - }; +-static u32 vc4_lbm_size(struct drm_plane_state *state) ++static u32 __vc4_lbm_size(struct drm_plane_state *state) + { + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); +@@ -569,7 +644,7 @@ static u32 vc4_lbm_size(struct drm_plane_state *state) + if (vc4_state->x_scaling0 == VC4_SCALING_TPZ) + pix_per_line = vc4_state->crtc_w; + else +- pix_per_line = vc4_state->src_w0; ++ pix_per_line = vc4_state->src_w0 >> 16; - static inline -@@ -400,6 +423,8 @@ static inline u32 vc4_hdmi_read(struct vc4_hdmi *hdmi, - const struct vc4_hdmi_variant *variant = hdmi->variant; - void __iomem *base; + if (!vc4_state->is_yuv) { + if (vc4_state->y_scaling0 == VC4_SCALING_TPZ) +@@ -587,29 +662,159 @@ static u32 vc4_lbm_size(struct drm_plane_state *state) + } -+ WARN_ON(pm_runtime_status_suspended(&hdmi->pdev->dev)); -+ - if (reg >= variant->num_registers) { - dev_warn(&hdmi->pdev->dev, - "Invalid register ID %u\n", reg); -@@ -426,6 +451,10 @@ static inline void vc4_hdmi_write(struct vc4_hdmi *hdmi, - const struct vc4_hdmi_variant *variant = hdmi->variant; - void __iomem *base; + /* Align it to 64 or 128 (hvs5) bytes */ +- lbm = roundup(lbm, vc4->is_vc5 ? 128 : 64); ++ lbm = roundup(lbm, vc4->gen == VC4_GEN_5 ? 128 : 64); -+ lockdep_assert_held(&hdmi->hw_lock); -+ -+ WARN_ON(pm_runtime_status_suspended(&hdmi->pdev->dev)); -+ - if (reg >= variant->num_registers) { - dev_warn(&hdmi->pdev->dev, - "Invalid register ID %u\n", reg); -diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c -index ad691571d759..a873d9d8fd58 100644 ---- a/drivers/gpu/drm/vc4/vc4_hvs.c -+++ b/drivers/gpu/drm/vc4/vc4_hvs.c -@@ -95,6 +95,123 @@ static int vc4_hvs_debugfs_underrun(struct seq_file *m, void *data) - return 0; + /* Each "word" of the LBM memory contains 2 or 4 (hvs5) pixels */ +- lbm /= vc4->is_vc5 ? 4 : 2; ++ lbm /= vc4->gen == VC4_GEN_5 ? 4 : 2; + + return lbm; } -+static int vc4_hvs_debugfs_dlist(struct seq_file *m, void *data) ++static unsigned int vc4_lbm_words_per_component(const struct drm_plane_state *state, ++ unsigned int channel) +{ -+ 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; ++ const struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + -+ 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; -+ } ++ switch (vc4_state->y_scalingchannel) { ++ case VC4_SCALING_PPF: ++ return 4; + -+ drm_printf(&p, "HVS chan %u:\n", i); ++ case VC4_SCALING_TPZ: ++ return 2; + -+ 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); -+ } -+ } ++ default: ++ return 0; + } -+ -+ return 0; +} + -+static int vc5_hvs_debugfs_gamma(struct seq_file *m, void *data) ++static unsigned int vc4_lbm_components(const struct drm_plane_state *state, ++ unsigned int channel) +{ -+ 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 i, chan; -+ u32 dispstat, dispbkgndx; -+ -+ for (chan = 0; chan < SCALER_CHANNELS_COUNT; chan++) { -+ u32 x_c, grad; -+ u32 offset = SCALER5_DSPGAMMA_START + -+ chan * SCALER5_DSPGAMMA_CHAN_OFFSET; -+ -+ dispstat = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTATX(chan)), -+ SCALER_DISPSTATX_MODE); -+ if (dispstat == SCALER_DISPSTATX_MODE_DISABLED || -+ dispstat == SCALER_DISPSTATX_MODE_EOF) { -+ drm_printf(&p, "HVS channel %u: Channel disabled\n", chan); -+ continue; -+ } ++ const struct drm_format_info *info = state->fb->format; ++ const struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + -+ dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(chan)); -+ if (!(dispbkgndx & SCALER_DISPBKGND_GAMMA)) { -+ drm_printf(&p, "HVS channel %u: Gamma disabled\n", chan); -+ continue; -+ } -+ -+ drm_printf(&p, "HVS channel %u:\n", chan); -+ drm_printf(&p, " red:\n"); -+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) { -+ x_c = HVS_READ(offset); -+ grad = HVS_READ(offset + 4); -+ drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n", -+ x_c, grad, -+ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X), -+ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C), -+ grad); -+ } -+ drm_printf(&p, " green:\n"); -+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) { -+ x_c = HVS_READ(offset); -+ grad = HVS_READ(offset + 4); -+ drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n", -+ x_c, grad, -+ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X), -+ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C), -+ grad); -+ } -+ drm_printf(&p, " blue:\n"); -+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) { -+ x_c = HVS_READ(offset); -+ grad = HVS_READ(offset + 4); -+ drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n", -+ x_c, grad, -+ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X), -+ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C), -+ grad); -+ } -+ -+ /* Alpha only valid on channel 2 */ -+ if (chan != 2) -+ continue; -+ -+ drm_printf(&p, " alpha:\n"); -+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) { -+ x_c = HVS_READ(offset); -+ grad = HVS_READ(offset + 4); -+ drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n", -+ x_c, grad, -+ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X), -+ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C), -+ grad); -+ } -+ } -+ return 0; -+} -+ - /* The filter kernel is composed of dwords each containing 3 9-bit - * signed integers packed next to each other. - */ -@@ -197,6 +314,80 @@ static void vc4_hvs_update_gamma_lut(struct drm_crtc *crtc) - vc4_hvs_lut_load(crtc); - } - -+static void vc5_hvs_write_gamma_entry(struct vc4_dev *vc4, -+ u32 offset, -+ struct vc5_gamma_entry *gamma) -+{ -+ HVS_WRITE(offset, gamma->x_c_terms); -+ HVS_WRITE(offset + 4, gamma->grad_term); -+} ++ if (vc4_state->y_scalingchannel == VC4_SCALING_NONE) ++ return 0; + -+static void vc5_hvs_lut_load(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 vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); -+ u32 i; -+ u32 offset = SCALER5_DSPGAMMA_START + -+ vc4_state->assigned_channel * SCALER5_DSPGAMMA_CHAN_OFFSET; ++ if (info->is_yuv) ++ return channel ? 2 : 1; + -+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) -+ vc5_hvs_write_gamma_entry(vc4, offset, &vc4_crtc->pwl_ri); -+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) -+ vc5_hvs_write_gamma_entry(vc4, offset, &vc4_crtc->pwl_gi); -+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) -+ vc5_hvs_write_gamma_entry(vc4, offset, &vc4_crtc->pwl_bi); ++ if (info->has_alpha) ++ return 4; + -+ if (vc4_state->assigned_channel == 2) { -+ /* Alpha only valid on channel 2 */ -+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) -+ vc5_hvs_write_gamma_entry(vc4, offset, &vc4_crtc->pwl_ai); -+ } ++ return 3; +} + -+static void vc5_hvs_update_gamma_lut(struct drm_crtc *crtc) ++static unsigned int vc4_lbm_channel_size(const struct drm_plane_state *state, ++ unsigned int channel) +{ -+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); -+ struct drm_color_lut *lut = crtc->state->gamma_lut->data; -+ unsigned int step, i; -+ u32 start, end; -+ -+#define VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl, chan) \ -+ start = drm_color_lut_extract(luti * step.chan, 12); \ -+ end = drm_color_lut_extract(lut(i + 1) * step - 1.chan, 12); \ -+ \ -+ /* Negative gradients not permitted by the hardware, so \ -+ * flatten such points out. \ -+ */ \ -+ if (end < start) \ -+ end = start; \ -+ \ -+ /* Assume 12bit pipeline. \ -+ * X evenly spread over full range (12 bit). \ -+ * C as U12.4 format. \ -+ * Gradient as U4.8 format. \ -+ */ \ -+ vc4_crtc->pwli = \ -+ VC5_HVS_SET_GAMMA_ENTRY(i << 8, start << 4, \ -+ ((end - start) << 4) / (step - 1)) ++ const struct drm_format_info *info = state->fb->format; ++ const struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ unsigned int channels_scaled = 0; ++ unsigned int components, words, wpc; ++ unsigned int width, lines; ++ unsigned int i; + -+ /* HVS5 has a 16 point piecewise linear function for each colour -+ * channel (including alpha on channel 2) on each display channel. -+ * -+ * Currently take a crude subsample of the gamma LUT, but this could -+ * be improved to implement curve fitting. ++ /* LBM is meant to use the smaller of source or dest width, but there ++ * is a issue with UV scaling that the size required for the second ++ * channel is based on the source width only. + */ -+ step = crtc->gamma_size / SCALER5_DSPGAMMA_NUM_POINTS; -+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++) { -+ VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl_r, red); -+ VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl_g, green); -+ VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl_b, blue); -+ } -+ -+ vc5_hvs_lut_load(crtc); -+} -+ - int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output) - { - struct vc4_dev *vc4 = to_vc4_dev(dev); -@@ -289,15 +480,21 @@ static int vc4_hvs_init_channel(struct vc4_dev *vc4, struct drm_crtc *crtc, - dispbkgndx &= ~SCALER_DISPBKGND_GAMMA; - dispbkgndx &= ~SCALER_DISPBKGND_INTERLACE; - -+ if (crtc->state->gamma_lut) -+ /* Enable gamma on if required */ -+ dispbkgndx |= SCALER_DISPBKGND_GAMMA; -+ - HVS_WRITE(SCALER_DISPBKGNDX(chan), dispbkgndx | - SCALER_DISPBKGND_AUTOHS | -- ((!vc4->hvs->hvs5) ? SCALER_DISPBKGND_GAMMA : 0) | - (interlace ? SCALER_DISPBKGND_INTERLACE : 0)); - - /* Reload the LUT, since the SRAMs would have been disabled if - * all CRTCs had SCALER_DISPBKGND_GAMMA unset at once. - */ -- vc4_hvs_lut_load(crtc); -+ if (!vc4->hvs->hvs5) -+ vc4_hvs_lut_load(crtc); ++ if (info->hsub > 1 && channel == 1) ++ width = state->src_w >> 16; + else -+ vc5_hvs_lut_load(crtc); - - return 0; - } -@@ -326,10 +523,50 @@ void vc4_hvs_stop_channel(struct drm_device *dev, unsigned int chan) - SCALER_DISPSTATX_EMPTY); - } - --int vc4_hvs_atomic_check(struct drm_crtc *crtc, -- struct drm_crtc_state *state) -+static int vc4_hvs_gamma_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 drm_connector_state *conn_state; -+ struct drm_connector *connector; -+ struct drm_device *dev = crtc->dev; -+ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ width = min(state->src_w >> 16, state->crtc_w); ++ width = round_up(width / info->hsub, 4); + -+ if (!vc4->hvs->hvs5) ++ wpc = vc4_lbm_words_per_component(state, channel); ++ if (!wpc) + return 0; + -+ if (!crtc_state->color_mgmt_changed) ++ components = vc4_lbm_components(state, channel); ++ if (!components) + return 0; + -+ if (crtc_state->gamma_lut) { -+ unsigned int len = drm_color_lut_size(crtc_state->gamma_lut); ++ if (state->alpha != DRM_BLEND_ALPHA_OPAQUE && info->has_alpha) ++ components -= 1; + -+ if (len != crtc->gamma_size) { -+ DRM_DEBUG_KMS("Invalid LUT size; got %u, expected %u\n", -+ len, crtc->gamma_size); -+ return -EINVAL; -+ } -+ } ++ words = width * wpc * components; + -+ connector = vc4_get_crtc_connector(crtc, crtc_state); -+ if (!connector) -+ return -EINVAL; ++ lines = DIV_ROUND_UP(words, 128 / info->hsub); + -+ if (!(connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)) -+ return 0; ++ for (i = 0; i < 2; i++) ++ if (vc4_state->y_scalingchannel != VC4_SCALING_NONE) ++ channels_scaled++; + -+ conn_state = drm_atomic_get_connector_state(state, connector); -+ if (!conn_state) -+ return -EINVAL; ++ if (channels_scaled == 1) ++ lines = lines / 2; + -+ crtc_state->mode_changed = true; -+ return 0; ++ return lines; +} + -+int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) ++static unsigned int __vc6_lbm_size(const struct drm_plane_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; -@@ -341,10 +578,10 @@ int vc4_hvs_atomic_check(struct drm_crtc *crtc, - /* 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. */ -@@ -356,7 +593,7 @@ int vc4_hvs_atomic_check(struct drm_crtc *crtc, - if (ret) - return ret; - -- return 0; -+ return vc4_hvs_gamma_check(crtc, state); - } - - static void vc4_hvs_update_dlist(struct drm_crtc *crtc) -@@ -365,17 +602,16 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc) - struct vc4_dev *vc4 = to_vc4_dev(dev); - struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); - struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); -+ unsigned long flags; - - if (crtc->state->event) { -- unsigned long flags; -- - crtc->state->event->pipe = drm_crtc_index(crtc); - - WARN_ON(drm_crtc_vblank_get(crtc) != 0); - - spin_lock_irqsave(&dev->event_lock, flags); - -- if (!vc4_state->feed_txp || vc4_state->txp_armed) { -+ if (!vc4_crtc->feeds_txp || vc4_state->txp_armed) { - vc4_crtc->event = crtc->state->event; - crtc->state->event = NULL; - } -@@ -388,25 +624,42 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc) - HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel), - vc4_state->mm.start); - } ++ const struct drm_format_info *info = state->fb->format; + -+ spin_lock_irqsave(&vc4_crtc->irq_lock, flags); -+ vc4_crtc->current_dlist = vc4_state->mm.start; -+ spin_unlock_irqrestore(&vc4_crtc->irq_lock, flags); ++ if (info->hsub > 1) ++ return max(vc4_lbm_channel_size(state, 0), ++ vc4_lbm_channel_size(state, 1)); ++ else ++ return vc4_lbm_channel_size(state, 0); +} + -+void vc4_hvs_atomic_begin(struct drm_crtc *crtc, -+ struct drm_atomic_state *state) ++u32 vc4_lbm_size(struct drm_plane_state *state) +{ -+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); -+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); -+ unsigned long flags; ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); + -+ spin_lock_irqsave(&vc4_crtc->irq_lock, flags); -+ vc4_crtc->current_hvs_channel = vc4_state->assigned_channel; -+ spin_unlock_irqrestore(&vc4_crtc->irq_lock, flags); - } - - 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_display_mode *mode = &crtc->state->adjusted_mode; -- bool oneshot = vc4_state->feed_txp; -+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); -+ bool oneshot = vc4_crtc->feeds_txp; - - vc4_hvs_update_dlist(crtc); - vc4_hvs_init_channel(vc4, crtc, mode, oneshot); - } - - 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; - -@@ -414,8 +667,10 @@ void vc4_hvs_atomic_disable(struct drm_crtc *crtc, - } - - 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); -@@ -477,14 +732,25 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, - u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel)); - - if (crtc->state->gamma_lut) { -- vc4_hvs_update_gamma_lut(crtc); -- dispbkgndx |= SCALER_DISPBKGND_GAMMA; -+ if (!vc4->hvs->hvs5) { -+ vc4_hvs_update_gamma_lut(crtc); -+ dispbkgndx |= SCALER_DISPBKGND_GAMMA; -+ } else { -+ vc5_hvs_update_gamma_lut(crtc); -+ } - } else { - /* Unsetting DISPBKGND_GAMMA skips the gamma lut step - * in hardware, which is the same as a linear lut that - * DRM expects us to use in absence of a user lut. -+ * -+ * Do NOT change state dynamically for hvs5 as it -+ * inserts a delay in the pipeline that will cause -+ * stalls if enabled/disabled whilst running. The other -+ * should already be disabling/enabling the pipeline -+ * when gamma changes. - */ -- dispbkgndx &= ~SCALER_DISPBKGND_GAMMA; -+ if (!vc4->hvs->hvs5) -+ dispbkgndx &= ~SCALER_DISPBKGND_GAMMA; - } - HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel), dispbkgndx); - } -@@ -671,6 +937,11 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) - 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); -+ if (hvs->hvs5) -+ vc4_debugfs_add_file(drm, "hvs_gamma", vc5_hvs_debugfs_gamma, -+ NULL); - - return 0; - } -diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c -index ba310c0ab5f6..422f2c211abd 100644 ---- a/drivers/gpu/drm/vc4/vc4_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_kms.c -@@ -40,6 +40,9 @@ static struct vc4_ctm_state *to_vc4_ctm_state(struct drm_private_state *priv) - struct vc4_hvs_state { - struct drm_private_state base; - unsigned int unassigned_channels; -+ unsigned int num_outputs; -+ unsigned long fifo_load; -+ unsigned long core_clock_rate; - }; - - static struct vc4_hvs_state * -@@ -154,6 +157,9 @@ vc4_ctm_commit(struct vc4_dev *vc4, struct drm_atomic_state *state) - 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; ++ /* LBM is not needed when there's no vertical scaling. */ ++ if (vc4_state->y_scaling0 == VC4_SCALING_NONE && ++ vc4_state->y_scaling1 == VC4_SCALING_NONE) ++ return 0; + - if (ctm_state->fifo) { - HVS_WRITE(SCALER_OLEDCOEF2, - VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix0), -@@ -182,6 +188,19 @@ vc4_ctm_commit(struct vc4_dev *vc4, struct drm_atomic_state *state) - VC4_SET_FIELD(ctm_state->fifo, SCALER_OLEDOFFS_DISPFIFO)); - } - -+static struct vc4_hvs_state * -+vc4_hvs_get_new_global_state(struct drm_atomic_state *state) ++ if (vc4->gen >= VC4_GEN_6) ++ return __vc6_lbm_size(state); ++ else ++ return __vc4_lbm_size(state); ++} ++ ++static size_t vc6_upm_size(const struct drm_plane_state *state, ++ unsigned int plane) +{ -+ struct vc4_dev *vc4 = to_vc4_dev(state->dev); -+ struct drm_private_state *priv_state; ++ const struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ unsigned int stride = state->fb->pitchesplane; + -+ priv_state = drm_atomic_get_new_private_obj_state(state, &vc4->hvs_channels); -+ if (IS_ERR(priv_state)) -+ return ERR_CAST(priv_state); ++ /* ++ * TODO: This only works for raster formats, and is sub-optimal ++ * for buffers with a stride aligned on 32 bytes. ++ */ ++ unsigned int words_per_line = (stride + 62) / 32; ++ unsigned int fetch_region_size = words_per_line * 32; ++ unsigned int buffer_lines = 2 << vc4_state->upm_buffer_lines; ++ unsigned int buffer_size = fetch_region_size * buffer_lines; + -+ return to_vc4_hvs_state(priv_state); ++ return ALIGN(buffer_size, HVS_UBM_WORD_SIZE); +} + - static struct vc4_hvs_state * - vc4_hvs_get_global_state(struct drm_atomic_state *state) + static void vc4_write_scaling_parameters(struct drm_plane_state *state, + int channel) { -@@ -203,6 +222,7 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4, - unsigned int i; - - for_each_new_crtc_in_state(state, crtc, crtc_state, i) { -+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); - struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); - u32 dispctrl; - u32 dsp3_mux; -@@ -223,7 +243,7 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4, - * TXP IP, and we need to disable the FIFO2 -> pixelvalve1 - * route. - */ -- if (vc4_state->feed_txp) -+ if (vc4_crtc->feeds_txp) - dsp3_mux = VC4_SET_FIELD(3, SCALER_DISPCTRL_DSP3_MUX); - else - dsp3_mux = VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX); -@@ -309,21 +329,44 @@ vc4_atomic_complete_commit(struct drm_atomic_state *state) - struct vc4_dev *vc4 = to_vc4_dev(dev); - struct vc4_hvs *hvs = vc4->hvs; - struct drm_crtc_state *new_crtc_state; -+ struct vc4_hvs_state *hvs_state; - struct drm_crtc *crtc; -+ struct clk_request *core_req; - int i; ++ struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); -+ hvs_state = vc4_hvs_get_new_global_state(state); -+ if (WARN_ON(!hvs_state)) -+ return; ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_6); + - 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); + /* Ch0 H-PPF Word 0: Scaling Parameters */ + if (vc4_state->x_scalingchannel == VC4_SCALING_PPF) { + vc4_write_ppf(vc4_state, +- vc4_state->src_wchannel, vc4_state->crtc_w); ++ vc4_state->src_wchannel, vc4_state->crtc_w, vc4_state->src_x, channel, ++ state->chroma_siting_h); + } + + /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */ + if (vc4_state->y_scalingchannel == VC4_SCALING_PPF) { + vc4_write_ppf(vc4_state, +- vc4_state->src_hchannel, vc4_state->crtc_h); ++ vc4_state->src_hchannel, vc4_state->crtc_h, vc4_state->src_y, channel, ++ state->chroma_siting_v); + vc4_dlist_write(vc4_state, 0xc0c0c0c0); + } + +@@ -660,7 +865,8 @@ static void vc4_plane_calc_load(struct drm_plane_state *state) + for (i = 0; i < fb->format->num_planes; i++) { + /* Even if the bandwidth/plane required for a single frame is + * +- * vc4_state->src_wi * vc4_state->src_hi * cpp * vrefresh ++ * (vc4_state->src_wi >> 16) * (vc4_state->src_hi >> 16) * ++ * cpp * vrefresh + * + * when downscaling, we have to read more pixels per line in + * the time frame reserved for a single line, so the bandwidth +@@ -669,11 +875,11 @@ static void vc4_plane_calc_load(struct drm_plane_state *state) + * load by this number. We're likely over-estimating the read + * demand, but that's better than under-estimating it. + */ +- vscale_factor = DIV_ROUND_UP(vc4_state->src_hi, ++ vscale_factor = DIV_ROUND_UP(vc4_state->src_hi >> 16, + vc4_state->crtc_h); +- vc4_state->membus_load += vc4_state->src_wi * +- vc4_state->src_hi * vscale_factor * +- fb->format->cppi; ++ vc4_state->membus_load += (vc4_state->src_wi >> 16) * ++ (vc4_state->src_hi >> 16) * ++ vscale_factor * fb->format->cppi; + vc4_state->hvs_load += vc4_state->crtc_h * vc4_state->crtc_w; } -- 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, -+ hvs_state->core_clock_rate); -+ -+ drm_dbg(dev, "Raising the core clock at %lu Hz\n", core_rate); -+ -+ /* -+ * 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); -+ } - - drm_atomic_helper_wait_for_fences(dev, state, false); +@@ -684,39 +890,88 @@ static void vc4_plane_calc_load(struct drm_plane_state *state) -@@ -333,10 +376,12 @@ vc4_atomic_complete_commit(struct drm_atomic_state *state) - - vc4_ctm_commit(vc4, state); + static int vc4_plane_allocate_lbm(struct drm_plane_state *state) + { +- struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); ++ struct drm_device *drm = state->plane->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct drm_plane *plane = state->plane; + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); +- unsigned long irqflags; + u32 lbm_size; -- 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); + lbm_size = vc4_lbm_size(state); +- if (!lbm_size) ++ if (!lbm_size) { ++ vc4_state->lbm_size = 0; + return 0; + } - - drm_atomic_helper_commit_planes(dev, state, 0); - -@@ -352,8 +397,20 @@ vc4_atomic_complete_commit(struct drm_atomic_state *state) - - drm_atomic_helper_commit_cleanup_done(state); - -- if (vc4->hvs->hvs5) -- clk_set_min_rate(hvs->core_clk, 0); -+ if (vc4->hvs && vc4->hvs->hvs5) { -+ drm_dbg(dev, "Running the core clock at %lu Hz\n", -+ hvs_state->core_clock_rate); + -+ /* -+ * Request a clock rate based on the current HVS -+ * requirements. -+ */ -+ hvs->core_req = clk_request_start(hvs->core_clk, -+ hvs_state->core_clock_rate); ++ /* ++ * NOTE: BCM2712 doesn't need to be aligned, since the size ++ * returned by vc4_lbm_size() is in words already. ++ */ ++ if (vc4->gen == VC4_GEN_5) ++ lbm_size = ALIGN(lbm_size, 64); ++ else if (vc4->gen == VC4_GEN_4) ++ lbm_size = ALIGN(lbm_size, 32); + -+ /* And drop the temporary request */ -+ clk_request_done(core_req); -+ } ++ drm_dbg_driver(drm, "PLANE:%d:%s LBM Allocation Size: %u\n", ++ plane->base.id, plane->name, lbm_size); - drm_atomic_state_put(state); + if (WARN_ON(!vc4_state->lbm_offset)) + return -EINVAL; -@@ -413,7 +470,8 @@ static int vc4_atomic_commit(struct drm_device *dev, - * drm_atomic_helper_setup_commit() from auto-completing - * commit->flip_done. +- /* Allocate the LBM memory that the HVS will use for temporary +- * storage due to our scaling/format conversion. ++ /* FIXME: Add loop here that ensures that the total LBM assigned in this ++ * state is less than the total lbm size */ -- state->legacy_cursor_update = false; -+ if (!vc4->firmware_kms) -+ state->legacy_cursor_update = false; - ret = drm_atomic_helper_setup_commit(state, nonblock); - if (ret) - return ret; -@@ -591,9 +649,6 @@ static int vc4_load_tracker_atomic_check(struct drm_atomic_state *state) - 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)) -@@ -668,9 +723,6 @@ static void vc4_load_tracker_obj_fini(struct drm_device *dev, void *unused) - { - struct vc4_dev *vc4 = to_vc4_dev(dev); - -- if (!vc4->load_tracker_available) -- return; +- if (!drm_mm_node_allocated(&vc4_state->lbm)) { +- int ret; - - drm_atomic_private_obj_fini(&vc4->load_tracker); - } - -@@ -678,9 +730,6 @@ static int vc4_load_tracker_obj_init(struct vc4_dev *vc4) - { - 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; -@@ -705,6 +754,9 @@ vc4_hvs_channels_duplicate_state(struct drm_private_obj *obj) - __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); - - state->unassigned_channels = old_state->unassigned_channels; -+ state->fifo_load = old_state->fifo_load; -+ state->num_outputs = old_state->num_outputs; -+ state->core_clock_rate = old_state->core_clock_rate; - - return &state->base; - } -@@ -778,6 +830,7 @@ static int vc4_hvs_channels_obj_init(struct vc4_dev *vc4) - 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; -@@ -794,6 +847,10 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev, - 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) -@@ -834,19 +891,76 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev, - * 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 { -+ if (!matching_channels) - return -EINVAL; -+ -+ channel = ffs(matching_channels) - 1; -+ new_vc4_crtc_state->assigned_channel = channel; -+ hvs_new_state->unassigned_channels &= ~BIT(channel); -+ } +- spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); +- ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, +- &vc4_state->lbm, +- lbm_size, +- vc4->is_vc5 ? 64 : 32, ++ vc4_state->lbm_size = lbm_size; + + return 0; +} + -+static int -+vc4_core_clock_atomic_check(struct drm_atomic_state *state) ++static int vc6_plane_allocate_upm(struct drm_plane_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 long pixel_rate; -+ unsigned long cob_rate; ++ const struct drm_format_info *info = state->fb->format; ++ struct drm_device *drm = state->plane->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_hvs *hvs = vc4->hvs; ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + unsigned int i; ++ int ret; + -+ priv_state = drm_atomic_get_private_obj_state(state, -+ &vc4->load_tracker); -+ if (IS_ERR(priv_state)) -+ return PTR_ERR(priv_state); ++ WARN_ON_ONCE(vc4->gen < VC4_GEN_6); + -+ load_state = to_vc4_load_tracker_state(priv_state); ++ vc4_state->upm_buffer_lines = SCALER6_PTR0_UPM_BUFF_SIZE_2_LINES; + -+ hvs_new_state = vc4_hvs_get_global_state(state); -+ if (!hvs_new_state) -+ return -EINVAL; ++ for (i = 0; i < info->num_planes; i++) { ++ unsigned long irqflags; ++ size_t upm_size; + -+ 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); ++ upm_size = vc6_upm_size(state, i); ++ if (!upm_size) ++ return -EINVAL; + -+ hvs_new_state->num_outputs -= 1; -+ hvs_new_state->fifo_load -= old_vc4_state->hvs_load; ++ spin_lock_irqsave(&hvs->mm_lock, irqflags); ++ ret = drm_mm_insert_node_generic(&hvs->upm_mm, ++ &vc4_state->upmi, ++ upm_size, HVS_UBM_WORD_SIZE, + 0, 0); +- spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); ++ spin_unlock_irqrestore(&hvs->mm_lock, irqflags); ++ if (ret) { ++ drm_err(drm, "Failed to allocate UPM entry: %d\n", ret); ++ return ret; + } + +- if (ret) ++ ret = ida_alloc_range(&hvs->upm_handles, 1, 32, GFP_KERNEL); ++ if (ret < 0) + return ret; +- } else { +- WARN_ON_ONCE(lbm_size != vc4_state->lbm.size); +- } + +- vc4_state->dlistvc4_state->lbm_offset = vc4_state->lbm.start; ++ vc4_state->upm_handlei = ret; + -+ if (new_crtc_state->active) { -+ struct vc4_crtc_state *new_vc4_state = -+ to_vc4_crtc_state(new_crtc_state); ++ vc4_state->dlistvc4_state->ptr0_offseti |= ++ VC4_SET_FIELD(vc4_state->upmi.start / HVS_UBM_WORD_SIZE, ++ SCALER6_PTR0_UPM_BASE) | ++ VC4_SET_FIELD(vc4_state->upm_handlei - 1, ++ SCALER6_PTR0_UPM_HANDLE) | ++ VC4_SET_FIELD(vc4_state->upm_buffer_lines, ++ SCALER6_PTR0_UPM_BUFF_SIZE); ++ } + + return 0; + } +@@ -768,6 +1023,11 @@ static const u32 colorspace_coeffs2DRM_COLOR_ENCODING_MAX3 = { + + static u32 vc4_hvs4_get_alpha_blend_mode(struct drm_plane_state *state) + { ++ struct drm_device *dev = state->state->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); + -+ hvs_new_state->num_outputs += 1; -+ hvs_new_state->fifo_load += new_vc4_state->hvs_load; - } - } ++ WARN_ON_ONCE(vc4->gen != VC4_GEN_4); ++ + if (!state->fb->format->has_alpha) + return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_FIXED, + SCALER_POS2_ALPHA_MODE); +@@ -789,6 +1049,17 @@ static u32 vc4_hvs4_get_alpha_blend_mode(struct drm_plane_state *state) -+ cob_rate = hvs_new_state->fifo_load; -+ pixel_rate = load_state->hvs_load; -+ if (hvs_new_state->num_outputs > 1) { -+ pixel_rate = (pixel_rate * 40) / 100; -+ } else { -+ pixel_rate = (pixel_rate * 60) / 100; + static u32 vc4_hvs5_get_alpha_blend_mode(struct drm_plane_state *state) + { ++ struct drm_device *dev = state->state->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ WARN_ON_ONCE(vc4->gen != VC4_GEN_5 && vc4->gen != VC4_GEN_6); ++ ++ if (vc4->gen == VC4_GEN_6 && vc4->step_d0) { ++ return state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI ? ++ SCALER5_CTL2_ALPHA_PREMULT : 0; + } + -+ hvs_new_state->core_clock_rate = max(cob_rate, pixel_rate); + - return 0; + if (!state->fb->format->has_alpha) + return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_FIXED, + SCALER5_CTL2_ALPHA_MODE); +@@ -808,6 +1079,21 @@ static u32 vc4_hvs5_get_alpha_blend_mode(struct drm_plane_state *state) + } } ++static u32 vc4_hvs6_get_alpha_mask_mode(struct drm_plane_state *state) ++{ ++ struct drm_device *dev = state->state->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); + - static int - vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) - { -@@ -864,7 +978,11 @@ vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) ++ WARN_ON_ONCE(vc4->gen != VC4_GEN_6); ++ ++ if (vc4->step_d0 && (!state->fb->format->has_alpha || ++ state->pixel_blend_mode == DRM_MODE_BLEND_PIXEL_NONE)) ++ return VC4_SET_FIELD(SCALER6_CTL0_ALPHA_MASK_FIXED, ++ SCALER6_CTL0_ALPHA_MASK); ++ ++ return VC4_SET_FIELD(SCALER6_CTL0_ALPHA_MASK_NONE, SCALER6_CTL0_ALPHA_MASK); ++} ++ + /* Writes out a full display list for an active plane to the plane's + * private dlist state. + */ +@@ -826,9 +1112,11 @@ static int vc4_plane_mode_set(struct drm_plane *plane, + bool mix_plane_alpha; + bool covers_screen; + u32 scl0, scl1, pitch0; +- u32 tiling, src_y; ++ u32 tiling, src_x, src_y; ++ u32 width, height; + u32 hvs_format = format->hvs; + unsigned int rotation; ++ u32 offsets3 = { 0 }; + int ret, i; + + if (vc4_state->dlist_initialized) +@@ -838,6 +1126,15 @@ static int vc4_plane_mode_set(struct drm_plane *plane, if (ret) return ret; -- return vc4_load_tracker_atomic_check(state); -+ ret = vc4_load_tracker_atomic_check(state); -+ if (ret) -+ return ret; ++ width = vc4_state->src_w0 >> 16; ++ height = vc4_state->src_h0 >> 16; + -+ return vc4_core_clock_atomic_check(state); - } ++ if (!width || !height || !vc4_state->crtc_w || !vc4_state->crtc_h) { ++ /* 0 source size probably means the plane is offscreen */ ++ vc4_state->dlist_initialized = 1; ++ return 0; ++ } ++ + /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB + * and 4:4:4, scl1 should be set to scl0 so both channels of + * the scaler do the same thing. For YUV, the Y plane needs +@@ -858,9 +1155,11 @@ static int vc4_plane_mode_set(struct drm_plane *plane, + DRM_MODE_REFLECT_Y); - static const struct drm_mode_config_funcs vc4_mode_funcs = { -@@ -880,9 +998,12 @@ int vc4_kms_load(struct drm_device *dev) - "brcm,bcm2711-vc5"); - int ret; + /* We must point to the last line when Y reflection is enabled. */ +- src_y = vc4_state->src_y; ++ src_y = vc4_state->src_y >> 16; + if (rotation & DRM_MODE_REFLECT_Y) +- src_y += vc4_state->src_h0 - 1; ++ src_y += height - 1; ++ ++ src_x = vc4_state->src_x >> 16; -+ /* -+ * 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; + switch (base_format_mod) { + case DRM_FORMAT_MOD_LINEAR: +@@ -871,13 +1170,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane, + * out. + */ + for (i = 0; i < num_planes; i++) { +- vc4_state->offsetsi += src_y / +- (i ? v_subsample : 1) * +- fb->pitchesi; - - /* Start with the load tracker enabled. Can be - * disabled through the debugfs load_tracker file. +- vc4_state->offsetsi += vc4_state->src_x / +- (i ? h_subsample : 1) * +- fb->format->cppi; ++ offsetsi += src_y / (i ? v_subsample : 1) * fb->pitchesi; ++ offsetsi += src_x / (i ? h_subsample : 1) * fb->format->cppi; + } + + break; +@@ -898,7 +1192,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, + * pitch * tile_h == tile_size * tiles_per_row */ -@@ -913,6 +1034,8 @@ int vc4_kms_load(struct drm_device *dev) - 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; + u32 tiles_w = fb->pitches0 >> (tile_size_shift - tile_h_shift); +- u32 tiles_l = vc4_state->src_x >> tile_w_shift; ++ u32 tiles_l = src_x >> tile_w_shift; + u32 tiles_r = tiles_w - tiles_l; + u32 tiles_t = src_y >> tile_h_shift; + /* Intra-tile offsets, which modify the base address (the +@@ -908,7 +1202,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, + u32 tile_y = (src_y >> 4) & 1; + u32 subtile_y = (src_y >> 2) & 3; + u32 utile_y = src_y & 3; +- u32 x_off = vc4_state->src_x & tile_w_mask; ++ u32 x_off = src_x & tile_w_mask; + u32 y_off = src_y & tile_h_mask; + + /* When Y reflection is requested we must set the +@@ -932,19 +1226,18 @@ static int vc4_plane_mode_set(struct drm_plane *plane, + VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) | + VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) | + VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R)); +- vc4_state->offsets0 += tiles_t * (tiles_w << tile_size_shift); +- vc4_state->offsets0 += subtile_y << 8; +- vc4_state->offsets0 += utile_y << 4; ++ offsets0 += tiles_t * (tiles_w << tile_size_shift); ++ offsets0 += subtile_y << 8; ++ offsets0 += utile_y << 4; + + /* Rows of tiles alternate left-to-right and right-to-left. */ + if (tiles_t & 1) { + pitch0 |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR; +- vc4_state->offsets0 += (tiles_w - tiles_l) << +- tile_size_shift; +- vc4_state->offsets0 -= (1 + !tile_y) << 10; ++ offsets0 += (tiles_w - tiles_l) << tile_size_shift; ++ offsets0 -= (1 + !tile_y) << 10; + } else { +- vc4_state->offsets0 += tiles_l << tile_size_shift; +- vc4_state->offsets0 += tile_y << 10; ++ offsets0 += tiles_l << tile_size_shift; ++ offsets0 += tile_y << 10; + } - ret = vc4_ctm_obj_init(vc4); - if (ret) -diff --git a/drivers/gpu/drm/vc4/vc4_perfmon.c b/drivers/gpu/drm/vc4/vc4_perfmon.c -index f4aa75efd16b..18abc06335c1 100644 ---- a/drivers/gpu/drm/vc4/vc4_perfmon.c -+++ b/drivers/gpu/drm/vc4/vc4_perfmon.c -@@ -77,7 +77,7 @@ struct vc4_perfmon *vc4_perfmon_find(struct vc4_file *vc4file, int id) - 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); - } + break; +@@ -1004,7 +1297,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, + * 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 remaining_pixels = src_x % 96; + u32 aligned = remaining_pixels / 12; + u32 last_bits = remaining_pixels % 12; + +@@ -1026,18 +1319,16 @@ static int vc4_plane_mode_set(struct drm_plane *plane, + return -EINVAL; + } + pix_per_tile = tile_w / fb->format->cpp0; +- x_off = (vc4_state->src_x % pix_per_tile) / ++ x_off = (src_x % pix_per_tile) / + (i ? h_subsample : 1) * + fb->format->cppi; + } - static int vc4_perfmon_idr_del(int id, void *elem, void *data) -diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c -index af4b8944a603..766280a844f4 100644 ---- a/drivers/gpu/drm/vc4/vc4_plane.c -+++ b/drivers/gpu/drm/vc4/vc4_plane.c -@@ -33,6 +33,7 @@ static const struct hvs_format { - u32 hvs; /* HVS_FORMAT_* */ - u32 pixel_order; - u32 pixel_order_hvs5; -+ bool hvs5_only; - } hvs_formats = { - { - .drm = DRM_FORMAT_XRGB8888, -@@ -128,6 +129,40 @@ static const struct hvs_format { - .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, -+ }, -+ { -+ .drm = DRM_FORMAT_XRGB2101010, -+ .hvs = HVS_PIXEL_FORMAT_RGBA1010102, -+ .pixel_order = HVS_PIXEL_ORDER_ABGR, -+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB, -+ .hvs5_only = true, -+ }, -+ { -+ .drm = DRM_FORMAT_ARGB2101010, -+ .hvs = HVS_PIXEL_FORMAT_RGBA1010102, -+ .pixel_order = HVS_PIXEL_ORDER_ABGR, -+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB, -+ .hvs5_only = true, -+ }, -+ { -+ .drm = DRM_FORMAT_ABGR2101010, -+ .hvs = HVS_PIXEL_FORMAT_RGBA1010102, -+ .pixel_order = HVS_PIXEL_ORDER_ARGB, -+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR, -+ .hvs5_only = true, -+ }, -+ { -+ .drm = DRM_FORMAT_XBGR2101010, -+ .hvs = HVS_PIXEL_FORMAT_RGBA1010102, -+ .pixel_order = HVS_PIXEL_ORDER_ARGB, -+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR, -+ .hvs5_only = true, -+ }, - }; +- tile = vc4_state->src_x / pix_per_tile; ++ tile = src_x / pix_per_tile; - static const struct hvs_format *vc4_get_hvs_format(u32 drm_format) -@@ -303,16 +338,16 @@ static int vc4_plane_margins_adj(struct drm_plane_state *pstate) - 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, -@@ -332,7 +367,6 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) - 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; -@@ -354,18 +388,14 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) - for (i = 0; i < num_planes; i++) - vc4_state->offsetsi = bo->paddr + fb->offsetsi; +- vc4_state->offsetsi += param * tile_w * tile; +- vc4_state->offsetsi += src_y / +- (i ? v_subsample : 1) * +- tile_w; +- vc4_state->offsetsi += x_off & ~(i ? 1 : 0); ++ offsetsi += param * tile_w * tile; ++ offsetsi += src_y / (i ? v_subsample : 1) * tile_w; ++ offsetsi += x_off & ~(i ? 1 : 0); + } -- /* 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_w0 = (state->src.x2 - state->src.x1) >> 16; -- vc4_state->src_h0 = (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_w0 = DIV_ROUND_CLOSEST(state->src.x2, 1<<16) - vc4_state->src_x; -+ vc4_state->src_h0 = DIV_ROUND_CLOSEST(state->src.y2, 1<<16) - vc4_state->src_y; + pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT); +@@ -1050,6 +1341,28 @@ static int vc4_plane_mode_set(struct drm_plane *plane, + return -EINVAL; + } - vc4_state->crtc_x = state->dst.x1; - vc4_state->crtc_y = state->dst.y1; -@@ -532,9 +562,6 @@ static void vc4_plane_calc_load(struct drm_plane_state *state) - struct vc4_dev *vc4; ++ /* fetch an extra pixel if we don't actually line up with the left edge. */ ++ if ((vc4_state->src_x & 0xffff) && vc4_state->src_x < (state->fb->width << 16)) ++ width++; ++ ++ /* same for the right side */ ++ if (((vc4_state->src_x + vc4_state->src_w0) & 0xffff) && ++ vc4_state->src_x + vc4_state->src_w0 < (state->fb->width << 16)) ++ width++; ++ ++ /* now for the top */ ++ if ((vc4_state->src_y & 0xffff) && vc4_state->src_y < (state->fb->height << 16)) ++ height++; ++ ++ /* and the bottom */ ++ if (((vc4_state->src_y + vc4_state->src_h0) & 0xffff) && ++ vc4_state->src_y + vc4_state->src_h0 < (state->fb->height << 16)) ++ height++; ++ ++ /* for YUV444 hardware wants double the width, otherwise it doesn't fetch full width of chroma */ ++ if (format->drm == DRM_FORMAT_YUV444 || format->drm == DRM_FORMAT_YVU444) ++ width <<= 1; ++ + /* Don't waste cycles mixing with plane alpha if the set alpha + * is opaque or there is no per-pixel alpha information. + * In any case we use the alpha property value as the fixed alpha. +@@ -1057,7 +1370,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, + mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE && + fb->format->has_alpha; + +- if (!vc4->is_vc5) { ++ if (vc4->gen == VC4_GEN_4) { + /* Control word */ + vc4_dlist_write(vc4_state, + SCALER_CTL0_VALID | +@@ -1092,10 +1405,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane, + vc4_dlist_write(vc4_state, + (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) | + vc4_hvs4_get_alpha_blend_mode(state) | +- VC4_SET_FIELD(vc4_state->src_w0, +- SCALER_POS2_WIDTH) | +- VC4_SET_FIELD(vc4_state->src_h0, +- SCALER_POS2_HEIGHT)); ++ VC4_SET_FIELD(width, SCALER_POS2_WIDTH) | ++ VC4_SET_FIELD(height, SCALER_POS2_HEIGHT)); + + /* Position Word 3: Context. Written by the HVS. */ + vc4_dlist_write(vc4_state, 0xc0c0c0c0); +@@ -1148,10 +1459,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane, + /* Position Word 2: Source Image Size */ + vc4_state->pos2_offset = vc4_state->dlist_count; + vc4_dlist_write(vc4_state, +- VC4_SET_FIELD(vc4_state->src_w0, +- SCALER5_POS2_WIDTH) | +- VC4_SET_FIELD(vc4_state->src_h0, +- SCALER5_POS2_HEIGHT)); ++ VC4_SET_FIELD(width, SCALER5_POS2_WIDTH) | ++ VC4_SET_FIELD(height, SCALER5_POS2_HEIGHT)); + + /* Position Word 3: Context. Written by the HVS. */ + vc4_dlist_write(vc4_state, 0xc0c0c0c0); +@@ -1162,9 +1471,13 @@ static int vc4_plane_mode_set(struct drm_plane *plane, + * + * The pointers may be any byte address. + */ +- vc4_state->ptr0_offset = vc4_state->dlist_count; +- for (i = 0; i < num_planes; i++) +- vc4_dlist_write(vc4_state, vc4_state->offsetsi); ++ vc4_state->ptr0_offset0 = vc4_state->dlist_count; ++ ++ for (i = 0; i < num_planes; i++) { ++ struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, i); ++ ++ vc4_dlist_write(vc4_state, bo->dma_addr + fb->offsetsi + offsetsi); ++ } - 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); -@@ -621,6 +648,95 @@ static int vc4_plane_allocate_lbm(struct drm_plane_state *state) + /* Pointer Context Word 0/1/2: Written by the HVS */ + for (i = 0; i < num_planes; i++) +@@ -1274,6 +1587,426 @@ static int vc4_plane_mode_set(struct drm_plane *plane, 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 u32 vc6_plane_get_csc_mode(struct vc4_plane_state *vc4_state) ++{ ++ struct drm_plane_state *state = &vc4_state->base; ++ struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); ++ u32 ret = 0; + -+static const u32 colorspace_coeffs2DRM_COLOR_ENCODING_MAX3 = { -+ { -+ /* 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, -+ } -+ } -+}; ++ if (vc4_state->is_yuv) { ++ enum drm_color_encoding color_encoding = state->color_encoding; ++ enum drm_color_range color_range = state->color_range; + -+static u32 vc4_hvs4_get_alpha_blend_mode(struct drm_plane_state *state) -+{ -+ if (!state->fb->format->has_alpha) -+ return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_FIXED, -+ SCALER_POS2_ALPHA_MODE); ++ /* CSC pre-loaded with: ++ * 0 = BT601 limited range ++ * 1 = BT709 limited range ++ * 2 = BT2020 limited range ++ * 3 = BT601 full range ++ * 4 = BT709 full range ++ * 5 = BT2020 full range ++ */ ++ if (color_encoding > DRM_COLOR_YCBCR_BT2020) ++ color_encoding = DRM_COLOR_YCBCR_BT601; ++ if (color_range > DRM_COLOR_YCBCR_FULL_RANGE) ++ color_range = DRM_COLOR_YCBCR_LIMITED_RANGE; + -+ switch (state->pixel_blend_mode) { -+ case DRM_MODE_BLEND_PIXEL_NONE: -+ return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_FIXED, -+ SCALER_POS2_ALPHA_MODE); -+ default: -+ case DRM_MODE_BLEND_PREMULTI: -+ return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_PIPELINE, -+ SCALER_POS2_ALPHA_MODE) | -+ SCALER_POS2_ALPHA_PREMULT; -+ case DRM_MODE_BLEND_COVERAGE: -+ return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_PIPELINE, -+ SCALER_POS2_ALPHA_MODE); ++ if (vc4->step_d0) { ++ ret |= SCALER6D0_CTL2_CSC_ENABLE; ++ ret |= VC4_SET_FIELD(color_encoding + (color_range * 3), ++ SCALER6D0_CTL2_BRCM_CFC_CONTROL); ++ } else { ++ ret |= SCALER6_CTL2_CSC_ENABLE; ++ ret |= VC4_SET_FIELD(color_encoding + (color_range * 3), ++ SCALER6_CTL2_BRCM_CFC_CONTROL); ++ } + } ++ ++ return ret; +} + -+static u32 vc4_hvs5_get_alpha_blend_mode(struct drm_plane_state *state) ++static int vc6_plane_mode_set(struct drm_plane *plane, ++ struct drm_plane_state *state) +{ -+ if (!state->fb->format->has_alpha) -+ return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_FIXED, -+ SCALER5_CTL2_ALPHA_MODE); ++ struct drm_device *drm = plane->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ struct drm_framebuffer *fb = state->fb; ++ const struct hvs_format *format = vc4_get_hvs_format(fb->format->format); ++ u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier); ++ int num_planes = fb->format->num_planes; ++ u32 h_subsample = fb->format->hsub; ++ u32 v_subsample = fb->format->vsub; ++ bool mix_plane_alpha; ++ bool covers_screen; ++ u32 scl0, scl1, pitch0; ++ u32 tiling, src_x, src_y; ++ u32 width, height; ++ u32 hvs_format = format->hvs; ++ u32 offsets3 = { 0 }; ++ unsigned int rotation; ++ int ret, i; + -+ switch (state->pixel_blend_mode) { -+ case DRM_MODE_BLEND_PIXEL_NONE: -+ return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_FIXED, -+ SCALER5_CTL2_ALPHA_MODE); -+ default: -+ case DRM_MODE_BLEND_PREMULTI: -+ return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_PIPELINE, -+ SCALER5_CTL2_ALPHA_MODE) | -+ SCALER5_CTL2_ALPHA_PREMULT; -+ case DRM_MODE_BLEND_COVERAGE: -+ return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_PIPELINE, -+ SCALER5_CTL2_ALPHA_MODE); ++ if (vc4_state->dlist_initialized) ++ return 0; ++ ++ ret = vc4_plane_setup_clipping_and_scaling(state); ++ if (ret) ++ return ret; ++ ++ width = vc4_state->src_w0 >> 16; ++ height = vc4_state->src_h0 >> 16; ++ ++ if (!width || !height || !vc4_state->crtc_w || !vc4_state->crtc_h) { ++ /* 0 source size probably means the plane is offscreen. ++ * 0 destination size is a redundant plane. ++ */ ++ vc4_state->dlist_initialized = 1; ++ return 0; + } -+} + - /* Writes out a full display list for an active plane to the plane's - * private dlist state. - */ -@@ -767,47 +883,90 @@ static int vc4_plane_mode_set(struct drm_plane *plane, - case DRM_FORMAT_MOD_BROADCOM_SAND128: - case DRM_FORMAT_MOD_BROADCOM_SAND256: { - uint32_t param = fourcc_mod_broadcom_param(fb->modifier); -- u32 tile_w, tile, x_off, pix_per_tile; -- -- 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; -- } - - if (param > SCALER_TILE_HEIGHT_MASK) { -- DRM_DEBUG_KMS("SAND height too large (%d)\n", param); ++ /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB ++ * and 4:4:4, scl1 should be set to scl0 so both channels of ++ * the scaler do the same thing. For YUV, the Y plane needs ++ * to be put in channel 1 and Cb/Cr in channel 0, so we swap ++ * the scl fields here. ++ */ ++ if (num_planes == 1) { ++ scl0 = vc4_get_scl_field(state, 0); ++ scl1 = scl0; ++ } else { ++ scl0 = vc4_get_scl_field(state, 1); ++ scl1 = vc4_get_scl_field(state, 0); ++ } ++ ++ rotation = drm_rotation_simplify(state->rotation, ++ DRM_MODE_ROTATE_0 | ++ DRM_MODE_REFLECT_X | ++ DRM_MODE_REFLECT_Y); ++ ++ /* We must point to the last line when Y reflection is enabled. */ ++ src_y = vc4_state->src_y >> 16; ++ if (rotation & DRM_MODE_REFLECT_Y) ++ src_y += height - 1; ++ ++ src_x = vc4_state->src_x >> 16; ++ ++ switch (base_format_mod) { ++ case DRM_FORMAT_MOD_LINEAR: ++ tiling = SCALER6_CTL0_ADDR_MODE_LINEAR; ++ ++ /* Adjust the base pointer to the first pixel to be scanned ++ * out. ++ */ ++ for (i = 0; i < num_planes; i++) { ++ offsetsi += src_y / (i ? v_subsample : 1) * fb->pitchesi; ++ offsetsi += src_x / (i ? h_subsample : 1) * fb->format->cppi; ++ } ++ ++ break; ++ ++ case DRM_FORMAT_MOD_BROADCOM_SAND128: ++ case DRM_FORMAT_MOD_BROADCOM_SAND256: { ++ uint32_t param = fourcc_mod_broadcom_param(fb->modifier); ++ u32 components_per_word; ++ u32 starting_offset; ++ u32 fetch_count; ++ ++ if (param > SCALER_TILE_HEIGHT_MASK) { + DRM_DEBUG_KMS("SAND height too large (%d)\n", + param); - return -EINVAL; - } - -- pix_per_tile = tile_w / fb->format->cpp0; -- tile = vc4_state->src_x / pix_per_tile; -- x_off = vc4_state->src_x % pix_per_tile; ++ return -EINVAL; ++ } ++ + if (fb->format->format == DRM_FORMAT_P030) { + hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT; -+ tiling = SCALER_CTL0_TILING_128B; ++ tiling = SCALER6_CTL0_ADDR_MODE_128B; + } else { -+ hvs_format = HVS_PIXEL_FORMAT_H264; ++ hvs_format = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE; + + switch (base_format_mod) { -+ case DRM_FORMAT_MOD_BROADCOM_SAND64: -+ tiling = SCALER_CTL0_TILING_64B; -+ break; + case DRM_FORMAT_MOD_BROADCOM_SAND128: -+ tiling = SCALER_CTL0_TILING_128B; ++ tiling = SCALER6_CTL0_ADDR_MODE_128B; + break; + case DRM_FORMAT_MOD_BROADCOM_SAND256: -+ tiling = SCALER_CTL0_TILING_256B_OR_T; ++ tiling = SCALER6_CTL0_ADDR_MODE_256B; + break; + default: + return -EINVAL; + } + } - - /* Adjust the base pointer to the first pixel to be scanned - * out. ++ ++ /* 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 @@ -66917,8 +95623,8 @@ + * 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++) { ++ */ ++ for (i = 0; i < num_planes; i++) { + u32 tile_w, tile, x_off, pix_per_tile; + + if (fb->format->format == DRM_FORMAT_P030) { @@ -66930,7 +95636,7 @@ + * 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 remaining_pixels = src_x % 96; + u32 aligned = remaining_pixels / 12; + u32 last_bits = remaining_pixels % 12; + @@ -66939,9 +95645,6 @@ + pix_per_tile = 96; + } else { + switch (base_format_mod) { -+ case DRM_FORMAT_MOD_BROADCOM_SAND64: -+ tile_w = 64; -+ break; + case DRM_FORMAT_MOD_BROADCOM_SAND128: + tile_w = 128; + break; @@ -66952,197 +95655,529 @@ + return -EINVAL; + } + pix_per_tile = tile_w / fb->format->cpp0; -+ x_off = (vc4_state->src_x % pix_per_tile) / ++ x_off = (src_x % pix_per_tile) / + (i ? h_subsample : 1) * + fb->format->cppi; + } + -+ tile = vc4_state->src_x / pix_per_tile; ++ tile = src_x / pix_per_tile; + - vc4_state->offsetsi += param * tile_w * tile; - vc4_state->offsetsi += src_y / - (i ? v_subsample : 1) * - tile_w; -- vc4_state->offsetsi += x_off / -- (i ? h_subsample : 1) * -- fb->format->cppi; -+ vc4_state->offsetsi += x_off & ~(i ? 1 : 0); - } - - pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT); -@@ -860,13 +1019,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane, - /* Position Word 2: Source Image Size, Alpha */ - vc4_state->pos2_offset = vc4_state->dlist_count; - vc4_dlist_write(vc4_state, -- VC4_SET_FIELD(fb->format->has_alpha ? -- SCALER_POS2_ALPHA_MODE_PIPELINE : -- SCALER_POS2_ALPHA_MODE_FIXED, -- SCALER_POS2_ALPHA_MODE) | - (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) | -- (fb->format->has_alpha ? -- SCALER_POS2_ALPHA_PREMULT : 0) | -+ vc4_hvs4_get_alpha_blend_mode(state) | - VC4_SET_FIELD(vc4_state->src_w0, - SCALER_POS2_WIDTH) | - VC4_SET_FIELD(vc4_state->src_h0, -@@ -911,14 +1065,9 @@ static int vc4_plane_mode_set(struct drm_plane *plane, - vc4_dlist_write(vc4_state, - VC4_SET_FIELD(state->alpha >> 4, - SCALER5_CTL2_ALPHA) | -- (fb->format->has_alpha ? -- SCALER5_CTL2_ALPHA_PREMULT : 0) | -+ vc4_hvs5_get_alpha_blend_mode(state) | - (mix_plane_alpha ? -- SCALER5_CTL2_ALPHA_MIX : 0) | -- VC4_SET_FIELD(fb->format->has_alpha ? -- SCALER5_CTL2_ALPHA_MODE_PIPELINE : -- SCALER5_CTL2_ALPHA_MODE_FIXED, -- SCALER5_CTL2_ALPHA_MODE) -+ SCALER5_CTL2_ALPHA_MIX : 0) - ); - - /* Position Word 1: Scaled Image Dimensions. */ -@@ -960,7 +1109,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane, - - /* 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->pitchesi, - SCALER_SRC_PITCH)); -@@ -971,9 +1121,20 @@ static int vc4_plane_mode_set(struct drm_plane *plane, - - /* 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; ++ offsetsi += param * tile_w * tile; ++ offsetsi += src_y / (i ? v_subsample : 1) * tile_w; ++ offsetsi += x_off & ~(i ? 1 : 0); ++ } + -+ 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; ++ components_per_word = fb->format->format == DRM_FORMAT_P030 ? 24 : 32; ++ starting_offset = src_x % components_per_word; ++ fetch_count = (width + starting_offset + components_per_word - 1) / ++ components_per_word; ++ ++ pitch0 = VC4_SET_FIELD(param, SCALER6_PTR2_PITCH) | ++ VC4_SET_FIELD(fetch_count - 1, SCALER6_PTR2_FETCH_COUNT); ++ break; ++ } + -+ ccm = colorspace_coeffscolor_rangecolor_encoding; ++ default: ++ DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx", ++ (long long)fb->modifier); ++ return -EINVAL; ++ } + -+ vc4_dlist_write(vc4_state, ccm0); -+ vc4_dlist_write(vc4_state, ccm1); -+ vc4_dlist_write(vc4_state, ccm2); - } - - vc4_state->lbm_offset = 0; -@@ -1146,7 +1307,6 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane, - 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; -@@ -1283,11 +1443,6 @@ static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = { - .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) -@@ -1320,6 +1475,13 @@ static bool vc4_format_mod_supported(struct drm_plane *plane, - default: - return false; - } -+ case DRM_FORMAT_P030: -+ switch (fourcc_mod_broadcom_mod(modifier)) { -+ case DRM_FORMAT_MOD_BROADCOM_SAND128: -+ return true; -+ default: -+ return false; ++ /* fetch an extra pixel if we don't actually line up with the left edge. */ ++ if ((vc4_state->src_x & 0xffff) && vc4_state->src_x < (state->fb->width << 16)) ++ width++; ++ ++ /* same for the right side */ ++ if (((vc4_state->src_x + vc4_state->src_w0) & 0xffff) && ++ vc4_state->src_x + vc4_state->src_w0 < (state->fb->width << 16)) ++ width++; ++ ++ /* now for the top */ ++ if ((vc4_state->src_y & 0xffff) && vc4_state->src_y < (state->fb->height << 16)) ++ height++; ++ ++ /* and the bottom */ ++ if (((vc4_state->src_y + vc4_state->src_h0) & 0xffff) && ++ vc4_state->src_y + vc4_state->src_h0 < (state->fb->height << 16)) ++ height++; ++ ++ /* for YUV444 hardware wants double the width, otherwise it doesn't ++ * fetch full width of chroma ++ */ ++ if (format->drm == DRM_FORMAT_YUV444 || format->drm == DRM_FORMAT_YVU444) ++ width <<= 1; ++ ++ /* Don't waste cycles mixing with plane alpha if the set alpha ++ * is opaque or there is no per-pixel alpha information. ++ * In any case we use the alpha property value as the fixed alpha. ++ */ ++ mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE && ++ fb->format->has_alpha; ++ ++ /* Control Word 0: Scaling Configuration & Element Validity*/ ++ vc4_dlist_write(vc4_state, ++ SCALER6_CTL0_VALID | ++ VC4_SET_FIELD(tiling, SCALER6_CTL0_ADDR_MODE) | ++ vc4_hvs6_get_alpha_mask_mode(state) | ++ (vc4_state->is_unity ? SCALER6_CTL0_UNITY : 0) | ++ VC4_SET_FIELD(format->pixel_order_hvs5, SCALER6_CTL0_ORDERRGBA) | ++ VC4_SET_FIELD(scl1, SCALER6_CTL0_SCL1_MODE) | ++ VC4_SET_FIELD(scl0, SCALER6_CTL0_SCL0_MODE) | ++ VC4_SET_FIELD(hvs_format, SCALER6_CTL0_PIXEL_FORMAT)); ++ ++ /* Position Word 0: Image Position */ ++ vc4_state->pos0_offset = vc4_state->dlist_count; ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(vc4_state->crtc_y, SCALER6_POS0_START_Y) | ++ (rotation & DRM_MODE_REFLECT_X ? SCALER6_POS0_HFLIP : 0) | ++ VC4_SET_FIELD(vc4_state->crtc_x, SCALER6_POS0_START_X)); ++ ++ /* Control Word 2: Alpha Value & CSC */ ++ vc4_dlist_write(vc4_state, ++ vc6_plane_get_csc_mode(vc4_state) | ++ vc4_hvs5_get_alpha_blend_mode(state) | ++ (mix_plane_alpha ? SCALER6_CTL2_ALPHA_MIX : 0) | ++ VC4_SET_FIELD(state->alpha >> 4, SCALER5_CTL2_ALPHA)); ++ ++ /* Position Word 1: Scaled Image Dimensions */ ++ if (!vc4_state->is_unity) ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(vc4_state->crtc_h - 1, ++ SCALER6_POS1_SCL_LINES) | ++ VC4_SET_FIELD(vc4_state->crtc_w - 1, ++ SCALER6_POS1_SCL_WIDTH)); ++ ++ /* Position Word 2: Source Image Size */ ++ vc4_state->pos2_offset = vc4_state->dlist_count; ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(height - 1, ++ SCALER6_POS2_SRC_LINES) | ++ VC4_SET_FIELD(width - 1, ++ SCALER6_POS2_SRC_WIDTH)); ++ ++ /* Position Word 3: Context */ ++ vc4_dlist_write(vc4_state, 0xc0c0c0c0); ++ ++ /* ++ * TODO: This only covers Raster Scan Order planes ++ */ ++ for (i = 0; i < num_planes; i++) { ++ struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, i); ++ dma_addr_t paddr = bo->dma_addr + fb->offsetsi + offsetsi; ++ ++ /* Pointer Word 0 */ ++ vc4_state->ptr0_offseti = vc4_state->dlist_count; ++ vc4_dlist_write(vc4_state, ++ (rotation & DRM_MODE_REFLECT_Y ? SCALER6_PTR0_VFLIP : 0) | ++ /* ++ * The UPM buffer will be allocated in ++ * vc6_plane_allocate_upm(). ++ */ ++ VC4_SET_FIELD(upper_32_bits(paddr) & 0xff, ++ SCALER6_PTR0_UPPER_ADDR)); ++ ++ /* Pointer Word 1 */ ++ vc4_dlist_write(vc4_state, lower_32_bits(paddr)); ++ ++ /* Pointer Word 2 */ ++ if (base_format_mod != DRM_FORMAT_MOD_BROADCOM_SAND128 && ++ base_format_mod != DRM_FORMAT_MOD_BROADCOM_SAND256) { ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(fb->pitchesi, ++ SCALER6_PTR2_PITCH)); ++ } else { ++ vc4_dlist_write(vc4_state, pitch0); + } - case DRM_FORMAT_RGBX1010102: - case DRM_FORMAT_BGRX1010102: - case DRM_FORMAT_RGBA1010102: -@@ -1338,7 +1500,7 @@ static bool vc4_format_mod_supported(struct drm_plane *plane, - 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, -@@ -1352,8 +1514,11 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, - struct drm_plane *plane = NULL; - struct vc4_plane *vc4_plane; - u32 formatsARRAY_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, -@@ -1368,13 +1533,17 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, - if (!vc4_plane) - return ERR_PTR(-ENOMEM); - -- for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) -- formatsi = hvs_formatsi.drm; -+ for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { -+ if (!hvs_formatsi.hvs5_only || hvs5) { -+ formatsnum_formats = hvs_formatsi.drm; -+ num_formats++; ++ } ++ ++ /* ++ * Palette Word 0 ++ * TODO: We're not using the palette mode ++ */ ++ ++ /* ++ * Trans Word 0 ++ * TODO: It's only relevant if we set the trans_rgb bit in the ++ * control word 0, and we don't at the moment. ++ */ ++ ++ vc4_state->lbm_offset = 0; ++ ++ if (!vc4_state->is_unity || fb->format->is_yuv) { ++ /* ++ * Reserve a slot for the LBM Base Address. The real value will ++ * be set when calling vc4_plane_allocate_lbm(). ++ */ ++ if (vc4_state->y_scaling0 != VC4_SCALING_NONE || ++ vc4_state->y_scaling1 != VC4_SCALING_NONE) { ++ vc4_state->lbm_offset = vc4_state->dlist_count; ++ vc4_dlist_counter_increment(vc4_state); ++ } ++ ++ if (vc4_state->x_scaling0 != VC4_SCALING_NONE || ++ vc4_state->x_scaling1 != VC4_SCALING_NONE || ++ vc4_state->y_scaling0 != VC4_SCALING_NONE || ++ vc4_state->y_scaling1 != VC4_SCALING_NONE) { ++ if (num_planes > 1) ++ /* ++ * Emit Cb/Cr as channel 0 and Y as channel ++ * 1. This matches how we set up scl0/scl1 ++ * above. ++ */ ++ vc4_write_scaling_parameters(state, 1); ++ ++ vc4_write_scaling_parameters(state, 0); ++ } ++ ++ /* ++ * If any PPF setup was done, then all the kernel ++ * pointers get uploaded. ++ */ ++ if (vc4_state->x_scaling0 == VC4_SCALING_PPF || ++ vc4_state->y_scaling0 == VC4_SCALING_PPF || ++ vc4_state->x_scaling1 == VC4_SCALING_PPF || ++ vc4_state->y_scaling1 == VC4_SCALING_PPF) { ++ u32 kernel = ++ VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start, ++ SCALER_PPF_KERNEL_OFFSET); ++ ++ /* HPPF plane 0 */ ++ vc4_dlist_write(vc4_state, kernel); ++ /* VPPF plane 0 */ ++ vc4_dlist_write(vc4_state, kernel); ++ /* HPPF plane 1 */ ++ vc4_dlist_write(vc4_state, kernel); ++ /* VPPF plane 1 */ ++ vc4_dlist_write(vc4_state, kernel); + } + } ++ ++ vc4_dlist_write(vc4_state, SCALER6_CTL0_END); ++ ++ vc4_state->dlist0 |= ++ VC4_SET_FIELD(vc4_state->dlist_count, SCALER6_CTL0_NEXT); ++ ++ /* crtc_* are already clipped coordinates. */ ++ covers_screen = vc4_state->crtc_x == 0 && vc4_state->crtc_y == 0 && ++ vc4_state->crtc_w == state->crtc->mode.hdisplay && ++ vc4_state->crtc_h == state->crtc->mode.vdisplay; ++ ++ /* ++ * Background fill might be necessary when the plane has per-pixel ++ * alpha content or a non-opaque plane alpha and could blend from the ++ * background or does not cover the entire screen. ++ */ ++ vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen || ++ state->alpha != DRM_BLEND_ALPHA_OPAQUE; ++ ++ /* ++ * Flag the dlist as initialized to avoid checking it twice in case ++ * the async update check already called vc4_plane_mode_set() and ++ * decided to fallback to sync update because async update was not ++ * possible. ++ */ ++ vc4_state->dlist_initialized = 1; ++ ++ vc4_plane_calc_load(state); ++ ++ drm_dbg_driver(drm, "PLANE:%d:%s Computed DLIST size: %u\n", ++ plane->base.id, plane->name, vc4_state->dlist_count); ++ ++ return 0; ++} ++ + /* If a modeset involves changing the setup of a plane, the atomic + * infrastructure will call this to validate a proposed plane setup. + * However, if a plane isn't getting updated, this (and the +@@ -1281,9 +2014,10 @@ static int vc4_plane_mode_set(struct drm_plane *plane, + * compute the dlist here and have all active plane dlists get updated + * in the CRTC's flush. + */ +-static int vc4_plane_atomic_check(struct drm_plane *plane, +- struct drm_atomic_state *state) ++int vc4_plane_atomic_check(struct drm_plane *plane, ++ struct drm_atomic_state *state) + { ++ struct vc4_dev *vc4 = to_vc4_dev(plane->dev); + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, + plane); + struct vc4_plane_state *vc4_state = to_vc4_plane_state(new_plane_state); +@@ -1294,11 +2028,28 @@ static int vc4_plane_atomic_check(struct drm_plane *plane, + if (!plane_enabled(new_plane_state)) + return 0; - 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); +- ret = vc4_plane_mode_set(plane, new_plane_state); ++ if (vc4->gen >= VC4_GEN_6) ++ ret = vc6_plane_mode_set(plane, new_plane_state); ++ else ++ ret = vc4_plane_mode_set(plane, new_plane_state); if (ret) - return ERR_PTR(ret); -@@ -1382,12 +1551,25 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, - drm_plane_helper_add(plane, &vc4_plane_helper_funcs); - - drm_plane_create_alpha_property(plane); -+ drm_plane_create_blend_mode_property(plane, -+ BIT(DRM_MODE_BLEND_PIXEL_NONE) | -+ BIT(DRM_MODE_BLEND_PREMULTI) | -+ BIT(DRM_MODE_BLEND_COVERAGE)); - 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); + return ret; -+ 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 vc4_plane_allocate_lbm(new_plane_state); ++ if (!vc4_state->src_w0 || !vc4_state->src_h0 || ++ !vc4_state->crtc_w || !vc4_state->crtc_h) ++ return 0; ++ ++ ret = vc4_plane_allocate_lbm(new_plane_state); ++ if (ret) ++ return ret; + - return plane; ++ if (vc4->gen >= VC4_GEN_6) { ++ ret = vc6_plane_allocate_upm(new_plane_state); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; } + static void vc4_plane_atomic_update(struct drm_plane *plane, +@@ -1346,7 +2097,8 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb) + { + struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); + struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, 0); +- uint32_t addr; ++ struct vc4_dev *vc4 = to_vc4_dev(plane->dev); ++ dma_addr_t dma_addr = bo->dma_addr + fb->offsets0; + int idx; + + if (!drm_dev_enter(plane->dev, &idx)) +@@ -1356,19 +2108,38 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb) + * because this is only called on the primary plane. + */ + WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0); +- addr = bo->dma_addr + fb->offsets0; + +- /* Write the new address into the hardware immediately. The +- * scanout will start from this address as soon as the FIFO +- * needs to refill with pixels. +- */ +- writel(addr, &vc4_state->hw_dlistvc4_state->ptr0_offset); ++ if (vc4->gen == VC4_GEN_6) { ++ u32 value; + +- /* Also update the CPU-side dlist copy, so that any later +- * atomic updates that don't do a new modeset on our plane +- * also use our updated address. +- */ +- vc4_state->dlistvc4_state->ptr0_offset = addr; ++ value = vc4_state->dlistvc4_state->ptr0_offset0 & ++ ~SCALER6_PTR0_UPPER_ADDR_MASK; ++ value |= VC4_SET_FIELD(upper_32_bits(dma_addr) & 0xff, ++ SCALER6_PTR0_UPPER_ADDR); ++ ++ writel(value, &vc4_state->hw_dlistvc4_state->ptr0_offset0); ++ vc4_state->dlistvc4_state->ptr0_offset0 = value; ++ ++ value = lower_32_bits(dma_addr); ++ writel(value, &vc4_state->hw_dlistvc4_state->ptr0_offset0 + 1); ++ vc4_state->dlistvc4_state->ptr0_offset0 + 1 = value; ++ } else { ++ u32 addr; ++ ++ addr = (u32)dma_addr; ++ ++ /* Write the new address into the hardware immediately. The ++ * scanout will start from this address as soon as the FIFO ++ * needs to refill with pixels. ++ */ ++ writel(addr, &vc4_state->hw_dlistvc4_state->ptr0_offset0); ++ ++ /* Also update the CPU-side dlist copy, so that any later ++ * atomic updates that don't do a new modeset on our plane ++ * also use our updated address. ++ */ ++ vc4_state->dlistvc4_state->ptr0_offset0 = addr; ++ } + + drm_dev_exit(idx); + } +@@ -1423,8 +2194,6 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane, + sizeof(vc4_state->y_scaling)); + vc4_state->is_unity = new_vc4_state->is_unity; + vc4_state->is_yuv = new_vc4_state->is_yuv; +- memcpy(vc4_state->offsets, new_vc4_state->offsets, +- sizeof(vc4_state->offsets)); + vc4_state->needs_bg_fill = new_vc4_state->needs_bg_fill; + + /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */ +@@ -1432,8 +2201,8 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane, + new_vc4_state->dlistvc4_state->pos0_offset; + vc4_state->dlistvc4_state->pos2_offset = + new_vc4_state->dlistvc4_state->pos2_offset; +- vc4_state->dlistvc4_state->ptr0_offset = +- new_vc4_state->dlistvc4_state->ptr0_offset; ++ vc4_state->dlistvc4_state->ptr0_offset0 = ++ new_vc4_state->dlistvc4_state->ptr0_offset0; + + /* Note that we can't just call vc4_plane_write_dlist() + * because that would smash the context data that the HVS is +@@ -1443,8 +2212,8 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane, + &vc4_state->hw_dlistvc4_state->pos0_offset); + writel(vc4_state->dlistvc4_state->pos2_offset, + &vc4_state->hw_dlistvc4_state->pos2_offset); +- writel(vc4_state->dlistvc4_state->ptr0_offset, +- &vc4_state->hw_dlistvc4_state->ptr0_offset); ++ writel(vc4_state->dlistvc4_state->ptr0_offset0, ++ &vc4_state->hw_dlistvc4_state->ptr0_offset0); + + drm_dev_exit(idx); + } +@@ -1454,11 +2223,15 @@ static int vc4_plane_atomic_async_check(struct drm_plane *plane, + { + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, + plane); ++ struct vc4_dev *vc4 = to_vc4_dev(plane->dev); + struct vc4_plane_state *old_vc4_state, *new_vc4_state; + int ret; + u32 i; + +- ret = vc4_plane_mode_set(plane, new_plane_state); ++ if (vc4->gen >= VC4_GEN_6) ++ ret = vc6_plane_mode_set(plane, new_plane_state); ++ else ++ ret = vc4_plane_mode_set(plane, new_plane_state); + if (ret) + return ret; + +@@ -1471,7 +2244,7 @@ static int vc4_plane_atomic_async_check(struct drm_plane *plane, + if (old_vc4_state->dlist_count != new_vc4_state->dlist_count || + old_vc4_state->pos0_offset != new_vc4_state->pos0_offset || + old_vc4_state->pos2_offset != new_vc4_state->pos2_offset || +- old_vc4_state->ptr0_offset != new_vc4_state->ptr0_offset || ++ old_vc4_state->ptr0_offset0 != new_vc4_state->ptr0_offset0 || + vc4_lbm_size(plane->state) != vc4_lbm_size(new_plane_state)) + return -EINVAL; + +@@ -1481,7 +2254,7 @@ static int vc4_plane_atomic_async_check(struct drm_plane *plane, + for (i = 0; i < new_vc4_state->dlist_count; i++) { + if (i == new_vc4_state->pos0_offset || + i == new_vc4_state->pos2_offset || +- i == new_vc4_state->ptr0_offset || ++ i == new_vc4_state->ptr0_offset0 || + (new_vc4_state->lbm_offset && + i == new_vc4_state->lbm_offset)) + continue; +@@ -1505,9 +2278,6 @@ static int vc4_prepare_fb(struct drm_plane *plane, + + drm_gem_plane_helper_prepare_fb(plane, state); + +- if (plane->state->fb == state->fb) +- return 0; +- + return vc4_bo_inc_usecnt(bo); + } + +@@ -1516,7 +2286,7 @@ static void vc4_cleanup_fb(struct drm_plane *plane, + { + struct vc4_bo *bo; + +- if (plane->state->fb == state->fb || !state->fb) ++ if (!state->fb) + return; + + bo = to_vc4_bo(&drm_fb_dma_get_gem_obj(state->fb, 0)->base); +@@ -1632,7 +2402,7 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, + }; + + for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { +- if (!hvs_formatsi.hvs5_only || vc4->is_vc5) { ++ if (!hvs_formatsi.hvs5_only || vc4->gen >= VC4_GEN_5) { + formatsnum_formats = hvs_formatsi.drm; + num_formats++; + } +@@ -1647,7 +2417,7 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, + return ERR_CAST(vc4_plane); + plane = &vc4_plane->base; + +- if (vc4->is_vc5) ++ if (vc4->gen >= VC4_GEN_5) + drm_plane_helper_add(plane, &vc5_plane_helper_funcs); + else + drm_plane_helper_add(plane, &vc4_plane_helper_funcs); +@@ -1672,6 +2442,8 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, + DRM_COLOR_YCBCR_BT709, + DRM_COLOR_YCBCR_LIMITED_RANGE); + ++ drm_plane_create_chroma_siting_properties(plane, 0, 0); ++ + if (type == DRM_PLANE_TYPE_PRIMARY) + drm_plane_create_zpos_immutable_property(plane, 0); + diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h -index be2c32a519b3..f40dd93f2cdd 100644 +index f3763bd600f6..3608cdec29ad 100644 --- a/drivers/gpu/drm/vc4/vc4_regs.h +++ b/drivers/gpu/drm/vc4/vc4_regs.h -@@ -491,6 +491,28 @@ +@@ -13,11 +13,24 @@ + /* Using the GNU statement expression extension */ + #define VC4_SET_FIELD(value, field) \ + ({ \ +- WARN_ON(!FIELD_FIT(field##_MASK, value)); \ +- FIELD_PREP(field##_MASK, value); \ ++ WARN_ON(!FIELD_FIT(field ## _MASK, value)); \ ++ FIELD_PREP(field ## _MASK, value); \ + }) + +-#define VC4_GET_FIELD(word, field) FIELD_GET(field##_MASK, word) ++#define VC4_GET_FIELD(word, field) FIELD_GET(field ## _MASK, word) ++ ++#define VC4_SET_FIELD6(value, field) \ ++ ({ \ ++ WARN_ON(!FIELD_FIT(hvs->vc4->step_d0 ? \ ++ SCALER6D0_ ## field ## _MASK : \ ++ SCALER6_ ## field ## _MASK, value));\ ++ FIELD_PREP(hvs->vc4->step_d0 ? \ ++ SCALER6D0_ ## field ## _MASK : \ ++ SCALER6_ ## field ## _MASK, value); \ ++ }) ++ ++#define VC4_GET_FIELD6(word, field) FIELD_GET(hvs->vc4->step_d0 ? \ ++ SCALER6D0_ ## field ## _MASK : SCALER6_ ## field ## _MASK, word) + + #define V3D_IDENT0 0x00000 + # define V3D_EXPECTED_IDENT0 \ +@@ -155,6 +168,7 @@ + # define PV_CONTROL_EN BIT(0) + + #define PV_V_CONTROL 0x04 ++# define PV_VCONTROL_ODD_TIMING BIT(29) + # define PV_VCONTROL_ODD_DELAY_MASK VC4_MASK(22, 6) + # define PV_VCONTROL_ODD_DELAY_SHIFT 6 + # define PV_VCONTROL_ODD_FIRST BIT(5) +@@ -215,6 +229,11 @@ + # define PV_MUX_CFG_RGB_PIXEL_MUX_MODE_SHIFT 2 + # define PV_MUX_CFG_RGB_PIXEL_MUX_MODE_NO_SWAP 8 + ++#define PV_PIPE_INIT_CTRL 0x94 ++# define PV_PIPE_INIT_CTRL_PV_INIT_WIDTH_MASK VC4_MASK(11, 8) ++# define PV_PIPE_INIT_CTRL_PV_INIT_IDLE_MASK VC4_MASK(7, 4) ++# define PV_PIPE_INIT_CTRL_PV_INIT_EN BIT(0) ++ + #define SCALER_CHANNELS_COUNT 3 + + #define SCALER_DISPCTRL 0x00000000 +@@ -418,6 +437,10 @@ + # define SCALER_DISPSTAT1_FRCNT0_SHIFT 18 + # define SCALER_DISPSTAT1_FRCNT1_MASK VC4_MASK(17, 12) + # define SCALER_DISPSTAT1_FRCNT1_SHIFT 12 ++# define SCALER5_DISPSTAT1_FRCNT0_MASK VC4_MASK(25, 20) ++# define SCALER5_DISPSTAT1_FRCNT0_SHIFT 20 ++# define SCALER5_DISPSTAT1_FRCNT1_MASK VC4_MASK(19, 14) ++# define SCALER5_DISPSTAT1_FRCNT1_SHIFT 14 + + #define SCALER_DISPSTATX(x) (SCALER_DISPSTAT0 + \ + (x) * (SCALER_DISPSTAT1 - \ +@@ -436,6 +459,8 @@ + #define SCALER_DISPSTAT2 0x00000068 + # define SCALER_DISPSTAT2_FRCNT2_MASK VC4_MASK(17, 12) + # define SCALER_DISPSTAT2_FRCNT2_SHIFT 12 ++# define SCALER5_DISPSTAT2_FRCNT2_MASK VC4_MASK(19, 14) ++# define SCALER5_DISPSTAT2_FRCNT2_SHIFT 14 + + #define SCALER_DISPBASE2 0x0000006c + #define SCALER_DISPALPHA2 0x00000070 +@@ -512,8 +537,261 @@ #define SCALER_DLIST_START 0x00002000 #define SCALER_DLIST_SIZE 0x00004000 @@ -67170,218 +96205,642 @@ + #define SCALER5_DLIST_START 0x00004000 - # define VC4_HDMI_SW_RESET_FORMAT_DETECT BIT(1) -@@ -516,6 +538,36 @@ - # 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 ++#define SCALER6_VERSION 0x00000000 ++#define SCALER6_CXM_SIZE 0x00000004 ++#define SCALER6_LBM_SIZE 0x00000008 ++#define SCALER6_UBM_SIZE 0x0000000c ++#define SCALER6_COBA_SIZE 0x00000010 ++#define SCALER6_COB_SIZE 0x00000014 ++ ++#define SCALER6_CONTROL 0x00000020 ++# define SCALER6_CONTROL_HVS_EN BIT(31) ++# define SCALER6_CONTROL_PF_LINES_MASK VC4_MASK(22, 18) ++# define SCALER6_CONTROL_ABORT_ON_EMPTY BIT(16) ++# define SCALER6_CONTROL_DSP1_TARGET_MASK VC4_MASK(13, 12) ++# define SCALER6_CONTROL_MAX_REQS_MASK VC4_MASK(7, 4) ++ ++#define SCALER6_FETCHER_STATUS 0x00000024 ++#define SCALER6_FETCH_STATUS 0x00000028 ++#define SCALER6_HANDLE_ERROR 0x0000002c ++ ++#define SCALER6_DISP0_CTRL0 0x00000030 ++#define SCALER6_DISPX_CTRL0(x) ((hvs->vc4->step_d0) ? \ ++ (SCALER6D0_DISP0_CTRL0 + ((x) * (SCALER6D0_DISP1_CTRL0 - SCALER6D0_DISP0_CTRL0))) : \ ++ (SCALER6_DISP0_CTRL0 + ((x) * (SCALER6_DISP1_CTRL0 - SCALER6_DISP0_CTRL0)))) ++# define SCALER6_DISPX_CTRL0_ENB BIT(31) ++# define SCALER6_DISPX_CTRL0_RESET BIT(30) ++# define SCALER6_DISPX_CTRL0_FWIDTH_MASK VC4_MASK(28, 16) ++# define SCALER6_DISPX_CTRL0_ONESHOT BIT(15) ++# define SCALER6_DISPX_CTRL0_ONECTX_MASK VC4_MASK(14, 13) ++# define SCALER6_DISPX_CTRL0_LINES_MASK VC4_MASK(12, 0) ++ ++#define SCALER6_DISP0_CTRL1 0x00000034 ++#define SCALER6_DISPX_CTRL1(x) ((hvs->vc4->step_d0) ? \ ++ (SCALER6D0_DISP0_CTRL1 + ((x) * (SCALER6D0_DISP1_CTRL1 - SCALER6D0_DISP0_CTRL1))) : \ ++ (SCALER6_DISP0_CTRL1 + ((x) * (SCALER6_DISP1_CTRL1 - SCALER6_DISP0_CTRL1)))) ++# define SCALER6_DISPX_CTRL1_BGENB BIT(8) ++# define SCALER6_DISPX_CTRL1_INTLACE BIT(0) ++ ++#define SCALER6_DISP0_BGND 0x00000038 ++#define SCALER6_DISPX_BGND(x) ((hvs->vc4->step_d0) ? \ ++ (SCALER6D0_DISP0_BGND + ((x) * (SCALER6D0_DISP1_BGND - SCALER6D0_DISP0_BGND))) : \ ++ (SCALER6_DISP0_BGND + ((x) * (SCALER6_DISP1_BGND - SCALER6_DISP0_BGND)))) ++ ++#define SCALER6_DISP0_LPTRS 0x0000003c ++#define SCALER6_DISPX_LPTRS(x) ((hvs->vc4->step_d0) ? \ ++ (SCALER6D0_DISP0_LPTRS + ((x) * (SCALER6D0_DISP1_LPTRS - SCALER6D0_DISP0_LPTRS))) : \ ++ (SCALER6_DISP0_LPTRS + ((x) * (SCALER6_DISP1_LPTRS - SCALER6_DISP0_LPTRS)))) ++# define SCALER6_DISPX_LPTRS_HEADE_MASK VC4_MASK(11, 0) ++ ++#define SCALER6_DISP0_COB 0x00000040 ++#define SCALER6_DISPX_COB(x) ((hvs->vc4->step_d0) ? \ ++ (SCALER6D0_DISP0_COB + ((x) * (SCALER6D0_DISP1_COB - SCALER6D0_DISP0_COB))) : \ ++ (SCALER6_DISP0_COB + ((x) * (SCALER6_DISP1_COB - SCALER6_DISP0_COB)))) ++# define SCALER6_DISPX_COB_TOP_MASK VC4_MASK(31, 16) ++# define SCALER6_DISPX_COB_BASE_MASK VC4_MASK(15, 0) ++ ++#define SCALER6_DISP0_STATUS 0x00000044 ++ ++#define SCALER6_DISPX_STATUS(x) ((hvs->vc4->step_d0) ? \ ++ (SCALER6D0_DISP0_STATUS + ((x) * (SCALER6D0_DISP1_STATUS - SCALER6D0_DISP0_STATUS))) : \ ++ (SCALER6_DISP0_STATUS + ((x) * (SCALER6_DISP1_STATUS - SCALER6_DISP0_STATUS)))) ++# define SCALER6_DISPX_STATUS_EMPTY BIT(22) ++# define SCALER6_DISPX_STATUS_FRCNT_MASK VC4_MASK(21, 16) ++# define SCALER6_DISPX_STATUS_OFIELD BIT(15) ++# define SCALER6_DISPX_STATUS_MODE_MASK VC4_MASK(14, 13) ++# define SCALER6_DISPX_STATUS_MODE_DISABLED 0 ++# define SCALER6_DISPX_STATUS_MODE_INIT 1 ++# define SCALER6_DISPX_STATUS_MODE_RUN 2 ++# define SCALER6_DISPX_STATUS_MODE_EOF 3 ++# define SCALER6_DISPX_STATUS_YLINE_MASK VC4_MASK(12, 0) ++ ++#define SCALER6_DISP0_DL 0x00000048 ++ ++#define SCALER6_DISPX_DL(x) ((hvs->vc4->step_d0) ? \ ++ (SCALER6D0_DISP0_DL + ((x) * (SCALER6D0_DISP1_DL - SCALER6D0_DISP0_DL))) : \ ++ (SCALER6_DISP0_DL + ((x) * (SCALER6_DISP1_DL - SCALER6_DISP0_DL)))) ++# define SCALER6_DISPX_DL_LACT_MASK VC4_MASK(11, 0) ++ ++#define SCALER6_DISP0_RUN 0x0000004c ++#define SCALER6_DISP1_CTRL0 0x00000050 ++#define SCALER6_DISP1_CTRL1 0x00000054 ++#define SCALER6_DISP1_BGND 0x00000058 ++#define SCALER6_DISP1_LPTRS 0x0000005c ++#define SCALER6_DISP1_COB 0x00000060 ++#define SCALER6_DISP1_STATUS 0x00000064 ++#define SCALER6_DISP1_DL 0x00000068 ++#define SCALER6_DISP1_RUN 0x0000006c ++#define SCALER6_DISP2_CTRL0 0x00000070 ++#define SCALER6_DISP2_CTRL1 0x00000074 ++#define SCALER6_DISP2_BGND 0x00000078 ++#define SCALER6_DISP2_LPTRS 0x0000007c ++#define SCALER6_DISP2_COB 0x00000080 ++#define SCALER6_DISP2_STATUS 0x00000084 ++#define SCALER6_DISP2_DL 0x00000088 ++#define SCALER6_DISP2_RUN 0x0000008c ++#define SCALER6_EOLN 0x00000090 ++#define SCALER6_DL_STATUS 0x00000094 ++#define SCALER6_BFG_MISC 0x0000009c ++#define SCALER6_QOS0 0x000000a0 ++#define SCALER6_PROF0 0x000000a4 ++#define SCALER6_QOS1 0x000000a8 ++#define SCALER6_PROF1 0x000000ac ++#define SCALER6_QOS2 0x000000b0 ++#define SCALER6_PROF2 0x000000b4 ++#define SCALER6_PRI_MAP0 0x000000b8 ++#define SCALER6_PRI_MAP1 0x000000bc ++#define SCALER6_HISTCTRL 0x000000c0 ++#define SCALER6_HISTBIN0 0x000000c4 ++#define SCALER6_HISTBIN1 0x000000c8 ++#define SCALER6_HISTBIN2 0x000000cc ++#define SCALER6_HISTBIN3 0x000000d0 ++#define SCALER6_HISTBIN4 0x000000d4 ++#define SCALER6_HISTBIN5 0x000000d8 ++#define SCALER6_HISTBIN6 0x000000dc ++#define SCALER6_HISTBIN7 0x000000e0 ++#define SCALER6_HDR_CFG_REMAP 0x000000f4 ++#define SCALER6_COL_SPACE 0x000000f8 ++#define SCALER6_HVS_ID 0x000000fc ++#define SCALER6_CFC1 0x00000100 ++#define SCALER6_DISP_UPM_ISO0 0x00000200 ++#define SCALER6_DISP_UPM_ISO1 0x00000204 ++#define SCALER6_DISP_UPM_ISO2 0x00000208 ++#define SCALER6_DISP_LBM_ISO0 0x0000020c ++#define SCALER6_DISP_LBM_ISO1 0x00000210 ++#define SCALER6_DISP_LBM_ISO2 0x00000214 ++#define SCALER6_DISP_COB_ISO0 0x00000218 ++#define SCALER6_DISP_COB_ISO1 0x0000021c ++#define SCALER6_DISP_COB_ISO2 0x00000220 ++#define SCALER6_BAD_COB 0x00000224 ++#define SCALER6_BAD_LBM 0x00000228 ++#define SCALER6_BAD_UPM 0x0000022c ++#define SCALER6_BAD_AXI 0x00000230 ++ ++ ++#define SCALER6D0_VERSION 0x00000000 ++#define SCALER6D0_CXM_SIZE 0x00000004 ++#define SCALER6D0_LBM_SIZE 0x00000008 ++#define SCALER6D0_UBM_SIZE 0x0000000c ++#define SCALER6D0_COBA_SIZE 0x00000010 ++#define SCALER6D0_COB_SIZE 0x00000014 ++#define SCALER6D0_CONTROL 0x00000020 ++#define SCALER6D0_FETCHER_STATUS 0x00000024 ++#define SCALER6D0_FETCH_STATUS 0x00000028 ++#define SCALER6D0_HANDLE_ERROR 0x0000002c ++ ++#define SCALER6D0_EOLN 0x00000030 ++#define SCALER6D0_DL_STATUS 0x00000034 ++#define SCALER6D0_PRI_MAP0 0x00000038 ++#define SCALER6D0_PRI_MAP1 0x0000003c ++#define SCALER6D0_HISTCTRL 0x000000d0 ++#define SCALER6D0_HISTBIN0 0x000000d4 ++#define SCALER6D0_HISTBIN1 0x000000d8 ++#define SCALER6D0_HISTBIN2 0x000000dc ++#define SCALER6D0_HISTBIN3 0x000000e0 ++#define SCALER6D0_HISTBIN4 0x000000e4 ++#define SCALER6D0_HISTBIN5 0x000000e8 ++#define SCALER6D0_HISTBIN6 0x000000ec ++#define SCALER6D0_HISTBIN7 0x000000f0 ++#define SCALER6D0_HVS_ID 0x000000fc ++ ++#define SCALER6D0_DISP0_CTRL0 0x00000100 ++# define SCALER6D0_DISPX_CTRL0_ENB BIT(31) ++# define SCALER6D0_DISPX_CTRL0_RESET BIT(30) ++# define SCALER6D0_DISPX_CTRL0_FWIDTH_MASK VC4_MASK(28, 16) ++# define SCALER6D0_DISPX_CTRL0_ONESHOT BIT(15) ++# define SCALER6D0_DISPX_CTRL0_ONECTX_MASK VC4_MASK(14, 13) ++# define SCALER6D0_DISPX_CTRL0_LINES_MASK VC4_MASK(12, 0) ++ ++#define SCALER6D0_DISP0_CTRL1 0x00000104 ++# define SCALER6D0_DISPX_CTRL1_BGENB BIT(8) ++# define SCALER6D0_DISPX_CTRL1_INTLACE BIT(0) ++ ++#define SCALER6D0_DISP0_BGND 0x00000108 ++ ++#define SCALER6D0_DISP0_LPTRS 0x00000110 ++# define SCALER6D0_DISPX_LPTRS_HEADE_MASK VC4_MASK(11, 0) ++ ++#define SCALER6D0_DISP0_COB 0x00000114 ++# define SCALER6D0_DISPX_COB_TOP_MASK VC4_MASK(31, 16) ++# define SCALER6D0_DISPX_COB_BASE_MASK VC4_MASK(15, 0) ++ ++#define SCALER6D0_DISP0_STATUS 0x00000118 ++ ++# define SCALER6D0_DISPX_STATUS_EMPTY BIT(22) ++# define SCALER6D0_DISPX_STATUS_FRCNT_MASK VC4_MASK(21, 16) ++# define SCALER6D0_DISPX_STATUS_OFIELD BIT(15) ++# define SCALER6D0_DISPX_STATUS_MODE_MASK VC4_MASK(14, 13) ++# define SCALER6D0_DISPX_STATUS_MODE_DISABLED 0 ++# define SCALER6D0_DISPX_STATUS_MODE_INIT 1 ++# define SCALER6D0_DISPX_STATUS_MODE_RUN 2 ++# define SCALER6D0_DISPX_STATUS_MODE_EOF 3 ++# define SCALER6D0_DISPX_STATUS_YLINE_MASK VC4_MASK(12, 0) ++ ++ ++#define SCALER6D0_DISP0_CTRL0 0x00000100 ++#define SCALER6D0_DISP0_CTRL1 0x00000104 ++#define SCALER6D0_DISP0_BGND0 0x00000108 ++#define SCALER6D0_DISP0_BGND1 0x0000010c ++#define SCALER6D0_DISP0_LPTRS 0x00000110 ++#define SCALER6D0_DISP0_COB 0x00000114 ++#define SCALER6D0_DISP0_STATUS 0x00000118 ++#define SCALER6D0_DISP0_DL 0x0000011c ++# define SCALER6D0_DISPX_DL_LACT_MASK VC4_MASK(11, 0) ++#define SCALER6D0_DISP0_RUN 0x00000120 ++#define SCALER6D0_QOS0 0x00000124 ++#define SCALER6D0_PROF0 0x00000128 ++ ++#define SCALER6D0_DISP1_CTRL0 0x00000140 ++#define SCALER6D0_DISP1_CTRL1 0x00000144 ++#define SCALER6D0_DISP1_BGND0 0x00000148 ++#define SCALER6D0_DISP1_BGND1 0x0000014c ++#define SCALER6D0_DISP1_LPTRS 0x00000150 ++#define SCALER6D0_DISP1_COB 0x00000154 ++#define SCALER6D0_DISP1_STATUS 0x00000158 ++#define SCALER6D0_DISP1_DL 0x0000015c ++#define SCALER6D0_DISP1_RUN 0x00000160 ++#define SCALER6D0_QOS1 0x00000164 ++#define SCALER6D0_PROF1 0x00000168 ++ ++#define SCALER6D0_DISP2_CTRL0 0x00000180 ++#define SCALER6D0_DISP2_CTRL1 0x00000184 ++#define SCALER6D0_DISP2_BGND0 0x00000188 ++#define SCALER6D0_DISP2_BGND1 0x0000018c ++#define SCALER6D0_DISP2_LPTRS 0x00000190 ++#define SCALER6D0_DISP2_COB 0x00000194 ++#define SCALER6D0_DISP2_STATUS 0x00000198 ++#define SCALER6D0_DISP2_DL 0x0000019c ++#define SCALER6D0_DISP2_RUN 0x000001a0 ++#define SCALER6D0_QOS2 0x000001a4 ++#define SCALER6D0_PROF2 0x000001a8 + -+enum { -+ VC4_HDMI_MAI_FORMAT_PCM = 2, -+ VC4_HDMI_MAI_FORMAT_HBR = 200, -+}; ++#define SCALER6(x) ((hvs->vc4->step_d0) ? SCALER6D0_ ## x : SCALER6_ ## x) + -+# define VC4_HDMI_MAI_FORMAT_SAMPLE_RATE_MASK VC4_MASK(15, 8) -+# define VC4_HDMI_MAI_FORMAT_SAMPLE_RATE_SHIFT 8 + # define VC4_HDMI_SW_RESET_FORMAT_DETECT BIT(1) + # define VC4_HDMI_SW_RESET_HDMI BIT(0) + +@@ -761,6 +1039,15 @@ enum { + # define VC4_HD_MAI_THR_DREQLOW_MASK VC4_MASK(5, 0) + # define VC4_HD_MAI_THR_DREQLOW_SHIFT 0 + ++# define VC4_D0_HD_MAI_THR_PANICHIGH_MASK VC4_MASK(29, 23) ++# define VC4_D0_HD_MAI_THR_PANICHIGH_SHIFT 23 ++# define VC4_D0_HD_MAI_THR_PANICLOW_MASK VC4_MASK(21, 15) ++# define VC4_D0_HD_MAI_THR_PANICLOW_SHIFT 15 ++# define VC4_D0_HD_MAI_THR_DREQHIGH_MASK VC4_MASK(13, 7) ++# define VC4_D0_HD_MAI_THR_DREQHIGH_SHIFT 7 ++# define VC4_D0_HD_MAI_THR_DREQLOW_MASK VC4_MASK(6, 0) ++# define VC4_D0_HD_MAI_THR_DREQLOW_SHIFT 0 + -+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 -@@ -744,8 +796,27 @@ - # define VC4_HD_CSC_CTL_RGB2YCC BIT(1) - # define VC4_HD_CSC_CTL_ENABLE BIT(0) - -+# define VC5_MT_CP_CSC_CTL_USE_444_TO_422 BIT(6) -+# define VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_MASK \ -+ VC4_MASK(5, 4) -+# define VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD \ -+ 3 -+# define VC5_MT_CP_CSC_CTL_USE_RNG_SUPPRESSION BIT(3) -+# define VC5_MT_CP_CSC_CTL_ENABLE BIT(2) -+# define VC5_MT_CP_CSC_CTL_MODE_MASK VC4_MASK(1, 0) -+ -+# define VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_MASK \ -+ VC4_MASK(7, 6) -+# define VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_LEGACY_STYLE \ -+ 2 -+ - # define VC4_DVP_HT_CLOCK_STOP_PIXEL BIT(1) - -+# define VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_MASK \ -+ VC4_MASK(3, 2) -+# define VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_FORMAT_422_LEGACY \ -+ 2 -+ - /* HVS display list information. */ - #define HVS_BOOTLOADER_DLIST_END 32 - -@@ -945,7 +1016,10 @@ enum hvs_pixel_format { - #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) -@@ -960,8 +1034,11 @@ enum hvs_pixel_format { - #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) -@@ -972,9 +1049,12 @@ enum hvs_pixel_format { - /* 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 + /* Divider from HDMI HSM clock to MAI serial clock. Sampling period + * converges to N / (M + 1) cycles. + */ +@@ -777,6 +1064,7 @@ enum { + # define VC4_HD_VID_CTL_CLRSYNC BIT(24) + # define VC4_HD_VID_CTL_CLRRGB BIT(23) + # define VC4_HD_VID_CTL_BLANKPIX BIT(18) ++# define VC4_HD_VID_CTL_BLANK_INSERT_EN BIT(16) + + # define VC4_HD_CSC_CTL_ORDER_MASK VC4_MASK(7, 5) + # define VC4_HD_CSC_CTL_ORDER_SHIFT 5 +@@ -1108,4 +1396,67 @@ enum hvs_pixel_format { + #define SCALER_PITCH0_TILE_WIDTH_R_MASK VC4_MASK(6, 0) + #define SCALER_PITCH0_TILE_WIDTH_R_SHIFT 0 + ++#define SCALER6_CTL0_END BIT(31) ++#define SCALER6_CTL0_VALID BIT(30) ++#define SCALER6_CTL0_NEXT_MASK VC4_MASK(29, 24) ++#define SCALER6_CTL0_RGB_TRANS BIT(23) ++#define SCALER6_CTL0_ADDR_MODE_MASK VC4_MASK(22, 20) ++#define SCALER6_CTL0_ADDR_MODE_LINEAR 0 ++#define SCALER6_CTL0_ADDR_MODE_128B 1 ++#define SCALER6_CTL0_ADDR_MODE_256B 2 ++#define SCALER6_CTL0_ADDR_MODE_MAP8 3 ++#define SCALER6_CTL0_ADDR_MODE_UIF 4 ++ ++#define SCALER6_CTL0_ALPHA_MASK_MASK VC4_MASK(19, 18) ++#define SCALER6_CTL0_ALPHA_MASK_NONE 0 ++#define SCALER6_CTL0_ALPHA_MASK_FIXED 3 ++ ++#define SCALER6_CTL0_UNITY BIT(15) ++#define SCALER6_CTL0_ORDERRGBA_MASK VC4_MASK(14, 13) ++#define SCALER6_CTL0_SCL1_MODE_MASK VC4_MASK(10, 8) ++#define SCALER6_CTL0_SCL0_MODE_MASK VC4_MASK(7, 5) ++#define SCALER6_CTL0_PIXEL_FORMAT_MASK VC4_MASK(4, 0) ++ ++#define SCALER6_POS0_START_Y_MASK VC4_MASK(28, 16) ++#define SCALER6_POS0_HFLIP BIT(15) ++#define SCALER6_POS0_START_X_MASK VC4_MASK(12, 0) ++ ++#define SCALER6_CTL2_ALPHA_MODE_MASK VC4_MASK(31, 30) ++#define SCALER6_CTL2_ALPHA_PREMULT BIT(29) ++#define SCALER6_CTL2_ALPHA_MIX BIT(28) ++#define SCALER6_CTL2_BFG BIT(26) ++#define SCALER6_CTL2_CSC_ENABLE BIT(25) ++#define SCALER6_CTL2_BRCM_CFC_CONTROL_MASK VC4_MASK(18, 16) ++#define SCALER6_CTL2_ALPHA_MASK VC4_MASK(15, 4) ++ ++#define SCALER6D0_CTL2_CSC_ENABLE BIT(19) ++#define SCALER6D0_CTL2_BRCM_CFC_CONTROL_MASK VC4_MASK(22, 20) ++ ++#define SCALER6_POS1_SCL_LINES_MASK VC4_MASK(28, 16) ++#define SCALER6_POS1_SCL_WIDTH_MASK VC4_MASK(12, 0) ++ ++#define SCALER6_POS2_SRC_LINES_MASK VC4_MASK(28, 16) ++#define SCALER6_POS2_SRC_WIDTH_MASK VC4_MASK(12, 0) ++ ++#define SCALER6_PTR0_VFLIP BIT(31) ++#define SCALER6_PTR0_UPM_BASE_MASK VC4_MASK(28, 16) ++#define SCALER6_PTR0_UPM_HANDLE_MASK VC4_MASK(14, 10) ++#define SCALER6_PTR0_UPM_BUFF_SIZE_MASK VC4_MASK(9, 8) ++#define SCALER6_PTR0_UPM_BUFF_SIZE_16_LINES 3 ++#define SCALER6_PTR0_UPM_BUFF_SIZE_8_LINES 2 ++#define SCALER6_PTR0_UPM_BUFF_SIZE_4_LINES 1 ++#define SCALER6_PTR0_UPM_BUFF_SIZE_2_LINES 0 ++#define SCALER6_PTR0_UPPER_ADDR_MASK VC4_MASK(7, 0) ++ ++#define SCALER6_PTR2_ALPHA_BPP_MASK VC4_MASK(31, 31) ++#define SCALER6_PTR2_ALPHA_BPP_1BPP 1 ++#define SCALER6_PTR2_ALPHA_BPP_8BPP 0 ++#define SCALER6_PTR2_ALPHA_ORDER_MASK VC4_MASK(30, 30) ++#define SCALER6_PTR2_ALPHA_ORDER_MSB_TO_LSB 1 ++#define SCALER6_PTR2_ALPHA_ORDER_LSB_TO_MSB 0 ++#define SCALER6_PTR2_ALPHA_OFFS_MASK VC4_MASK(29, 27) ++#define SCALER6_PTR2_LSKIP_MASK VC4_MASK(26, 24) ++#define SCALER6_PTR2_PITCH_MASK VC4_MASK(16, 0) ++#define SCALER6_PTR2_FETCH_COUNT_MASK VC4_MASK(26, 16) ++ + #endif /* VC4_REGS_H */ +diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c +index 1bda5010f15a..14079853338e 100644 +--- a/drivers/gpu/drm/vc4/vc4_render_cl.c ++++ b/drivers/gpu/drm/vc4/vc4_render_cl.c +@@ -599,7 +599,7 @@ int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec) + bool has_bin = args->bin_cl_size != 0; + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; - #define SCALER_TPZ0_VERT_RECALC BIT(31) - #define SCALER_TPZ0_SCALE_MASK VC4_MASK(28, 8) + if (args->min_x_tile > args->max_x_tile || diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c -index d13502ae973d..9809ca3e2945 100644 +index ffe1f7d1b911..b87d5f8ad4b8 100644 --- a/drivers/gpu/drm/vc4/vc4_txp.c +++ b/drivers/gpu/drm/vc4/vc4_txp.c -@@ -13,6 +13,7 @@ - #include <linux/of_platform.h> - #include <linux/pm_runtime.h> +@@ -145,6 +145,9 @@ + /* Number of lines received and committed to memory. */ + #define TXP_PROGRESS 0x10 + ++#define TXP_DST_PTR_HIGH_MOPLET 0x1c ++#define TXP_DST_PTR_HIGH_MOP 0x24 ++ + #define TXP_READ(offset) \ + ({ \ + kunit_fail_current_test("Accessing a register in a unit test!\n"); \ +@@ -159,6 +162,7 @@ + + struct vc4_txp { + struct vc4_crtc base; ++ const struct vc4_txp_data *data; -+#include <drm/drm_atomic.h> - #include <drm/drm_atomic_helper.h> - #include <drm/drm_edid.h> - #include <drm/drm_fb_cma_helper.h> -@@ -272,8 +273,10 @@ static int vc4_txp_connector_atomic_check(struct drm_connector *conn, - } + struct platform_device *pdev; - 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); +@@ -286,9 +290,13 @@ static void vc4_txp_connector_atomic_commit(struct drm_connector *conn, + 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; ++ const struct vc4_txp_data *txp_data = txp->data; + struct drm_gem_dma_object *gem; struct drm_display_mode *mode; -@@ -379,43 +382,42 @@ static const struct drm_crtc_funcs vc4_txp_crtc_funcs = { - .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, + struct drm_framebuffer *fb; ++ unsigned int hdisplay; ++ unsigned int vdisplay; ++ dma_addr_t addr; + u32 ctrl; + int idx; + int i; +@@ -308,9 +316,11 @@ static void vc4_txp_connector_atomic_commit(struct drm_connector *conn, + return; + + ctrl = TXP_GO | TXP_EI | +- VC4_SET_FIELD(0xf, TXP_BYTE_ENABLE) | + VC4_SET_FIELD(txp_fmtsi, TXP_FORMAT); + ++ if (txp_data->has_byte_enable) ++ ctrl |= VC4_SET_FIELD(0xf, TXP_BYTE_ENABLE); ++ + if (fb->format->has_alpha) + ctrl |= TXP_ALPHA_ENABLE; + else +@@ -324,11 +334,25 @@ static void vc4_txp_connector_atomic_commit(struct drm_connector *conn, + return; + + gem = drm_fb_dma_get_gem_obj(fb, 0); +- TXP_WRITE(TXP_DST_PTR, gem->dma_addr + fb->offsets0); ++ addr = gem->dma_addr + fb->offsets0; ++ ++ TXP_WRITE(TXP_DST_PTR, lower_32_bits(addr)); ++ ++ if (txp_data->supports_40bit_addresses) ++ TXP_WRITE(txp_data->high_addr_ptr_reg, upper_32_bits(addr) & 0xff); ++ + TXP_WRITE(TXP_DST_PITCH, fb->pitches0); ++ ++ hdisplay = mode->hdisplay ?: 1; ++ vdisplay = mode->vdisplay ?: 1; ++ if (txp_data->size_minus_one) { ++ hdisplay -= 1; ++ vdisplay -= 1; ++ } ++ + TXP_WRITE(TXP_DIM, +- VC4_SET_FIELD(mode->hdisplay, TXP_WIDTH) | +- VC4_SET_FIELD(mode->vdisplay, TXP_HEIGHT)); ++ VC4_SET_FIELD(hdisplay, TXP_WIDTH) | ++ VC4_SET_FIELD(vdisplay, TXP_HEIGHT)); + + TXP_WRITE(TXP_DST_CTRL, ctrl); + +@@ -362,6 +386,7 @@ static const struct drm_connector_funcs vc4_txp_connector_funcs = { + static void vc4_txp_encoder_disable(struct drm_encoder *encoder) + { + struct drm_device *drm = encoder->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_txp *txp = encoder_to_vc4_txp(encoder); + int idx; + +@@ -380,7 +405,8 @@ static void vc4_txp_encoder_disable(struct drm_encoder *encoder) + WARN_ON(TXP_READ(TXP_DST_CTRL) & TXP_BUSY); + } + +- TXP_WRITE(TXP_DST_CTRL, TXP_POWERDOWN); ++ if (vc4->gen < VC4_GEN_6) ++ TXP_WRITE(TXP_DST_CTRL, TXP_POWERDOWN); + + drm_dev_exit(idx); + } +@@ -484,17 +510,49 @@ static irqreturn_t vc4_txp_interrupt(int irq, void *data) + return IRQ_HANDLED; + } + +-const struct vc4_crtc_data vc4_txp_crtc_data = { +- .name = "txp", +- .debugfs_name = "txp_regs", +- .hvs_available_channels = BIT(2), +- .hvs_output = 2, ++const struct vc4_txp_data bcm2712_mop_data = { ++ .base = { ++ .name = "mop", ++ .debugfs_name = "mop_regs", ++ .hvs_available_channels = BIT(2), ++ .hvs_output = 2, ++ }, ++ .encoder_type = VC4_ENCODER_TYPE_TXP0, ++ .high_addr_ptr_reg = TXP_DST_PTR_HIGH_MOP, ++ .has_byte_enable = true, ++ .size_minus_one = true, ++ .supports_40bit_addresses = true, ++}; ++ ++const struct vc4_txp_data bcm2712_moplet_data = { ++ .base = { ++ .name = "moplet", ++ .debugfs_name = "moplet_regs", ++ .hvs_available_channels = BIT(1), ++ .hvs_output = 4, ++ }, ++ .encoder_type = VC4_ENCODER_TYPE_TXP1, ++ .high_addr_ptr_reg = TXP_DST_PTR_HIGH_MOPLET, ++ .size_minus_one = true, ++ .supports_40bit_addresses = true, ++}; ++ ++const struct vc4_txp_data bcm2835_txp_data = { ++ .base = { ++ .name = "txp", ++ .debugfs_name = "txp_regs", ++ .hvs_available_channels = BIT(2), ++ .hvs_output = 2, ++ }, ++ .encoder_type = VC4_ENCODER_TYPE_TXP0, ++ .has_byte_enable = true, }; - static int vc4_txp_atomic_check(struct drm_crtc *crtc, -- struct drm_crtc_state *state) -+ struct drm_atomic_state *state) + static int vc4_txp_bind(struct device *dev, struct device *master, void *data) { -- 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); - int ret; + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = dev_get_drvdata(master); ++ const struct vc4_txp_data *txp_data; + struct vc4_encoder *vc4_encoder; + struct drm_encoder *encoder; + struct vc4_crtc *vc4_crtc; +@@ -509,6 +567,11 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data) + if (!txp) + return -ENOMEM; - ret = vc4_hvs_atomic_check(crtc, state); ++ txp_data = of_device_get_match_data(dev); ++ if (!txp_data) ++ return -ENODEV; ++ ++ txp->data = txp_data; + txp->pdev = pdev; + txp->regs = vc4_ioremap_regs(pdev, 0); + if (IS_ERR(txp->regs)) +@@ -519,13 +582,13 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data) + vc4_crtc->regset.regs = txp_regs; + vc4_crtc->regset.nregs = ARRAY_SIZE(txp_regs); + +- ret = vc4_crtc_init(drm, pdev, vc4_crtc, &vc4_txp_crtc_data, ++ ret = vc4_crtc_init(drm, pdev, vc4_crtc, &txp_data->base, + &vc4_txp_crtc_funcs, &vc4_txp_crtc_helper_funcs, true); if (ret) return ret; -- state->no_vblank = true; -- vc4_state->feed_txp = true; -+ crtc_state->no_vblank = true; + vc4_encoder = &txp->encoder; +- txp->encoder.type = VC4_ENCODER_TYPE_TXP; ++ txp->encoder.type = txp_data->encoder_type; + + encoder = &vc4_encoder->base; + encoder->possible_crtcs = drm_crtc_mask(&vc4_crtc->base); +@@ -579,7 +642,9 @@ static void vc4_txp_remove(struct platform_device *pdev) + } + + static const struct of_device_id vc4_txp_dt_match = { +- { .compatible = "brcm,bcm2835-txp" }, ++ { .compatible = "brcm,bcm2712-mop", .data = &bcm2712_mop_data }, ++ { .compatible = "brcm,bcm2712-moplet", .data = &bcm2712_moplet_data }, ++ { .compatible = "brcm,bcm2835-txp", .data = &bcm2835_txp_data }, + { /* sentinel */ }, + }; + +diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c +index 04ac7805e6d5..14d268f80fa5 100644 +--- a/drivers/gpu/drm/vc4/vc4_v3d.c ++++ b/drivers/gpu/drm/vc4/vc4_v3d.c +@@ -127,7 +127,7 @@ static int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused) + int + vc4_v3d_pm_get(struct vc4_dev *vc4) + { +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; - return 0; - } + mutex_lock(&vc4->power_lock); +@@ -148,7 +148,7 @@ vc4_v3d_pm_get(struct vc4_dev *vc4) + void + vc4_v3d_pm_put(struct vc4_dev *vc4) + { +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; - static void vc4_txp_atomic_enable(struct drm_crtc *crtc, -- struct drm_crtc_state *old_state) -+ struct drm_atomic_state *state) + mutex_lock(&vc4->power_lock); +@@ -178,7 +178,7 @@ int vc4_v3d_get_bin_slot(struct vc4_dev *vc4) + uint64_t seqno = 0; + struct vc4_exec_info *exec; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + try_again: +@@ -325,7 +325,7 @@ int vc4_v3d_bin_bo_get(struct vc4_dev *vc4, bool *used) { - drm_crtc_vblank_on(crtc); -- vc4_hvs_atomic_enable(crtc, old_state); -+ vc4_hvs_atomic_enable(crtc, state); - } + int ret = 0; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + mutex_lock(&vc4->bin_bo_lock); +@@ -360,7 +360,7 @@ static void bin_bo_release(struct kref *ref) - static void vc4_txp_atomic_disable(struct drm_crtc *crtc, -- struct drm_crtc_state *old_state) -+ struct drm_atomic_state *state) + void vc4_v3d_bin_bo_put(struct vc4_dev *vc4) { - struct drm_device *dev = crtc->dev; +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; - /* Disable vblank irq handling before crtc is disabled. */ - drm_crtc_vblank_off(crtc); + mutex_lock(&vc4->bin_bo_lock); +diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c +index 7dff3ca5af6b..722c0f8909d2 100644 +--- a/drivers/gpu/drm/vc4/vc4_validate.c ++++ b/drivers/gpu/drm/vc4/vc4_validate.c +@@ -109,7 +109,7 @@ vc4_use_bo(struct vc4_exec_info *exec, uint32_t hindex) + struct drm_gem_dma_object *obj; + struct vc4_bo *bo; -- vc4_hvs_atomic_disable(crtc, old_state); -+ vc4_hvs_atomic_disable(crtc, state); +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return NULL; - /* - * Make sure we issue a vblank event after disabling the CRTC if -@@ -433,6 +435,7 @@ static void vc4_txp_atomic_disable(struct drm_crtc *crtc, + if (hindex >= exec->bo_count) { +@@ -169,7 +169,7 @@ vc4_check_tex_size(struct vc4_exec_info *exec, struct drm_gem_dma_object *fbo, + uint32_t utile_w = utile_width(cpp); + uint32_t utile_h = utile_height(cpp); - static const struct drm_crtc_helper_funcs vc4_txp_crtc_helper_funcs = { - .atomic_check = vc4_txp_atomic_check, -+ .atomic_begin = vc4_hvs_atomic_begin, - .atomic_flush = vc4_hvs_atomic_flush, - .atomic_enable = vc4_txp_atomic_enable, - .atomic_disable = vc4_txp_atomic_disable, -@@ -478,6 +481,7 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data) - - vc4_crtc->pdev = pdev; - vc4_crtc->data = &vc4_txp_crtc_data; -+ vc4_crtc->feeds_txp = true; +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return false; - txp->pdev = pdev; + /* The shaded vertex format stores signed 12.4 fixed point +@@ -495,7 +495,7 @@ vc4_validate_bin_cl(struct drm_device *dev, + uint32_t dst_offset = 0; + uint32_t src_offset = 0; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + while (src_offset < len) { +@@ -942,7 +942,7 @@ vc4_validate_shader_recs(struct drm_device *dev, + uint32_t i; + int ret = 0; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + for (i = 0; i < exec->shader_state_count; i++) { +diff --git a/drivers/gpu/drm/vc4/vc4_validate_shaders.c b/drivers/gpu/drm/vc4/vc4_validate_shaders.c +index 9745f8810eca..2d74e786914c 100644 +--- a/drivers/gpu/drm/vc4/vc4_validate_shaders.c ++++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c +@@ -786,7 +786,7 @@ vc4_validate_shader(struct drm_gem_dma_object *shader_obj) + struct vc4_validated_shader_info *validated_shader = NULL; + struct vc4_shader_validation_state validation_state; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return NULL; + + memset(&validation_state, 0, sizeof(validation_state)); diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c -index bd5b8eb58b18..255e5c6c48e0 100644 +index 268f18b10ee0..b4c336b15cfe 100644 --- a/drivers/gpu/drm/vc4/vc4_vec.c +++ b/drivers/gpu/drm/vc4/vc4_vec.c -@@ -45,6 +45,7 @@ - #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) -@@ -65,15 +66,37 @@ +@@ -67,7 +67,7 @@ #define VEC_CONFIG0_YCDELAY BIT(4) #define VEC_CONFIG0_RAMPEN BIT(2) #define VEC_CONFIG0_YCDIS BIT(2) @@ -67389,157 +96848,34 @@ +#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 - -@@ -116,6 +139,14 @@ - - #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 - -@@ -154,9 +185,16 @@ + #define VEC_CONFIG0_PAL_M_STD 2 +@@ -186,6 +186,8 @@ #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; -@@ -165,8 +203,6 @@ struct vc4_vec { - - struct clk *clock; - -- const struct vc4_vec_tv_mode *tv_mode; -- - struct debugfs_regset32 regset; + struct vc4_vec_variant { + u32 dac_config; }; - -@@ -206,13 +242,20 @@ to_vc4_vec_connector(struct drm_connector *connector) - 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, +@@ -234,6 +236,7 @@ enum vc4_vec_tv_mode_id { + VC4_VEC_TV_MODE_PAL_60, + VC4_VEC_TV_MODE_PAL_N, + VC4_VEC_TV_MODE_SECAM, ++ VC4_VEC_TV_MODE_MONOCHROME, }; struct vc4_vec_tv_mode { -- const struct drm_display_mode *mode; -- void (*mode_set)(struct vc4_vec *vec); -+ const struct drm_display_mode *interlaced_mode; -+ const struct drm_display_mode *progressive_mode; -+ u32 config0; -+ u32 config1; -+ u32 custom_freq; - }; - - static const struct debugfs_reg32 vec_regs = { -@@ -242,66 +285,126 @@ static const struct debugfs_reg32 vec_regs = { +@@ -271,6 +274,18 @@ static const struct debugfs_reg32 vec_regs = { 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 = { -- DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500, -+static const struct drm_display_mode drm_mode_480i = { -+ DRM_MODE("720x480i", 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 drm_mode_240p = { + DRM_MODE("720x240", DRM_MODE_TYPE_DRIVER, 13500, + 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0, + 240, 240 + 3, 240 + 3 + 3, 262, 0, 0) +}; - --static const struct drm_display_mode pal_mode = { -- DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500, -+static const struct drm_display_mode drm_mode_576i = { -+ DRM_MODE("720x576i", 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 drm_display_mode drm_mode_288p = { + DRM_MODE("720x288", DRM_MODE_TYPE_DRIVER, 13500, + 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0, @@ -67547,89 +96883,49 @@ +}; + 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, -+ .interlaced_mode = &drm_mode_480i, -+ .progressive_mode = &drm_mode_240p, -+ .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, -+ .interlaced_mode = &drm_mode_480i, -+ .progressive_mode = &drm_mode_240p, -+ .config0 = VEC_CONFIG0_NTSC_STD, -+ .config1 = VEC_CONFIG1_C_CVBS_CVBS, -+ }, -+ VC4_VEC_TV_MODE_NTSC_443 = { -+ /* NTSC with PAL chroma frequency */ -+ .interlaced_mode = &drm_mode_480i, -+ .progressive_mode = &drm_mode_240p, -+ .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, -+ .interlaced_mode = &drm_mode_576i, -+ .progressive_mode = &drm_mode_288p, -+ .config0 = VEC_CONFIG0_PAL_BDGHI_STD, -+ .config1 = VEC_CONFIG1_C_CVBS_CVBS, + { + .mode = DRM_MODE_TV_MODE_NTSC, +@@ -324,6 +339,22 @@ static const struct vc4_vec_tv_mode vc4_vec_tv_modes = { + .config1 = VEC_CONFIG1_C_CVBS_CVBS, + .custom_freq = 0x29c71c72, }, - VC4_VEC_TV_MODE_PAL_M = { -- .mode = &pal_mode, -- .mode_set = vc4_vec_pal_m_mode_set, -+ .interlaced_mode = &drm_mode_480i, -+ .progressive_mode = &drm_mode_240p, -+ .config0 = VEC_CONFIG0_PAL_M_STD, ++ { ++ /* 50Hz mono */ ++ .mode = DRM_MODE_TV_MODE_MONOCHROME, ++ .expected_htotal = 864, ++ .config0 = VEC_CONFIG0_PAL_BDGHI_STD | VEC_CONFIG0_BURDIS | ++ VEC_CONFIG0_CHRDIS, + .config1 = VEC_CONFIG1_C_CVBS_CVBS, + }, -+ VC4_VEC_TV_MODE_PAL_N = { -+ .interlaced_mode = &drm_mode_576i, -+ .progressive_mode = &drm_mode_288p, -+ .config0 = VEC_CONFIG0_PAL_N_STD, ++ { ++ /* 60Hz mono */ ++ .mode = DRM_MODE_TV_MODE_MONOCHROME, ++ .expected_htotal = 858, ++ .config0 = VEC_CONFIG0_PAL_M_STD | VEC_CONFIG0_BURDIS | ++ VEC_CONFIG0_CHRDIS, + .config1 = VEC_CONFIG1_C_CVBS_CVBS, + }, -+ VC4_VEC_TV_MODE_PAL60 = { -+ /* PAL-M with chroma frequency of regular PAL */ -+ .interlaced_mode = &drm_mode_480i, -+ .progressive_mode = &drm_mode_240p, -+ .config0 = VEC_CONFIG0_PAL_M_STD, -+ .config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ, -+ .custom_freq = 0x2a098acb, -+ }, -+ VC4_VEC_TV_MODE_SECAM = { -+ .interlaced_mode = &drm_mode_576i, -+ .progressive_mode = &drm_mode_288p, -+ .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 + static inline const struct vc4_vec_tv_mode * +@@ -351,8 +382,38 @@ static const struct drm_prop_enum_list legacy_tv_mode_names = { + { VC4_VEC_TV_MODE_PAL_M, "PAL-M", }, + { VC4_VEC_TV_MODE_PAL_N, "PAL-N", }, + { VC4_VEC_TV_MODE_SECAM, "SECAM", }, ++ { VC4_VEC_TV_MODE_MONOCHROME, "Mono", }, + }; + ++enum drm_connector_tv_mode +vc4_vec_get_default_mode(struct drm_connector *connector) +{ -+ int i; ++ if (connector->cmdline_mode.tv_mode_specified) { ++ return connector->cmdline_mode.tv_mode; ++ } else if (vc4_vec_tv_norm) { ++ int ret; + -+ if (vc4_vec_tv_norm) { -+ for (i = 0; i < ARRAY_SIZE(tv_mode_names); i++) -+ if (strcmp(vc4_vec_tv_norm, tv_mode_namesi) == 0) -+ return (enum vc4_vec_tv_mode_id) i; ++ ret = drm_get_tv_mode_from_name(vc4_vec_tv_norm, strlen(vc4_vec_tv_norm)); ++ if (ret >= 0) ++ return ret; + } else if (connector->cmdline_mode.specified && + ((connector->cmdline_mode.refresh_specified && + (connector->cmdline_mode.refresh == 25 || @@ -67641,297 +96937,188 @@ + * 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; ++ return DRM_MODE_TV_MODE_PAL; + } + + /* in all other cases, default to NTSC */ -+ return VC4_VEC_TV_MODE_NTSC; ++ return DRM_MODE_TV_MODE_NTSC; +} + static enum drm_connector_status vc4_vec_connector_detect(struct drm_connector *connector, bool force) { -@@ -317,31 +420,74 @@ static void vc4_vec_connector_destroy(struct drm_connector *connector) - static int vc4_vec_connector_get_modes(struct drm_connector *connector) +@@ -406,6 +467,10 @@ vc4_vec_connector_set_property(struct drm_connector *connector, + state->tv.mode = DRM_MODE_TV_MODE_SECAM; + break; + ++ case VC4_VEC_TV_MODE_MONOCHROME: ++ state->tv.mode = DRM_MODE_TV_MODE_MONOCHROME; ++ break; ++ + default: + return -EINVAL; + } +@@ -414,48 +479,55 @@ vc4_vec_connector_set_property(struct drm_connector *connector, + } + + static int +-vc4_vec_connector_get_property(struct drm_connector *connector, +- const struct drm_connector_state *state, +- struct drm_property *property, +- uint64_t *val) ++vc4_vec_generic_tv_mode_to_legacy(enum drm_connector_tv_mode tv_mode) { - struct drm_connector_state *state = connector->state; -- struct drm_display_mode *mode; +- struct vc4_vec *vec = connector_to_vc4_vec(connector); - -- mode = drm_mode_duplicate(connector->dev, -- vc4_vec_tv_modesstate->tv.mode.mode); -- if (!mode) { -+ struct drm_display_mode *interlaced_mode, *progressive_mode; -+ -+ interlaced_mode = -+ drm_mode_duplicate(connector->dev, -+ vc4_vec_tv_modesstate->tv.mode.interlaced_mode); -+ progressive_mode = -+ drm_mode_duplicate(connector->dev, -+ vc4_vec_tv_modesstate->tv.mode.progressive_mode); -+ if (!interlaced_mode || !progressive_mode) { - DRM_ERROR("Failed to create a new display mode\n"); -+ drm_mode_destroy(connector->dev, interlaced_mode); -+ drm_mode_destroy(connector->dev, progressive_mode); - return -ENOMEM; - } +- if (property != vec->legacy_tv_mode_property) +- return -EINVAL; +- +- switch (state->tv.mode) { ++ switch (tv_mode) { + case DRM_MODE_TV_MODE_NTSC: +- *val = VC4_VEC_TV_MODE_NTSC; +- break; ++ return VC4_VEC_TV_MODE_NTSC; -- drm_mode_probed_add(connector, mode); -+ if (connector->cmdline_mode.specified && -+ connector->cmdline_mode.refresh_specified && -+ !connector->cmdline_mode.interlace) -+ /* progressive mode set at boot, let's make it preferred */ -+ progressive_mode->type |= DRM_MODE_TYPE_PREFERRED; -+ else -+ /* otherwise, interlaced mode is preferred */ -+ interlaced_mode->type |= DRM_MODE_TYPE_PREFERRED; + case DRM_MODE_TV_MODE_NTSC_443: +- *val = VC4_VEC_TV_MODE_NTSC_443; +- break; ++ return VC4_VEC_TV_MODE_NTSC_443; + + case DRM_MODE_TV_MODE_NTSC_J: +- *val = VC4_VEC_TV_MODE_NTSC_J; +- break; ++ return VC4_VEC_TV_MODE_NTSC_J; + + case DRM_MODE_TV_MODE_PAL: +- *val = VC4_VEC_TV_MODE_PAL; +- break; ++ return VC4_VEC_TV_MODE_PAL; + + case DRM_MODE_TV_MODE_PAL_M: +- *val = VC4_VEC_TV_MODE_PAL_M; +- break; ++ return VC4_VEC_TV_MODE_PAL_M; + + case DRM_MODE_TV_MODE_PAL_N: +- *val = VC4_VEC_TV_MODE_PAL_N; +- break; ++ return VC4_VEC_TV_MODE_PAL_N; + + case DRM_MODE_TV_MODE_SECAM: +- *val = VC4_VEC_TV_MODE_SECAM; +- break; ++ return VC4_VEC_TV_MODE_SECAM; + -+ drm_mode_probed_add(connector, interlaced_mode); -+ drm_mode_probed_add(connector, progressive_mode); ++ case DRM_MODE_TV_MODE_MONOCHROME: ++ return VC4_VEC_TV_MODE_MONOCHROME; - return 1; + default: + return -EINVAL; + } ++} ++ ++static int ++vc4_vec_connector_get_property(struct drm_connector *connector, ++ const struct drm_connector_state *state, ++ struct drm_property *property, ++ uint64_t *val) ++{ ++ struct vc4_vec *vec = connector_to_vc4_vec(connector); ++ enum vc4_vec_tv_mode_id legacy_mode; ++ ++ if (property != vec->legacy_tv_mode_property) ++ return -EINVAL; ++ ++ legacy_mode = vc4_vec_generic_tv_mode_to_legacy(state->tv.mode); ++ if (legacy_mode < 0) ++ return legacy_mode; ++ ++ *val = legacy_mode; + + return 0; } +@@ -470,14 +542,38 @@ static const struct drm_connector_funcs vc4_vec_connector_funcs = { + .atomic_set_property = vc4_vec_connector_set_property, + }; -+static void vc4_vec_connector_reset(struct drm_connector *connector) ++static int vc4_vec_connector_get_modes(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); -+} ++ struct drm_display_mode *mode; ++ int count = drm_connector_helper_tv_get_modes(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); ++ mode = drm_mode_duplicate(connector->dev, &drm_mode_240p); ++ if (!mode) ++ return -ENOMEM; + -+ if (new_state->crtc && old_state->tv.mode != new_state->tv.mode) { -+ struct drm_crtc_state *crtc_state = -+ drm_atomic_get_new_crtc_state(state, new_state->crtc); ++ drm_mode_probed_add(connector, mode); ++ count++; + -+ crtc_state->mode_changed = true; -+ } ++ mode = drm_mode_duplicate(connector->dev, &drm_mode_288p); ++ if (!mode) ++ return -ENOMEM; + -+ return 0; ++ drm_mode_probed_add(connector, mode); ++ count++; ++ ++ return count; +} + - 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, + .atomic_check = drm_atomic_helper_connector_tv_check, +- .get_modes = drm_connector_helper_tv_get_modes, ++ .get_modes = vc4_vec_connector_get_modes, }; - static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev, -@@ -367,8 +513,7 @@ static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev, - - drm_object_attach_property(&connector->base, - dev->mode_config.tv_mode_property, -- VC4_VEC_TV_MODE_NTSC); -- vec->tv_mode = &vc4_vec_tv_modesVC4_VEC_TV_MODE_NTSC; -+ vc4_vec_get_default_mode(connector)); - - drm_connector_attach_encoder(connector, vec->encoder); - -@@ -401,6 +546,7 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder) + static int vc4_vec_connector_init(struct drm_device *dev, struct vc4_vec *vec) { - 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; + struct drm_connector *connector = &vec->connector; ++ enum vc4_vec_tv_mode_id legacy_default_mode; ++ enum drm_connector_tv_mode default_mode; + struct drm_property *prop; int ret; - ret = pm_runtime_get_sync(&vec->pdev->dev); -@@ -449,17 +595,25 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder) - VEC_WRITE(VEC_CLMP0_START, 0xac); - VEC_WRITE(VEC_CLMP0_END, 0xec); - VEC_WRITE(VEC_CONFIG2, -- VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS); -+ VEC_CONFIG2_UV_DIG_DIS | -+ VEC_CONFIG2_RGB_DIG_DIS | -+ ((encoder->crtc->state->adjusted_mode.flags & -+ DRM_MODE_FLAG_INTERLACE) ? 0 : VEC_CONFIG2_PROG_SCAN)); - 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_modestv_mode.config0); -+ VEC_WRITE(VEC_CONFIG1, vc4_vec_tv_modestv_mode.config1); -+ if (vc4_vec_tv_modestv_mode.custom_freq != 0) { -+ VEC_WRITE(VEC_FREQ3_2, -+ (vc4_vec_tv_modestv_mode.custom_freq >> 16) & -+ 0xffff); -+ VEC_WRITE(VEC_FREQ1_0, -+ vc4_vec_tv_modestv_mode.custom_freq & 0xffff); -+ } - - VEC_WRITE(VEC_DAC_MISC, - VEC_DAC_MISC_VID_ACT | VEC_DAC_MISC_DAC_RST_N); -@@ -467,34 +621,80 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder) - } +@@ -490,9 +586,17 @@ static int vc4_vec_connector_init(struct drm_device *dev, struct vc4_vec *vec) + drm_connector_helper_add(connector, &vc4_vec_connector_helper_funcs); --static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder, -- const struct drm_display_mode *mode, -- struct drm_display_mode *adjusted_mode) --{ -- 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_modesconn_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_modesconn_state->tv.mode; -+ const struct drm_display_mode *reference_mode = -+ vc4_vec_tv_modesconn_state->tv.mode.interlaced_mode; -+ -+ if (crtc_state->adjusted_mode.crtc_clock != reference_mode->clock || -+ crtc_state->adjusted_mode.crtc_htotal != reference_mode->htotal || -+ crtc_state->adjusted_mode.crtc_hdisplay % 4 != 0 || -+ crtc_state->adjusted_mode.crtc_hsync_end - -+ crtc_state->adjusted_mode.crtc_hsync_start < 1) -+ return -EINVAL; - -- if (conn_state->crtc && -- !drm_mode_equal(vec_mode->mode, &crtc_state->adjusted_mode)) -+ switch (reference_mode->vtotal) { -+ case 525: -+ if (crtc_state->adjusted_mode.crtc_vdisplay < 1 || -+ crtc_state->adjusted_mode.crtc_vdisplay > 253 || -+ crtc_state->adjusted_mode.crtc_vsync_start - -+ crtc_state->adjusted_mode.crtc_vdisplay < 1 || -+ crtc_state->adjusted_mode.crtc_vsync_end - -+ crtc_state->adjusted_mode.crtc_vsync_start != 3 || -+ crtc_state->adjusted_mode.crtc_vtotal - -+ crtc_state->adjusted_mode.crtc_vsync_end < 4 || -+ crtc_state->adjusted_mode.crtc_vtotal > 262) -+ return -EINVAL; -+ -+ if ((crtc_state->adjusted_mode.flags & -+ DRM_MODE_FLAG_INTERLACE) && -+ (crtc_state->adjusted_mode.vdisplay % 2 != 0 || -+ crtc_state->adjusted_mode.vsync_start % 2 != 1 || -+ crtc_state->adjusted_mode.vsync_end % 2 != 1 || -+ crtc_state->adjusted_mode.vtotal % 2 != 1)) -+ return -EINVAL; -+ -+ /* progressive mode is hard-wired to 262 total lines */ -+ if (!(crtc_state->adjusted_mode.flags & -+ DRM_MODE_FLAG_INTERLACE) && -+ crtc_state->adjusted_mode.crtc_vtotal != 262) -+ return -EINVAL; -+ -+ break; -+ -+ case 625: -+ if (crtc_state->adjusted_mode.crtc_vdisplay < 1 || -+ crtc_state->adjusted_mode.crtc_vdisplay > 305 || -+ crtc_state->adjusted_mode.crtc_vsync_start - -+ crtc_state->adjusted_mode.crtc_vdisplay < 1 || -+ crtc_state->adjusted_mode.crtc_vsync_end - -+ crtc_state->adjusted_mode.crtc_vsync_start != 3 || -+ crtc_state->adjusted_mode.crtc_vtotal - -+ crtc_state->adjusted_mode.crtc_vsync_end < 2 || -+ crtc_state->adjusted_mode.crtc_vtotal > 312) -+ return -EINVAL; ++ default_mode = vc4_vec_get_default_mode(connector); ++ if (default_mode < 0) ++ return default_mode; + -+ if ((crtc_state->adjusted_mode.flags & -+ DRM_MODE_FLAG_INTERLACE) && -+ (crtc_state->adjusted_mode.vdisplay % 2 != 0 || -+ crtc_state->adjusted_mode.vsync_start % 2 != 0 || -+ crtc_state->adjusted_mode.vsync_end % 2 != 0 || -+ crtc_state->adjusted_mode.vtotal % 2 != 1)) -+ return -EINVAL; -+ -+ /* progressive mode is hard-wired to 312 total lines */ -+ if (!(crtc_state->adjusted_mode.flags & -+ DRM_MODE_FLAG_INTERLACE) && -+ crtc_state->adjusted_mode.crtc_vtotal != 312) -+ return -EINVAL; + drm_object_attach_property(&connector->base, + dev->mode_config.tv_mode_property, +- DRM_MODE_TV_MODE_NTSC); ++ default_mode); + -+ break; ++ legacy_default_mode = vc4_vec_generic_tv_mode_to_legacy(default_mode); ++ if (legacy_default_mode < 0) ++ return legacy_default_mode; + + prop = drm_property_create_enum(dev, 0, "mode", + legacy_tv_mode_names, +@@ -501,7 +605,9 @@ static int vc4_vec_connector_init(struct drm_device *dev, struct vc4_vec *vec) + return -ENOMEM; + vec->legacy_tv_mode_property = prop; + +- drm_object_attach_property(&connector->base, prop, VC4_VEC_TV_MODE_NTSC); ++ drm_object_attach_property(&connector->base, prop, legacy_default_mode); + -+ default: - return -EINVAL; -+ } ++ drm_connector_attach_tv_margin_properties(connector); - return 0; - } -@@ -502,21 +702,25 @@ static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder, - 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 */ }, - }; + drm_connector_attach_encoder(connector, &vec->encoder.base); - static int vc4_vec_bind(struct device *dev, struct device *master, void *data) -@@ -546,6 +750,8 @@ static int vc4_vec_bind(struct device *dev, struct device *master, void *data) - 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); -@@ -625,3 +831,10 @@ struct platform_driver vc4_vec_driver = { +@@ -754,7 +860,8 @@ static int vc4_vec_bind(struct device *dev, struct device *master, void *data) + BIT(DRM_MODE_TV_MODE_PAL) | + BIT(DRM_MODE_TV_MODE_PAL_M) | + BIT(DRM_MODE_TV_MODE_PAL_N) | +- BIT(DRM_MODE_TV_MODE_SECAM)); ++ BIT(DRM_MODE_TV_MODE_SECAM) | ++ BIT(DRM_MODE_TV_MODE_MONOCHROME)); + if (ret) + return ret; + +@@ -825,3 +932,10 @@ struct platform_driver vc4_vec_driver = { .of_match_table = vc4_vec_dt_match, }, }; @@ -68123,353 +97310,11 @@ + /* Rec 2020 */ + VC_IMAGE_YUVINFO_CSC_REC_2020 = 9, +}; -diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c -index f84b7e61311b..4bf74836bd53 100644 ---- a/drivers/gpu/drm/virtio/virtgpu_display.c -+++ b/drivers/gpu/drm/virtio/virtgpu_display.c -@@ -95,12 +95,12 @@ static void virtio_gpu_crtc_mode_set_nofb(struct drm_crtc *crtc) - } - - 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; -@@ -111,13 +111,13 @@ static void virtio_gpu_crtc_atomic_disable(struct drm_crtc *crtc, - } - - 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 --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c -index 1ae5cd47d954..758d8a98d96b 100644 ---- a/drivers/gpu/drm/vkms/vkms_crtc.c -+++ b/drivers/gpu/drm/vkms/vkms_crtc.c -@@ -169,9 +169,11 @@ static const struct drm_crtc_funcs vkms_crtc_funcs = { - }; - - 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; -@@ -179,12 +181,12 @@ static int vkms_crtc_atomic_check(struct drm_crtc *crtc, - 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); - -@@ -200,8 +202,8 @@ static int vkms_crtc_atomic_check(struct drm_crtc *crtc, - 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) -@@ -215,19 +217,19 @@ static int vkms_crtc_atomic_check(struct drm_crtc *crtc, - } - - 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); - -@@ -238,7 +240,7 @@ static void vkms_crtc_atomic_begin(struct drm_crtc *crtc, - } - - 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 --git a/drivers/gpu/drm/vkms/vkms_writeback.c b/drivers/gpu/drm/vkms/vkms_writeback.c -index 094fa4aa061d..c0a53a2cbbf1 100644 ---- a/drivers/gpu/drm/vkms/vkms_writeback.c -+++ b/drivers/gpu/drm/vkms/vkms_writeback.c -@@ -1,6 +1,8 @@ - // 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> -@@ -100,8 +102,10 @@ static void vkms_wb_cleanup_job(struct drm_writeback_connector *connector, - } - - 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; -@@ -117,7 +121,7 @@ static void vkms_wb_atomic_commit(struct drm_connector *conn, - 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 --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c -index e58112997c88..415078e9ea39 100644 ---- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c -+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c -@@ -522,8 +522,10 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane, - - - 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 & -@@ -552,13 +554,13 @@ int vmw_du_crtc_atomic_check(struct drm_crtc *crtc, - - - 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 --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h -index 3ee03227607c..03f3694015ce 100644 ---- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h -+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h -@@ -473,11 +473,11 @@ void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps, - 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 --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c -index c4017c7a24db..9d1de5b5cc6a 100644 ---- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c -+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c -@@ -214,7 +214,7 @@ static void vmw_ldu_crtc_mode_set_nofb(struct drm_crtc *crtc) - * 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) - { - } - -@@ -224,7 +224,7 @@ static void vmw_ldu_crtc_atomic_enable(struct drm_crtc *crtc, - * @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 --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c -index 4bf0f5ec4fc2..dfa55fb80b07 100644 ---- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c -+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c -@@ -279,7 +279,7 @@ static void vmw_sou_crtc_helper_prepare(struct drm_crtc *crtc) - * 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) - { - } - -@@ -289,7 +289,7 @@ static void vmw_sou_crtc_atomic_enable(struct drm_crtc *crtc, - * @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 --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c -index cf3aafd00837..5b04ec047ef3 100644 ---- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c -+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c -@@ -408,12 +408,12 @@ static void vmw_stdu_crtc_helper_prepare(struct drm_crtc *crtc) - } - - 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 --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c -index 205c72a249b7..d85909af1800 100644 ---- a/drivers/gpu/drm/xlnx/zynqmp_disp.c -+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c -@@ -1441,7 +1441,7 @@ static int zynqmp_disp_crtc_setup_clock(struct drm_crtc *crtc, - - 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; -@@ -1473,8 +1473,10 @@ zynqmp_disp_crtc_atomic_enable(struct drm_crtc *crtc, - - 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; - -@@ -1504,21 +1506,21 @@ zynqmp_disp_crtc_atomic_disable(struct drm_crtc *crtc, - } - - 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 --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c -index 5259ff2825f9..904f62f3bfc1 100644 ---- a/drivers/gpu/drm/zte/zx_vou.c -+++ b/drivers/gpu/drm/zte/zx_vou.c -@@ -350,7 +350,7 @@ static inline void vou_chn_set_update(struct zx_crtc *zcrtc) - } - - 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; -@@ -455,7 +455,7 @@ static void zx_crtc_atomic_enable(struct drm_crtc *crtc, - } - - 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; -@@ -473,7 +473,7 @@ static void zx_crtc_atomic_disable(struct drm_crtc *crtc, - } - - 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 --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h -index 370ec4402ebe..f87d2205be42 100644 +index 72046039d1be..c3d576c6f1ec 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h -@@ -221,6 +221,9 @@ +@@ -239,6 +239,9 @@ #define USB_VENDOR_ID_BAANTO 0x2453 #define USB_DEVICE_ID_BAANTO_MT_190W2 0x0100 @@ -68479,9 +97324,9 @@ #define USB_VENDOR_ID_BELKIN 0x050d #define USB_DEVICE_ID_FLIP_KVM 0x3201 -@@ -1270,6 +1273,9 @@ - #define USB_VENDOR_ID_XAT 0x2505 - #define USB_DEVICE_ID_XAT_CSR 0x0220 +@@ -1403,6 +1406,9 @@ + #define USB_VENDOR_ID_XIAOMI 0x2717 + #define USB_DEVICE_ID_MI_SILENT_MOUSE 0x5014 +#define USB_VENDOR_ID_XENTA 0x1d57 +#define USB_DEVICE_ID_AIRMOUSE_MX3 0xad03 @@ -68490,10 +97335,10 @@ #define USB_DEVICE_ID_XIN_MO_DUAL_ARCADE 0x05e1 #define USB_DEVICE_ID_THT_2P_ARCADE 0x75e1 diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c -index 84a30202e3db..fd02b2821daf 100644 +index e0bbf0c6345d..1d1949d62dfa 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c -@@ -41,6 +41,7 @@ static const struct hid_device_id hid_quirks = { +@@ -42,6 +42,7 @@ static const struct hid_device_id hid_quirks = { { 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 }, @@ -68501,7 +97346,7 @@ { 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 }, -@@ -194,6 +195,7 @@ static const struct hid_device_id hid_quirks = { +@@ -209,6 +210,7 @@ static const struct hid_device_id hid_quirks = { { 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 }, @@ -68510,7 +97355,7 @@ { 0 } }; diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c -index 009a0469d54f..1f0e61d1312d 100644 +index 257dd73e37bf..fb588ac24acc 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -45,7 +45,7 @@ @@ -68522,7 +97367,7 @@ module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644); MODULE_PARM_DESC(mousepoll, "Polling interval of mice"); -@@ -1114,7 +1114,9 @@ static int usbhid_start(struct hid_device *hid) +@@ -1112,7 +1112,9 @@ static int usbhid_start(struct hid_device *hid) */ switch (hid->collection->usage) { case HID_GD_MOUSE: @@ -68533,7 +97378,7 @@ interval = hid_mousepoll_interval; break; case HID_GD_JOYSTICK: -@@ -1126,6 +1128,7 @@ static int usbhid_start(struct hid_device *hid) +@@ -1124,6 +1126,7 @@ static int usbhid_start(struct hid_device *hid) interval = hid_kbpoll_interval; break; } @@ -68542,562 +97387,796 @@ ret = -ENOMEM; if (usb_endpoint_dir_in(endpoint)) { diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index 0c2b032ee617..bcba1433f076 100644 +index b7ce1654c48e..5b3cc16b9512 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig -@@ -1489,6 +1489,17 @@ config SENSORS_RASPBERRYPI_HWMON - 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 +@@ -2386,6 +2386,13 @@ config SENSORS_INTEL_M10_BMC_HWMON + sensors monitor various telemetry data of different components on the + card, e.g. board temperature, FPGA core temperature/voltage/current. + ++config SENSORS_RP1_ADC ++ tristate "RP1 ADC and temperature sensor driver" ++ depends on MFD_RP1 + help -+ 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. ++ Say yes here to enable support for the voltage and temperature ++ sensors of the Raspberry Pi RP1 peripheral chip. + - config SENSORS_SL28CPLD - tristate "Kontron sl28cpld hardware monitoring driver" - depends on MFD_SL28CPLD || COMPILE_TEST + if ACPI + + comment "ACPI drivers" diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index 9db2903b61e5..dc68c9788a5e 100644 +index cd8bfab85056..04bd32e1f93b 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile -@@ -157,6 +157,7 @@ obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o +@@ -179,6 +179,7 @@ obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o 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_RP1_ADC) += rp1-adc.o + obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o + obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o - obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o -diff --git a/drivers/hwmon/raspberrypi-hwmon.c b/drivers/hwmon/raspberrypi-hwmon.c -index d3a64a35f7a9..db3b03438dd0 100644 ---- a/drivers/hwmon/raspberrypi-hwmon.c -+++ b/drivers/hwmon/raspberrypi-hwmon.c -@@ -15,6 +15,36 @@ - #include <linux/workqueue.h> - #include <soc/bcm2835/raspberrypi-firmware.h> +diff --git a/drivers/hwmon/aht10.c b/drivers/hwmon/aht10.c +index f136bf3ff40a..558ef3af4486 100644 +--- a/drivers/hwmon/aht10.c ++++ b/drivers/hwmon/aht10.c +@@ -57,6 +57,12 @@ static const struct i2c_device_id aht10_id = { + }; + MODULE_DEVICE_TABLE(i2c, aht10_id); -+/* -+ * 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 ++static const struct of_device_id aht10_of_id = { ++ { .compatible = "aosong,aht10", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, aht10_of_id); ++ + /** + * struct aht10_data - All the data required to operate an AHT10/AHT20 chip + * @client: the i2c client associated with the AHT10/AHT20 +@@ -381,6 +387,7 @@ static int aht10_probe(struct i2c_client *client) + static struct i2c_driver aht10_driver = { + .driver = { + .name = "aht10", ++ .of_match_table = aht10_of_id, + }, + .probe = aht10_probe, + .id_table = aht10_id, +diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c +index 21b635046521..2b095b0dc80b 100644 +--- a/drivers/hwmon/ds1621.c ++++ b/drivers/hwmon/ds1621.c +@@ -378,6 +378,16 @@ static const struct i2c_device_id ds1621_id = { + }; + MODULE_DEVICE_TABLE(i2c, ds1621_id); + ++static const struct of_device_id ds1621_of_ids = { ++ { .compatible = "dallas,ds1621", }, ++ { .compatible = "dallas,ds1625", }, ++ { .compatible = "dallas,ds1631", }, ++ { .compatible = "dallas,ds1721", }, ++ { .compatible = "dallas,ds1731", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ds1621_of_ids); + -+#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__) + /* This is the driver that will be inserted */ + static struct i2c_driver ds1621_driver = { + .class = I2C_CLASS_HWMON, +diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c +index 29f0e4945f19..00e92ff352b0 100644 +--- a/drivers/hwmon/emc2305.c ++++ b/drivers/hwmon/emc2305.c +@@ -15,12 +15,13 @@ + static const unsigned short + emc2305_normal_i2c = { 0x27, 0x2c, 0x2d, 0x2e, 0x2f, 0x4c, 0x4d, I2C_CLIENT_END }; + ++#define EMC2305_REG_FAN_STATUS 0x24 ++#define EMC2305_REG_FAN_STALL_STATUS 0x25 + #define EMC2305_REG_DRIVE_FAIL_STATUS 0x27 + #define EMC2305_REG_VENDOR 0xfe + #define EMC2305_FAN_MAX 0xff + #define EMC2305_FAN_MIN 0x00 + #define EMC2305_FAN_MAX_STATE 10 +-#define EMC2305_DEVICE 0x34 + #define EMC2305_VENDOR 0x5d + #define EMC2305_REG_PRODUCT_ID 0xfd + #define EMC2305_TACH_REGS_UNUSE_BITS 3 +@@ -39,6 +40,7 @@ emc2305_normal_i2c = { 0x27, 0x2c, 0x2d, 0x2e, 0x2f, 0x4c, 0x4d, I2C_CLIENT_EN + #define EMC2305_RPM_FACTOR 3932160 + + #define EMC2305_REG_FAN_DRIVE(n) (0x30 + 0x10 * (n)) ++#define EMC2305_REG_FAN_CFG(n) (0x32 + 0x10 * (n)) + #define EMC2305_REG_FAN_MIN_DRIVE(n) (0x38 + 0x10 * (n)) + #define EMC2305_REG_FAN_TACH(n) (0x3e + 0x10 * (n)) + +@@ -58,6 +60,15 @@ static const struct i2c_device_id emc2305_ids = { + }; + MODULE_DEVICE_TABLE(i2c, emc2305_ids); + ++static const struct of_device_id emc2305_dt_ids = { ++ { .compatible = "microchip,emc2305" }, ++ { .compatible = "microchip,emc2303" }, ++ { .compatible = "microchip,emc2302" }, ++ { .compatible = "microchip,emc2301" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, emc2305_dt_ids); + - #define UNDERVOLTAGE_STICKY_BIT BIT(16) + /** + * struct emc2305_cdev_data - device-specific cooling device state + * @cdev: cooling device +@@ -103,6 +114,7 @@ struct emc2305_data { + u8 pwm_num; + bool pwm_separate; + u8 pwm_minEMC2305_PWM_MAX; ++ u8 pwm_max; + struct emc2305_cdev_data cdev_dataEMC2305_PWM_MAX; + }; - struct rpi_hwmon_data { -@@ -47,10 +77,13 @@ static void rpi_firmware_get_throttled(struct rpi_hwmon_data *data) - if (new_uv == old_uv) - return; +@@ -275,7 +287,7 @@ static int emc2305_set_pwm(struct device *dev, long val, int channel) + struct i2c_client *client = data->client; + int ret; -- 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); +- if (val < data->pwm_minchannel || val > EMC2305_FAN_MAX) ++ if (val < data->pwm_minchannel || val > data->pwm_max) + return -EINVAL; + + ret = i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_DRIVE(channel), val); +@@ -286,6 +298,49 @@ static int emc2305_set_pwm(struct device *dev, long val, int channel) + return 0; + } + ++static int emc2305_get_tz_of(struct device *dev) ++{ ++ struct device_node *np = dev->of_node; ++ struct emc2305_data *data = dev_get_drvdata(dev); ++ int ret = 0; ++ u8 val; ++ int i; ++ ++ /* OF parameters are optional - overwrite default setting ++ * if some of them are provided. ++ */ ++ ++ ret = of_property_read_u8(np, "emc2305,cooling-levels", &val); ++ if (!ret) ++ data->max_state = val; ++ else if (ret != -EINVAL) ++ return ret; ++ ++ ret = of_property_read_u8(np, "emc2305,pwm-max", &val); ++ if (!ret) ++ data->pwm_max = val; ++ else if (ret != -EINVAL) ++ return ret; ++ ++ ret = of_property_read_u8(np, "emc2305,pwm-min", &val); ++ if (!ret) ++ for (i = 0; i < EMC2305_PWM_MAX; i++) ++ data->pwm_mini = val; ++ else if (ret != -EINVAL) ++ return ret; ++ ++ /* Not defined or 0 means one thermal zone over all cooling devices. ++ * Otherwise - separated thermal zones for each PWM channel. ++ */ ++ ret = of_property_read_u8(np, "emc2305,pwm-channel", &val); ++ if (!ret) ++ data->pwm_separate = (val != 0); ++ else if (ret != -EINVAL) ++ return ret; ++ ++ return 0; ++} ++ + static int emc2305_set_single_tz(struct device *dev, int idx) + { + struct emc2305_data *data = dev_get_drvdata(dev); +@@ -295,9 +350,17 @@ static int emc2305_set_single_tz(struct device *dev, int idx) + cdev_idx = (idx) ? idx - 1 : 0; + pwm = data->pwm_mincdev_idx; + +- data->cdev_datacdev_idx.cdev = +- thermal_cooling_device_register(emc2305_fan_nameidx, data, +- &emc2305_cooling_ops); ++ if (dev->of_node) ++ data->cdev_datacdev_idx.cdev = ++ devm_thermal_of_cooling_device_register(dev, dev->of_node, ++ emc2305_fan_nameidx, ++ data, ++ &emc2305_cooling_ops); ++ else ++ data->cdev_datacdev_idx.cdev = ++ thermal_cooling_device_register(emc2305_fan_nameidx, ++ data, ++ &emc2305_cooling_ops); + + if (IS_ERR(data->cdev_datacdev_idx.cdev)) { + dev_err(dev, "Failed to register cooling device %s\n", emc2305_fan_nameidx); +@@ -350,9 +413,11 @@ static void emc2305_unset_tz(struct device *dev) + int i; + + /* Unregister cooling device. */ +- for (i = 0; i < EMC2305_PWM_MAX; i++) +- if (data->cdev_datai.cdev) +- thermal_cooling_device_unregister(data->cdev_datai.cdev); ++ if (!dev->of_node) { ++ for (i = 0; i < EMC2305_PWM_MAX; i++) ++ if (data->cdev_datai.cdev) ++ thermal_cooling_device_unregister(data->cdev_datai.cdev); ++ } + } + + static umode_t +@@ -574,11 +639,18 @@ static int emc2305_probe(struct i2c_client *client) + data->pwm_separate = pdata->pwm_separate; + for (i = 0; i < EMC2305_PWM_MAX; i++) + data->pwm_mini = pdata->pwm_mini; ++ data->pwm_max = EMC2305_FAN_MAX; + } else { + data->max_state = EMC2305_FAN_MAX_STATE; + data->pwm_separate = false; + for (i = 0; i < EMC2305_PWM_MAX; i++) + data->pwm_mini = EMC2305_FAN_MIN; ++ data->pwm_max = EMC2305_FAN_MAX; ++ if (dev->of_node) { ++ ret = emc2305_get_tz_of(dev); ++ if (ret < 0) ++ return ret; ++ } + } + + data->hwmon_dev = devm_hwmon_device_register_with_info(dev, "emc2305", data, +@@ -599,6 +671,12 @@ static int emc2305_probe(struct i2c_client *client) + return ret; + } + ++ /* Acknowledge any existing faults. Stops the device responding on the ++ * SMBus alert address. ++ */ ++ i2c_smbus_read_byte_data(client, EMC2305_REG_FAN_STALL_STATUS); ++ i2c_smbus_read_byte_data(client, EMC2305_REG_FAN_STATUS); ++ + return 0; + } + +@@ -614,6 +692,7 @@ static struct i2c_driver emc2305_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "emc2305", ++ .of_match_table = emc2305_dt_ids, + }, + .probe = emc2305_probe, + .remove = emc2305_remove, +diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c +index 6e4516c2ab89..131895d5a031 100644 +--- a/drivers/hwmon/pwm-fan.c ++++ b/drivers/hwmon/pwm-fan.c +@@ -12,6 +12,7 @@ + #include <linux/module.h> + #include <linux/mutex.h> + #include <linux/of.h> ++#include <linux/of_address.h> + #include <linux/platform_device.h> + #include <linux/pwm.h> + #include <linux/regulator/consumer.h> +@@ -51,6 +52,9 @@ struct pwm_fan_ctx { + ktime_t sample_start; + struct timer_list rpm_timer; + ++ void __iomem *rpm_regbase; ++ unsigned int rpm_offset; ++ + unsigned int pwm_value; + unsigned int pwm_fan_state; + unsigned int pwm_fan_max_state; +@@ -61,6 +65,10 @@ struct pwm_fan_ctx { + struct hwmon_channel_info fan_channel; + }; + ++static const u32 rpm_reg_channel_config = { ++ HWMON_F_INPUT, 0 ++}; ++ + /* This handler assumes self resetting edge triggered interrupt. */ + static irqreturn_t pulse_handler(int irq, void *dev_id) + { +@@ -151,7 +159,7 @@ static int pwm_fan_power_on(struct pwm_fan_ctx *ctx) + } + + state->enabled = true; +- ret = pwm_apply_state(ctx->pwm, state); ++ ret = pwm_apply_might_sleep(ctx->pwm, state); + if (ret) { + dev_err(ctx->dev, "failed to enable PWM\n"); + goto disable_regulator; +@@ -181,7 +189,7 @@ static int pwm_fan_power_off(struct pwm_fan_ctx *ctx) + + state->enabled = false; + state->duty_cycle = 0; +- ret = pwm_apply_state(ctx->pwm, state); ++ ret = pwm_apply_might_sleep(ctx->pwm, state); + if (ret) { + dev_err(ctx->dev, "failed to disable PWM\n"); + return ret; +@@ -207,7 +215,7 @@ static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) + + period = state->period; + state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); +- ret = pwm_apply_state(ctx->pwm, state); ++ ret = pwm_apply_might_sleep(ctx->pwm, state); + if (ret) + return ret; + ret = pwm_fan_power_on(ctx); +@@ -278,7 +286,7 @@ static int pwm_fan_update_enable(struct pwm_fan_ctx *ctx, long val) + state, + &enable_regulator); + +- pwm_apply_state(ctx->pwm, state); ++ pwm_apply_might_sleep(ctx->pwm, state); + pwm_fan_switch_power(ctx, enable_regulator); + pwm_fan_update_state(ctx, 0); + } +@@ -335,7 +343,10 @@ static int pwm_fan_read(struct device *dev, enum hwmon_sensor_types type, + } + return -EOPNOTSUPP; + case hwmon_fan: +- *val = ctx->tachschannel.rpm; ++ if (ctx->rpm_regbase) ++ *val = (long)readl(ctx->rpm_regbase + ctx->rpm_offset); ++ else ++ *val = ctx->tachschannel.rpm; + return 0; + + default: +@@ -470,6 +481,7 @@ static void pwm_fan_cleanup(void *__ctx) + /* Switch off everything */ + ctx->enable_mode = pwm_disable_reg_disable; + pwm_fan_power_off(ctx); ++ iounmap(ctx->rpm_regbase); + } + + static int pwm_fan_probe(struct platform_device *pdev) +@@ -542,10 +554,23 @@ static int pwm_fan_probe(struct platform_device *pdev) + return ret; + + ctx->tach_count = platform_irq_count(pdev); ++ if (ctx->tach_count == 0) { ++ struct device_node *rpm_node; ++ ++ rpm_node = of_parse_phandle(dev->of_node, "rpm-regmap", 0); ++ if (rpm_node) ++ ctx->rpm_regbase = of_iomap(rpm_node, 0); ++ } ++ + if (ctx->tach_count < 0) + return dev_err_probe(dev, ctx->tach_count, + "Could not get number of fan tachometer inputs\n"); +- dev_dbg(dev, "%d fan tachometer inputs\n", ctx->tach_count); ++ if (IS_ERR(ctx->rpm_regbase)) ++ return dev_err_probe(dev, PTR_ERR(ctx->rpm_regbase), ++ "Could not get rpm reg\n"); ++ ++ dev_dbg(dev, "%d fan tachometer inputs, %d rpm regmap\n", ctx->tach_count, ++ !!ctx->rpm_regbase); + + if (ctx->tach_count) { + channel_count++; /* We also have a FAN channel. */ +@@ -562,12 +587,24 @@ static int pwm_fan_probe(struct platform_device *pdev) + if (!fan_channel_config) + return -ENOMEM; + ctx->fan_channel.config = fan_channel_config; ++ } else if (ctx->rpm_regbase) { ++ channel_count++; /* We also have a FAN channel. */ ++ ctx->fan_channel.type = hwmon_fan; ++ ctx->fan_channel.config = rpm_reg_channel_config; ++ ++ if (of_property_read_u32(pdev->dev.of_node, "rpm-offset", &ctx->rpm_offset)) { ++ dev_err(&pdev->dev, "unable to read 'rpm-offset'"); ++ ret = -EINVAL; ++ goto error; ++ } + } + + channels = devm_kcalloc(dev, channel_count + 1, + sizeof(struct hwmon_channel_info *), GFP_KERNEL); +- if (!channels) +- return -ENOMEM; ++ if (!channels) { ++ ret = -ENOMEM; ++ goto error; + } - sysfs_notify(&data->hwmon_dev->kobj, NULL, "in0_lcrit_alarm"); + channels0 = HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE); + +@@ -609,6 +646,8 @@ static int pwm_fan_probe(struct platform_device *pdev) + ctx->sample_start = ktime_get(); + mod_timer(&ctx->rpm_timer, jiffies + HZ); + ++ channels1 = &ctx->fan_channel; ++ } else if (ctx->rpm_regbase) { + channels1 = &ctx->fan_channel; + } + +@@ -619,12 +658,13 @@ static int pwm_fan_probe(struct platform_device *pdev) + ctx, &ctx->info, NULL); + if (IS_ERR(hwmon)) { + dev_err(dev, "Failed to register hwmon device\n"); +- return PTR_ERR(hwmon); ++ ret = PTR_ERR(hwmon); ++ goto error; + } + + ret = pwm_fan_of_get_cooling_data(dev, ctx); + if (ret) +- return ret; ++ goto error; + + ctx->pwm_fan_state = ctx->pwm_fan_max_state; + if (IS_ENABLED(CONFIG_THERMAL)) { +@@ -635,12 +675,17 @@ static int pwm_fan_probe(struct platform_device *pdev) + dev_err(dev, + "Failed to register pwm-fan as cooling device: %d\n", + ret); +- return ret; ++ goto error; + } + ctx->cdev = cdev; + } + + return 0; ++ ++error: ++ if (ctx->rpm_regbase) ++ iounmap(ctx->rpm_regbase); ++ return ret; } -diff --git a/drivers/hwmon/rpi-poe-fan.c b/drivers/hwmon/rpi-poe-fan.c + + static void pwm_fan_shutdown(struct platform_device *pdev) +diff --git a/drivers/hwmon/rp1-adc.c b/drivers/hwmon/rp1-adc.c new file mode 100644 -index 000000000000..8483b6ce1db8 +index 000000000000..f1ec4c3b9f5d --- /dev/null -+++ b/drivers/hwmon/rpi-poe-fan.c -@@ -0,0 +1,451 @@ -+// SPDX-License-Identifier: GPL-2.0 ++++ b/drivers/hwmon/rp1-adc.c +@@ -0,0 +1,307 @@ ++// 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> ++ * Driver for the RP1 ADC and temperature sensor ++ * Copyright (C) 2023 Raspberry Pi Ltd. + */ + ++#include <linux/clk.h> ++#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> ++#include <linux/io.h> +#include <linux/module.h> -+#include <linux/mutex.h> -+#include <linux/notifier.h> -+#include <linux/of.h> ++#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> -+#include <linux/reboot.h> -+#include <linux/sysfs.h> -+#include <linux/thermal.h> -+#include <soc/bcm2835/raspberrypi-firmware.h> ++#include <linux/regulator/consumer.h> + -+#define MAX_PWM 255 ++#define MODULE_NAME "rp1-adc" + -+#define POE_CUR_PWM 0x0 -+#define POE_DEF_PWM 0x1 ++#define RP1_ADC_CS 0x00 ++#define RP1_ADC_RESULT 0x04 ++#define RP1_ADC_FCS 0x08 ++#define RP1_ADC_FIFO 0x0c ++#define RP1_ADC_DIV 0x10 ++ ++#define RP1_ADC_INTR 0x14 ++#define RP1_ADC_INTE 0x18 ++#define RP1_ADC_INTF 0x1c ++#define RP1_ADC_INTS 0x20 ++ ++#define RP1_ADC_RWTYPE_SET 0x2000 ++#define RP1_ADC_RWTYPE_CLR 0x3000 ++ ++#define RP1_ADC_CS_RROBIN_MASK 0x1f ++#define RP1_ADC_CS_RROBIN_SHIFT 16 ++#define RP1_ADC_CS_AINSEL_MASK 0x7 ++#define RP1_ADC_CS_AINSEL_SHIFT 12 ++#define RP1_ADC_CS_ERR_STICKY 0x400 ++#define RP1_ADC_CS_ERR 0x200 ++#define RP1_ADC_CS_READY 0x100 ++#define RP1_ADC_CS_START_MANY 0x8 ++#define RP1_ADC_CS_START_ONCE 0x4 ++#define RP1_ADC_CS_TS_EN 0x2 ++#define RP1_ADC_CS_EN 0x1 ++ ++#define RP1_ADC_FCS_THRESH_MASK 0xf ++#define RP1_ADC_FCS_THRESH_SHIFT 24 ++#define RP1_ADC_FCS_LEVEL_MASK 0xf ++#define RP1_ADC_FCS_LEVEL_SHIFT 16 ++#define RP1_ADC_FCS_OVER 0x800 ++#define RP1_ADC_FCS_UNDER 0x400 ++#define RP1_ADC_FCS_FULL 0x200 ++#define RP1_ADC_FCS_EMPTY 0x100 ++#define RP1_ADC_FCS_DREQ_EN 0x8 ++#define RP1_ADC_FCS_ERR 0x4 ++#define RP1_ADC_FCS_SHIFR 0x2 ++#define RP1_ADC_FCS_EN 0x1 ++ ++#define RP1_ADC_FIFO_ERR 0x8000 ++#define RP1_ADC_FIFO_VAL_MASK 0xfff ++ ++#define RP1_ADC_DIV_INT_MASK 0xffff ++#define RP1_ADC_DIV_INT_SHIFT 8 ++#define RP1_ADC_DIV_FRAC_MASK 0xff ++#define RP1_ADC_DIV_FRAC_SHIFT 0 + -+struct 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; ++struct rp1_adc_data { ++ void __iomem *base; ++ spinlock_t lock; ++ struct device *hwmon_dev; ++ int vref_mv; +}; + -+static int write_reg(struct rpi_firmware *fw, u32 reg, u32 *val, u32 set_tag) ++static int rp1_adc_ready_wait(struct rp1_adc_data *data) +{ -+ struct fw_tag_data_s fw_tag_data = { -+ .reg = reg, -+ .val = *val -+ }; -+ int ret; ++ int retries = 10; + -+ 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; -+} ++ while (retries && !(readl(data->base + RP1_ADC_CS) & RP1_ADC_CS_READY)) ++ retries--; + -+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; ++ return retries ? 0 : -EIO; +} + -+static int rpi_poe_reboot(struct notifier_block *nb, unsigned long code, -+ void *unused) ++static int rp1_adc_read(struct rp1_adc_data *data, ++ struct device_attribute *devattr, unsigned int *val) +{ -+ struct rpi_poe_fan_ctx *ctx = container_of(nb, struct rpi_poe_fan_ctx, -+ nb); ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ int channel = attr->index; ++ int ret; + -+ if (ctx->pwm_value != ctx->def_pwm_value) -+ write_reg(ctx->fw, POE_CUR_PWM, &ctx->def_pwm_value, ctx->set_tag); ++ spin_lock(&data->lock); + -+ return NOTIFY_DONE; -+} ++ writel(RP1_ADC_CS_AINSEL_MASK << RP1_ADC_CS_AINSEL_SHIFT, ++ data->base + RP1_ADC_RWTYPE_CLR + RP1_ADC_CS); ++ writel(channel << RP1_ADC_CS_AINSEL_SHIFT, ++ data->base + RP1_ADC_RWTYPE_SET + RP1_ADC_CS); ++ writel(RP1_ADC_CS_START_ONCE, ++ data->base + RP1_ADC_RWTYPE_SET + RP1_ADC_CS); + -+static int __set_pwm(struct rpi_poe_fan_ctx *ctx, u32 pwm) -+{ -+ int ret = 0; ++ ret = rp1_adc_ready_wait(data); ++ if (ret) ++ return ret; + -+ mutex_lock(&ctx->lock); -+ if (ctx->pwm_value == pwm) -+ goto exit_set_pwm_err; ++ /* Asserted if the completed conversion had a convergence error */ ++ if (readl(data->base + RP1_ADC_CS) & RP1_ADC_CS_ERR) ++ return -EIO; + -+ 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; -+} ++ *val = readl(data->base + RP1_ADC_RESULT); + -+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; ++ spin_unlock(&data->lock); + -+ 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) ++static int rp1_adc_to_mv(struct rp1_adc_data *data, unsigned int val) +{ -+ int i; -+ -+ for (i = 0; i < ctx->rpi_poe_fan_max_state; ++i) -+ if (pwm < ctx->rpi_poe_fan_cooling_levelsi + 1) -+ break; -+ -+ ctx->rpi_poe_fan_state = i; ++ return ((u64)data->vref_mv * val) / 0xfff; +} + -+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) ++static ssize_t rp1_adc_show(struct device *dev, ++ struct device_attribute *devattr, ++ char *buf) +{ -+ struct rpi_poe_fan_ctx *ctx = dev_get_drvdata(dev); -+ unsigned long pwm; ++ struct rp1_adc_data *data = dev_get_drvdata(dev); ++ unsigned int val; + int ret; + -+ if (kstrtoul(buf, 10, &pwm) || pwm > MAX_PWM) -+ return -EINVAL; -+ -+ ret = __set_pwm(ctx, pwm); ++ ret = rp1_adc_read(data, devattr, &val); + if (ret) + return ret; + -+ rpi_poe_fan_update_state(ctx, pwm); -+ return count; ++ return sprintf(buf, "%d\n", rp1_adc_to_mv(data, val)); +} + -+static ssize_t set_def_pwm(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) ++static ssize_t rp1_adc_temp_show(struct device *dev, ++ struct device_attribute *devattr, ++ char *buf) +{ -+ 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; ++ struct rp1_adc_data *data = dev_get_drvdata(dev); ++ unsigned int val; ++ int ret, mv, mc; + -+ ret = __set_def_pwm(ctx, def_pwm); ++ writel(RP1_ADC_CS_TS_EN, ++ data->base + RP1_ADC_RWTYPE_SET + RP1_ADC_CS); ++ ret = rp1_adc_read(data, devattr, &val); + if (ret) + return ret; -+ 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, -+}; ++ mv = rp1_adc_to_mv(data, val); + -+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; ++ /* T = 27 - (ADC_voltage - 0.706)/0.001721 */ + -+ *state = ctx->rpi_poe_fan_max_state; ++ mc = 27000 - DIV_ROUND_CLOSEST((mv - 706) * (s64)1000000, 1721); + -+ return 0; ++ return sprintf(buf, "%d\n", mc); +} + -+static int rpi_poe_fan_get_cur_state(struct thermal_cooling_device *cdev, -+ unsigned long *state) ++static ssize_t rp1_adc_raw_show(struct device *dev, ++ struct device_attribute *devattr, ++ char *buf) +{ -+ struct rpi_poe_fan_ctx *ctx = cdev->devdata; -+ -+ if (!ctx) -+ return -EINVAL; ++ struct rp1_adc_data *data = dev_get_drvdata(dev); ++ unsigned int val; ++ int ret = rp1_adc_read(data, devattr, &val); + -+ *state = ctx->rpi_poe_fan_state; ++ if (ret) ++ return ret; + -+ return 0; ++ return sprintf(buf, "%u\n", val); +} + -+static int rpi_poe_fan_set_cur_state(struct thermal_cooling_device *cdev, -+ unsigned long state) ++static ssize_t rp1_adc_temp_raw_show(struct device *dev, ++ struct device_attribute *devattr, ++ char *buf) +{ -+ 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; ++ struct rp1_adc_data *data = dev_get_drvdata(dev); ++ unsigned int val; ++ int ret = rp1_adc_read(data, devattr, &val); + -+ ret = __set_pwm(ctx, ctx->rpi_poe_fan_cooling_levelsstate); -+ if (ret) { -+ dev_err(&cdev->device, "Cannot set pwm!\n"); ++ if (ret) + return ret; -+ } -+ -+ ctx->rpi_poe_fan_state = state; + -+ return ret; ++ return sprintf(buf, "%u\n", val); +} + -+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 SENSOR_DEVICE_ATTR_RO(in1_input, rp1_adc, 0); ++static SENSOR_DEVICE_ATTR_RO(in2_input, rp1_adc, 1); ++static SENSOR_DEVICE_ATTR_RO(in3_input, rp1_adc, 2); ++static SENSOR_DEVICE_ATTR_RO(in4_input, rp1_adc, 3); ++static SENSOR_DEVICE_ATTR_RO(temp1_input, rp1_adc_temp, 4); ++static SENSOR_DEVICE_ATTR_RO(in1_raw, rp1_adc_raw, 0); ++static SENSOR_DEVICE_ATTR_RO(in2_raw, rp1_adc_raw, 1); ++static SENSOR_DEVICE_ATTR_RO(in3_raw, rp1_adc_raw, 2); ++static SENSOR_DEVICE_ATTR_RO(in4_raw, rp1_adc_raw, 3); ++static SENSOR_DEVICE_ATTR_RO(temp1_raw, rp1_adc_temp_raw, 4); ++ ++static struct attribute *rp1_adc_attrs = { ++ &sensor_dev_attr_in1_input.dev_attr.attr, ++ &sensor_dev_attr_in2_input.dev_attr.attr, ++ &sensor_dev_attr_in3_input.dev_attr.attr, ++ &sensor_dev_attr_in4_input.dev_attr.attr, ++ &sensor_dev_attr_temp1_input.dev_attr.attr, ++ &sensor_dev_attr_in1_raw.dev_attr.attr, ++ &sensor_dev_attr_in2_raw.dev_attr.attr, ++ &sensor_dev_attr_in3_raw.dev_attr.attr, ++ &sensor_dev_attr_in4_raw.dev_attr.attr, ++ &sensor_dev_attr_temp1_raw.dev_attr.attr, ++ NULL +}; + -+static int rpi_poe_fan_of_get_cooling_data(struct device *dev, -+ struct rpi_poe_fan_ctx *ctx) ++static umode_t rp1_adc_is_visible(struct kobject *kobj, ++ struct attribute *attr, int index) +{ -+ 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_levelsi > MAX_PWM) { -+ dev_err(dev, "PWM fan state%d:%d > %d\n", i, -+ ctx->rpi_poe_fan_cooling_levelsi, MAX_PWM); -+ return -EINVAL; -+ } -+ } -+ -+ ctx->rpi_poe_fan_max_state = num - 1; -+ -+ return 0; ++ return 0444; +} + -+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; ++static const struct attribute_group rp1_adc_group = { ++ .attrs = rp1_adc_attrs, ++ .is_visible = rp1_adc_is_visible, ++}; ++__ATTRIBUTE_GROUPS(rp1_adc); + -+ fw_node = of_parse_phandle(np, "firmware", 0); -+ if (!fw_node) { -+ dev_err(&pdev->dev, "Missing firmware node\n"); -+ return -ENOENT; -+ } ++static int __init rp1_adc_probe(struct platform_device *pdev) ++{ ++ struct rp1_adc_data *data; ++ struct regulator *reg; ++ struct clk *clk; ++ int vref_uv, ret; + -+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); -+ if (!ctx) ++ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); ++ if (!data) + return -ENOMEM; + -+ mutex_init(&ctx->lock); ++ spin_lock_init(&data->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; ++ data->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(data->base)) ++ return PTR_ERR(data->base); + -+ platform_set_drvdata(pdev, ctx); ++ platform_set_drvdata(pdev, data); + -+ 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; ++ clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(clk)) ++ return -ENODEV; + -+ rpi_poe_fan_update_state(ctx, ctx->pwm_value); -+ if (!IS_ENABLED(CONFIG_THERMAL)) -+ return 0; ++ clk_set_rate(clk, 50000000); ++ clk_prepare_enable(clk); + -+ 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; ++ reg = devm_regulator_get(&pdev->dev, "vref"); ++ if (IS_ERR(reg)) ++ return PTR_ERR(reg); ++ ++ vref_uv = regulator_get_voltage(reg); ++ data->vref_mv = DIV_ROUND_CLOSEST(vref_uv, 1000); ++ ++ data->hwmon_dev = ++ devm_hwmon_device_register_with_groups(&pdev->dev, ++ "rp1_adc", ++ data, ++ rp1_adc_groups); ++ if (IS_ERR(data->hwmon_dev)) { ++ ret = PTR_ERR(data->hwmon_dev); ++ dev_err(&pdev->dev, "hwmon_device_register failed with %d.\n", ret); ++ goto err_register; + } -+ 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; ++ /* Disable interrupts */ ++ writel(0, data->base + RP1_ADC_INTE); + -+ 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); ++ /* Enable the block, clearing any sticky error */ ++ writel(RP1_ADC_CS_EN | RP1_ADC_CS_ERR_STICKY, data->base + RP1_ADC_CS); + + 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; ++err_register: ++ sysfs_remove_group(&pdev->dev.kobj, &rp1_adc_group); + -+ 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) ++static int rp1_adc_remove(struct platform_device *pdev) +{ -+ struct rpi_poe_fan_ctx *ctx = dev_get_drvdata(dev); -+ u32 value = ctx->pwm_value; -+ int ret = 0; ++ struct rp1_adc_data *data = platform_get_drvdata(pdev); + -+ if (value != 0) -+ ret = write_reg(ctx->fw, POE_CUR_PWM, &value, ctx->set_tag); ++ hwmon_device_unregister(data->hwmon_dev); + -+ return ret; ++ return 0; +} -+#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", }, -+ {}, ++static const struct of_device_id rp1_adc_dt_ids = { ++ { .compatible = "raspberrypi,rp1-adc", }, ++ { } +}; -+MODULE_DEVICE_TABLE(of, of_rpi_poe_fan_match); ++MODULE_DEVICE_TABLE(of, rp1_adc_dt_ids); + -+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, ++static struct platform_driver rp1_adc_driver = { ++ .remove = rp1_adc_remove, ++ .driver = { ++ .name = MODULE_NAME, ++ .of_match_table = rp1_adc_dt_ids, + }, +}; + -+module_platform_driver(rpi_poe_fan_driver); ++module_platform_driver_probe(rp1_adc_driver, rp1_adc_probe); + -+MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>"); -+MODULE_ALIAS("platform:rpi-poe-fan"); -+MODULE_DESCRIPTION("Raspberry Pi PoE HAT fan driver"); ++MODULE_DESCRIPTION("RP1 ADC driver"); ++MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.com>"); +MODULE_LICENSE("GPL"); +diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c +index 79657910b79e..122a1031b4d8 100644 +--- a/drivers/hwmon/sht3x.c ++++ b/drivers/hwmon/sht3x.c +@@ -911,8 +911,18 @@ static int sht3x_probe(struct i2c_client *client) + return PTR_ERR_OR_ZERO(hwmon_dev); + } + ++static const struct of_device_id sht3x_of_ids = { ++ { .compatible = "sensirion,sht3x" }, ++ { .compatible = "sensirion,sts3x" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, sht3x_of_ids); ++ + static struct i2c_driver sht3x_i2c_driver = { +- .driver.name = "sht3x", ++ .driver = { ++ .name = "sht3x", ++ .of_match_table = sht3x_of_ids, ++ }, + .probe = sht3x_probe, + .id_table = sht3x_ids, + }; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig -index 036fdcee5eb3..17e3afba7e0d 100644 +index 9b4369ce8759..bb555bfcc6aa 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig -@@ -9,6 +9,25 @@ menu "I2C Hardware Bus support" - comment "PC SMBus host controller drivers" - depends on PCI +@@ -16,6 +16,25 @@ config I2C_CCGX_UCSI + for Cypress CCGx Type-C controller. Individual bus drivers + need to select this one on demand. +config I2C_BCM2708 + tristate "BCM2708 BSC" @@ -69122,7 +98201,7 @@ tristate "ALI 1535" depends on PCI diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile -index e6d5d108e22b..b8e5bfd23158 100644 +index f15e364622e7..48d24d0d1bd8 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -3,6 +3,8 @@ @@ -69653,10 +98732,10 @@ +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c -index 37443edbf754..7d8e183bb533 100644 +index b92de1944221..71a74de9fa5a 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c -@@ -51,6 +51,22 @@ +@@ -56,6 +56,22 @@ #define BCM2835_I2C_CDIV_MIN 0x0002 #define BCM2835_I2C_CDIV_MAX 0xFFFE @@ -69679,7 +98758,7 @@ struct bcm2835_i2c_dev { struct device *dev; void __iomem *regs; -@@ -63,8 +79,78 @@ struct bcm2835_i2c_dev { +@@ -68,8 +84,78 @@ struct bcm2835_i2c_dev { u32 msg_err; u8 *msg_buf; size_t msg_buf_remaining; @@ -69758,7 +98837,7 @@ static inline void bcm2835_i2c_writel(struct bcm2835_i2c_dev *i2c_dev, u32 reg, u32 val) { -@@ -106,6 +192,7 @@ static int clk_bcm2835_i2c_set_rate(struct clk_hw *hw, unsigned long rate, +@@ -111,6 +197,7 @@ static int clk_bcm2835_i2c_set_rate(struct clk_hw *hw, unsigned long rate, { struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw); u32 redl, fedl; @@ -69766,7 +98845,7 @@ u32 divider = clk_bcm2835_i2c_calc_divider(rate, parent_rate); if (divider == -EINVAL) -@@ -129,6 +216,17 @@ static int clk_bcm2835_i2c_set_rate(struct clk_hw *hw, unsigned long rate, +@@ -134,6 +221,17 @@ static int clk_bcm2835_i2c_set_rate(struct clk_hw *hw, unsigned long rate, bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DEL, (fedl << BCM2835_I2C_FEDL_SHIFT) | (redl << BCM2835_I2C_REDL_SHIFT)); @@ -69784,7 +98863,7 @@ return 0; } -@@ -252,6 +350,7 @@ static void bcm2835_i2c_start_transfer(struct bcm2835_i2c_dev *i2c_dev) +@@ -257,6 +355,7 @@ static void bcm2835_i2c_start_transfer(struct bcm2835_i2c_dev *i2c_dev) 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); @@ -69792,18 +98871,38 @@ } static void bcm2835_i2c_finish_transfer(struct bcm2835_i2c_dev *i2c_dev) -@@ -278,6 +377,7 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) +@@ -283,12 +382,11 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) 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) { -@@ -344,6 +444,13 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs, +- if (err) { ++ if (err && !(val & BCM2835_I2C_S_TA)) + i2c_dev->msg_err = err; +- goto complete; +- } + + if (val & BCM2835_I2C_S_DONE) { + if (!i2c_dev->curr_msg) { +@@ -300,8 +398,6 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) + + if ((val & BCM2835_I2C_S_RXD) || i2c_dev->msg_buf_remaining) + i2c_dev->msg_err = BCM2835_I2C_S_LEN; +- else +- i2c_dev->msg_err = 0; + goto complete; + } + +@@ -347,17 +443,29 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs, + { + struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap); unsigned long time_left; ++ bool ignore_nak = false; int i; +- for (i = 0; i < (num - 1); i++) + if (debug) + i2c_dev->debug_num_msgs = num; + @@ -69811,13 +98910,29 @@ + for (i = 0; i < num; i++) + bcm2835_debug_print_msg(i2c_dev, &msgsi, i + 1, num, __func__); + - for (i = 0; i < (num - 1); i++) ++ for (i = 0; i < (num - 1); i++) { if (msgsi.flags & I2C_M_RD) { dev_warn_once(i2c_dev->dev, -@@ -362,6 +469,10 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs, + "only one read message supported, has to be last\n"); + return -EOPNOTSUPP; + } ++ if (msgsi.flags & I2C_M_IGNORE_NAK) ++ ignore_nak = true; ++ } + + i2c_dev->curr_msg = msgs; + i2c_dev->num_msgs = num; ++ i2c_dev->msg_err = 0; + reinit_completion(&i2c_dev->completion); + + bcm2835_i2c_start_transfer(i2c_dev); +@@ -367,6 +475,13 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs, bcm2835_i2c_finish_transfer(i2c_dev); ++ if (ignore_nak) ++ i2c_dev->msg_err &= ~BCM2835_I2C_S_ERR; ++ + if (debug > 1 || (debug && (!time_left || i2c_dev->msg_err))) + bcm2835_debug_print(i2c_dev); + i2c_dev->debug_num_msgs = 0; @@ -69825,7 +98940,7 @@ if (!time_left) { bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); -@@ -372,7 +483,9 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs, +@@ -377,7 +492,9 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs, if (!i2c_dev->msg_err) return num; @@ -69836,13 +98951,351 @@ if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) return -EREMOTEIO; +@@ -387,7 +504,7 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs, + + static u32 bcm2835_i2c_func(struct i2c_adapter *adap) + { +- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; ++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING; + } + + static const struct i2c_algorithm bcm2835_i2c_algo = { +diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c +index 83803a63e23f..5cb4fcf562eb 100644 +--- a/drivers/i2c/busses/i2c-designware-common.c ++++ b/drivers/i2c/busses/i2c-designware-common.c +@@ -57,6 +57,8 @@ static char *abort_sources = { + "slave lost the bus while transmitting data to a remote master", + ABRT_SLAVE_RD_INTX = + "incorrect slave-transmitter mode configuration", ++ ABRT_SLAVE_SDA_STUCK_AT_LOW = ++ "SDA stuck at low", + }; + + static int dw_reg_read(void *context, unsigned int reg, unsigned int *val) +@@ -326,6 +328,9 @@ void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev) + { + u32 acpi_speed = i2c_dw_acpi_round_bus_speed(dev->dev); + struct i2c_timings *t = &dev->timings; ++ u32 wanted_speed; ++ u32 legal_speed = 0; ++ int i; + + /* + * Find bus speed from the "clock-frequency" device property, ACPI +@@ -337,6 +342,30 @@ void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev) + t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed); + else + t->bus_freq_hz = I2C_MAX_FAST_MODE_FREQ; ++ ++ wanted_speed = t->bus_freq_hz; ++ ++ /* For unsupported speeds, scale down the lowest speed which is faster. */ ++ for (i = 0; i < ARRAY_SIZE(supported_speeds); i++) { ++ /* supported speeds is in decreasing order */ ++ if (wanted_speed == supported_speedsi) { ++ legal_speed = 0; ++ break; ++ } ++ if (wanted_speed > supported_speedsi) ++ break; ++ ++ legal_speed = supported_speedsi; ++ } ++ ++ if (legal_speed) { ++ /* ++ * Pretend this was the requested speed, but preserve the preferred ++ * speed so the clock counts can be scaled. ++ */ ++ t->bus_freq_hz = legal_speed; ++ dev->wanted_bus_speed = wanted_speed; ++ } + } + EXPORT_SYMBOL_GPL(i2c_dw_adjust_bus_speed); + +@@ -574,8 +603,16 @@ int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev) + int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) + { + unsigned long abort_source = dev->abort_source; ++ unsigned int reg; + int i; + ++ if (abort_source & DW_IC_TX_ABRT_SLAVE_SDA_STUCK_AT_LOW) { ++ regmap_write(dev->map, DW_IC_ENABLE, ++ DW_IC_ENABLE_ENABLE | DW_IC_ENABLE_BUS_RECOVERY); ++ regmap_read_poll_timeout(dev->map, DW_IC_ENABLE, reg, ++ !(reg & DW_IC_ENABLE_BUS_RECOVERY), ++ 1100, 200000); ++ } + if (abort_source & DW_IC_TX_ABRT_NOACK) { + for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) + dev_dbg(dev->dev, +@@ -590,6 +627,8 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) + return -EAGAIN; + else if (abort_source & DW_IC_TX_ABRT_GCALL_READ) + return -EINVAL; /* wrong msgs data */ ++ else if (abort_source & DW_IC_TX_ABRT_SLAVE_SDA_STUCK_AT_LOW) ++ return -EREMOTEIO; + else + return -EIO; + } +diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h +index 2c97fff25b07..c5c5b8d048de 100644 +--- a/drivers/i2c/busses/i2c-designware-core.h ++++ b/drivers/i2c/busses/i2c-designware-core.h +@@ -79,9 +79,12 @@ + #define DW_IC_TX_ABRT_SOURCE 0x80 + #define DW_IC_ENABLE_STATUS 0x9c + #define DW_IC_CLR_RESTART_DET 0xa8 ++#define DW_IC_SCL_STUCK_AT_LOW_TIMEOUT 0xac ++#define DW_IC_SDA_STUCK_AT_LOW_TIMEOUT 0xb0 + #define DW_IC_COMP_PARAM_1 0xf4 + #define DW_IC_COMP_VERSION 0xf8 + #define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A /* "111*" == v1.11* */ ++#define DW_IC_BUS_CLEAR_MIN_VERS 0x3230302A /* "200*" == v2.00* */ + #define DW_IC_COMP_TYPE 0xfc + #define DW_IC_COMP_TYPE_VALUE 0x44570140 /* "DW" + 0x0140 */ + +@@ -109,20 +112,25 @@ + DW_IC_INTR_RX_UNDER | \ + DW_IC_INTR_RD_REQ) + ++#define DW_IC_ENABLE_ENABLE BIT(0) + #define DW_IC_ENABLE_ABORT BIT(1) ++#define DW_IC_ENABLE_BUS_RECOVERY BIT(3) + + #define DW_IC_STATUS_ACTIVITY BIT(0) + #define DW_IC_STATUS_TFE BIT(2) + #define DW_IC_STATUS_RFNE BIT(3) + #define DW_IC_STATUS_MASTER_ACTIVITY BIT(5) + #define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6) ++#define DW_IC_STATUS_SDA_STUCK_NOT_RECOVERED BIT(11) + + #define DW_IC_SDA_HOLD_RX_SHIFT 16 + #define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, 16) + + #define DW_IC_ERR_TX_ABRT 0x1 + ++#define DW_IC_TAR_SPECIAL BIT(11) + #define DW_IC_TAR_10BITADDR_MASTER BIT(12) ++#define DW_IC_TAR_SMBUS_QUICK_CMD BIT(16) + + #define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH (BIT(2) | BIT(3)) + #define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK GENMASK(3, 2) +@@ -161,6 +169,7 @@ + #define ABRT_SLAVE_FLUSH_TXFIFO 13 + #define ABRT_SLAVE_ARBLOST 14 + #define ABRT_SLAVE_RD_INTX 15 ++#define ABRT_SLAVE_SDA_STUCK_AT_LOW 17 + + #define DW_IC_TX_ABRT_7B_ADDR_NOACK BIT(ABRT_7B_ADDR_NOACK) + #define DW_IC_TX_ABRT_10ADDR1_NOACK BIT(ABRT_10ADDR1_NOACK) +@@ -176,6 +185,7 @@ + #define DW_IC_RX_ABRT_SLAVE_RD_INTX BIT(ABRT_SLAVE_RD_INTX) + #define DW_IC_RX_ABRT_SLAVE_ARBLOST BIT(ABRT_SLAVE_ARBLOST) + #define DW_IC_RX_ABRT_SLAVE_FLUSH_TXFIFO BIT(ABRT_SLAVE_FLUSH_TXFIFO) ++#define DW_IC_TX_ABRT_SLAVE_SDA_STUCK_AT_LOW BIT(ABRT_SLAVE_SDA_STUCK_AT_LOW) + + #define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \ + DW_IC_TX_ABRT_10ADDR1_NOACK | \ +@@ -289,6 +299,7 @@ struct dw_i2c_dev { + u16 fp_lcnt; + u16 hs_hcnt; + u16 hs_lcnt; ++ u32 wanted_bus_speed; + int (*acquire_lock)(void); + void (*release_lock)(void); + int semaphore_idx; +diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c +index 85dbd0eb5392..7593bcf03b9f 100644 +--- a/drivers/i2c/busses/i2c-designware-master.c ++++ b/drivers/i2c/busses/i2c-designware-master.c +@@ -38,6 +38,34 @@ static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev) + regmap_write(dev->map, DW_IC_CON, dev->master_cfg); + } + ++static u32 linear_interpolate(u32 x, u32 x1, u32 x2, u32 y1, u32 y2) ++{ ++ return ((x - x1) * y2 + (x2 - x) * y1) / (x2 - x1); ++} ++ ++static u16 u16_clamp(u32 v) ++{ ++ return (u16)min(v, 0xffff); ++} ++ ++static void clock_calc(struct dw_i2c_dev *dev, u32 *hcnt, u32 *lcnt) ++{ ++ struct i2c_timings *t = &dev->timings; ++ u32 wanted_khz = (dev->wanted_bus_speed ?: t->bus_freq_hz)/1000; ++ u32 clk_khz = i2c_dw_clk_rate(dev); ++ u32 min_high_ns = (wanted_khz <= 100) ? 4000 : ++ (wanted_khz <= 400) ? ++ linear_interpolate(wanted_khz, 100, 400, 4000, 600) : ++ linear_interpolate(wanted_khz, 400, 1000, 600, 260); ++ u32 high_cycles = (u32)(((u64)clk_khz * min_high_ns + 999999) / 1000000) + 1; ++ u32 extra_high_cycles = (u32)((u64)clk_khz * t->scl_fall_ns / 1000000); ++ u32 extra_low_cycles = (u32)((u64)clk_khz * t->scl_rise_ns / 1000000); ++ u32 period = ((u64)clk_khz + wanted_khz - 1) / wanted_khz; ++ ++ *hcnt = u16_clamp(high_cycles - extra_high_cycles); ++ *lcnt = u16_clamp(period - high_cycles - extra_low_cycles); ++} ++ + static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) + { + unsigned int comp_param1; +@@ -45,6 +73,7 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) + struct i2c_timings *t = &dev->timings; + const char *fp_str = ""; + u32 ic_clk; ++ u32 hcnt, lcnt; + int ret; + + ret = i2c_dw_acquire_lock(dev); +@@ -60,6 +89,8 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) + sda_falling_time = t->sda_fall_ns ?: 300; /* ns */ + scl_falling_time = t->scl_fall_ns ?: 300; /* ns */ + ++ clock_calc(dev, &hcnt, &lcnt); ++ + /* Calculate SCL timing parameters for standard mode if not set */ + if (!dev->ss_hcnt || !dev->ss_lcnt) { + ic_clk = i2c_dw_clk_rate(dev); +@@ -75,6 +106,8 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) + scl_falling_time, + 0); /* No offset */ + } ++ dev->ss_hcnt = hcnt; ++ dev->ss_lcnt = lcnt; + dev_dbg(dev->dev, "Standard Mode HCNT:LCNT = %d:%d\n", + dev->ss_hcnt, dev->ss_lcnt); + +@@ -125,6 +158,8 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) + scl_falling_time, + 0); /* No offset */ + } ++ dev->fs_hcnt = hcnt; ++ dev->fs_lcnt = lcnt; + dev_dbg(dev->dev, "Fast Mode%s HCNT:LCNT = %d:%d\n", + fp_str, dev->fs_hcnt, dev->fs_lcnt); + +@@ -153,10 +188,15 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) + scl_falling_time, + 0); /* No offset */ + } ++ dev->hs_hcnt = hcnt; ++ dev->hs_lcnt = lcnt; + dev_dbg(dev->dev, "High Speed Mode HCNT:LCNT = %d:%d\n", + dev->hs_hcnt, dev->hs_lcnt); + } + ++ if (!dev->sda_hold_time) ++ dev->sda_hold_time = lcnt / 2; ++ + ret = i2c_dw_set_sda_hold(dev); + if (ret) + return ret; +@@ -175,6 +215,7 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) + */ + static int i2c_dw_init_master(struct dw_i2c_dev *dev) + { ++ unsigned int timeout = 0; + int ret; + + ret = i2c_dw_acquire_lock(dev); +@@ -198,6 +239,17 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev) + regmap_write(dev->map, DW_IC_HS_SCL_LCNT, dev->hs_lcnt); + } + ++ if (dev->master_cfg & DW_IC_CON_BUS_CLEAR_CTRL) { ++ /* Set a sensible timeout if not already configured */ ++ regmap_read(dev->map, DW_IC_SDA_STUCK_AT_LOW_TIMEOUT, &timeout); ++ if (timeout == ~0) { ++ /* Use 10ms as a timeout, which is 1000 cycles at 100kHz */ ++ timeout = i2c_dw_clk_rate(dev) * 10; /* clock rate is in kHz */ ++ regmap_write(dev->map, DW_IC_SDA_STUCK_AT_LOW_TIMEOUT, timeout); ++ regmap_write(dev->map, DW_IC_SCL_STUCK_AT_LOW_TIMEOUT, timeout); ++ } ++ } ++ + /* Write SDA hold time if supported */ + if (dev->sda_hold_time) + regmap_write(dev->map, DW_IC_SDA_HOLD, dev->sda_hold_time); +@@ -229,6 +281,10 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) + ic_tar = DW_IC_TAR_10BITADDR_MASTER; + } + ++ /* Convert a zero-length read into an SMBUS quick command */ ++ if (!msgsdev->msg_write_idx.len) ++ ic_tar = DW_IC_TAR_SPECIAL | DW_IC_TAR_SMBUS_QUICK_CMD; ++ + regmap_update_bits(dev->map, DW_IC_CON, DW_IC_CON_10BITADDR_MASTER, + ic_con); + +@@ -472,6 +528,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) + regmap_read(dev->map, DW_IC_RXFLR, &flr); + rx_limit = dev->rx_fifo_depth - flr; + ++ /* Handle SMBUS quick commands */ ++ if (!buf_len) { ++ if (msgsdev->msg_write_idx.flags & I2C_M_RD) ++ regmap_write(dev->map, DW_IC_DATA_CMD, 0x300); ++ else ++ regmap_write(dev->map, DW_IC_DATA_CMD, 0x200); ++ } ++ + while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) { + u32 cmd = 0; + +@@ -743,7 +807,7 @@ static const struct i2c_algorithm i2c_dw_algo = { + }; + + static const struct i2c_adapter_quirks i2c_dw_quirks = { +- .flags = I2C_AQ_NO_ZERO_LEN, ++ .flags = 0, + }; + + static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) +@@ -876,7 +940,8 @@ void i2c_dw_configure_master(struct dw_i2c_dev *dev) + { + struct i2c_timings *t = &dev->timings; + +- dev->functionality = I2C_FUNC_10BIT_ADDR | DW_IC_DEFAULT_FUNCTIONALITY; ++ dev->functionality = I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_QUICK | ++ DW_IC_DEFAULT_FUNCTIONALITY; + + dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | + DW_IC_CON_RESTART_EN; +@@ -983,6 +1048,7 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) + struct i2c_adapter *adap = &dev->adapter; + unsigned long irq_flags; + unsigned int ic_con; ++ unsigned int id_ver; + int ret; + + init_completion(&dev->cmd_complete); +@@ -1018,7 +1084,11 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) + if (ret) + return ret; + +- if (ic_con & DW_IC_CON_BUS_CLEAR_CTRL) ++ ret = regmap_read(dev->map, DW_IC_COMP_VERSION, &id_ver); ++ if (ret) ++ return ret; ++ ++ if (ic_con & DW_IC_CON_BUS_CLEAR_CTRL || id_ver >= DW_IC_BUS_CLEAR_MIN_VERS) + dev->master_cfg |= DW_IC_CON_BUS_CLEAR_CTRL; + + ret = dev->init(dev); diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c -index a4a6825c8758..cfbcf3952ddc 100644 +index e5a5b9e8bf2c..113b971418a3 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c -@@ -445,7 +445,9 @@ static int i2c_gpio_probe(struct platform_device *pdev) +@@ -453,7 +453,9 @@ static int i2c_gpio_probe(struct platform_device *pdev) adap->dev.parent = dev; - adap->dev.of_node = np; + device_set_node(&adap->dev, fwnode); - adap->nr = pdev->id; + if (pdev->id != PLATFORM_DEVID_NONE || !pdev->dev.of_node || @@ -69851,13 +99304,93 @@ ret = i2c_bit_add_numbered_bus(adap); if (ret) return ret; +diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c +index 57ff09f18c37..6d724d64f97c 100644 +--- a/drivers/i2c/i2c-mux.c ++++ b/drivers/i2c/i2c-mux.c +@@ -355,8 +355,13 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, + if (muxc->dev->of_node) { + struct device_node *dev_node = muxc->dev->of_node; + struct device_node *mux_node, *child = NULL; ++ u32 base_nr = 0; + u32 reg; + ++ of_property_read_u32(dev_node, "base-nr", &base_nr); ++ if (!force_nr && base_nr) ++ force_nr = base_nr + chan_id; ++ + if (muxc->arbitrator) + mux_node = of_get_child_by_name(dev_node, "i2c-arb"); + else if (muxc->gate) +diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c +index 0778a8fb6866..b80d2b53627b 100644 +--- a/drivers/iio/adc/mcp3422.c ++++ b/drivers/iio/adc/mcp3422.c +@@ -407,7 +407,14 @@ static const struct i2c_device_id mcp3422_id = { + MODULE_DEVICE_TABLE(i2c, mcp3422_id); + + static const struct of_device_id mcp3422_of_match = { +- { .compatible = "mcp3422" }, ++ { .compatible = "microchip,mcp3421" }, ++ { .compatible = "microchip,mcp3422" }, ++ { .compatible = "microchip,mcp3423" }, ++ { .compatible = "microchip,mcp3424" }, ++ { .compatible = "microchip,mcp3425" }, ++ { .compatible = "microchip,mcp3426" }, ++ { .compatible = "microchip,mcp3427" }, ++ { .compatible = "microchip,mcp3428" }, + { } + }; + MODULE_DEVICE_TABLE(of, mcp3422_of_match); +diff --git a/drivers/iio/light/tsl4531.c b/drivers/iio/light/tsl4531.c +index 4da7d78906d4..39a6b1f8fe99 100644 +--- a/drivers/iio/light/tsl4531.c ++++ b/drivers/iio/light/tsl4531.c +@@ -232,9 +232,16 @@ static const struct i2c_device_id tsl4531_id = { + }; + MODULE_DEVICE_TABLE(i2c, tsl4531_id); + ++static const struct of_device_id tsl4531_of_id = { ++ { .compatible = "amstaos,tsl4531" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, tsl4531_of_id); ++ + static struct i2c_driver tsl4531_driver = { + .driver = { + .name = TSL4531_DRV_NAME, ++ .of_match_table = tsl4531_of_id, + .pm = pm_sleep_ptr(&tsl4531_pm_ops), + }, + .probe = tsl4531_probe, +diff --git a/drivers/iio/light/veml6070.c b/drivers/iio/light/veml6070.c +index d99bf3ae0fe8..b90cf0492bc4 100644 +--- a/drivers/iio/light/veml6070.c ++++ b/drivers/iio/light/veml6070.c +@@ -194,9 +194,16 @@ static const struct i2c_device_id veml6070_id = { + }; + MODULE_DEVICE_TABLE(i2c, veml6070_id); + ++static const struct of_device_id veml6070_of_id = { ++ { .compatible = "vishay,veml6070" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, veml6070_of_id); ++ + static struct i2c_driver veml6070_driver = { + .driver = { + .name = VEML6070_DRV_NAME, ++ .of_match_table = veml6070_of_id, + }, + .probe = veml6070_probe, + .remove = veml6070_remove, diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig -index b080f0cfb068..7457dd54fee9 100644 +index ac6925ce8366..6e12fd8e4376 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig -@@ -382,4 +382,12 @@ config JOYSTICK_FSIA6B +@@ -412,4 +412,12 @@ config JOYSTICK_SENSEHAT To compile this driver as a module, choose M here: the - module will be called fsia6b. + module will be called sensehat_joystick. +config JOYSTICK_RPISENSE + tristate "Raspberry Pi Sense HAT joystick" @@ -69869,14 +99402,13 @@ + endif diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile -index 58232b3057d3..f5b39db324b3 100644 +index 3937535f0098..038a76a2513a 100644 --- a/drivers/input/joystick/Makefile +++ b/drivers/input/joystick/Makefile -@@ -37,4 +37,4 @@ obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o +@@ -40,3 +40,4 @@ obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o 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 --git a/drivers/input/joystick/rpisense-js.c b/drivers/input/joystick/rpisense-js.c new file mode 100644 @@ -70037,64 +99569,215 @@ +MODULE_DESCRIPTION("Raspberry Pi Sense HAT joystick driver"); +MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>"); +MODULE_LICENSE("GPL"); +diff --git a/drivers/input/misc/da7280.c b/drivers/input/misc/da7280.c +index ce82548916bb..c1fa75c0f970 100644 +--- a/drivers/input/misc/da7280.c ++++ b/drivers/input/misc/da7280.c +@@ -352,7 +352,7 @@ static int da7280_haptic_set_pwm(struct da7280_haptic *haptics, bool enabled) + state.duty_cycle = period_mag_multi; + } + +- error = pwm_apply_state(haptics->pwm_dev, &state); ++ error = pwm_apply_might_sleep(haptics->pwm_dev, &state); + if (error) + dev_err(haptics->dev, "Failed to apply pwm state: %d\n", error); + +@@ -1175,7 +1175,7 @@ static int da7280_probe(struct i2c_client *client) + /* Sync up PWM state and ensure it is off. */ + pwm_init_state(haptics->pwm_dev, &state); + state.enabled = false; +- error = pwm_apply_state(haptics->pwm_dev, &state); ++ error = pwm_apply_might_sleep(haptics->pwm_dev, &state); + if (error) { + dev_err(dev, "Failed to apply PWM state: %d\n", error); + return error; +diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c +index 1e731d8397c6..5b9aedf4362f 100644 +--- a/drivers/input/misc/pwm-beeper.c ++++ b/drivers/input/misc/pwm-beeper.c +@@ -39,7 +39,7 @@ static int pwm_beeper_on(struct pwm_beeper *beeper, unsigned long period) + state.period = period; + pwm_set_relative_duty_cycle(&state, 50, 100); + +- error = pwm_apply_state(beeper->pwm, &state); ++ error = pwm_apply_might_sleep(beeper->pwm, &state); + if (error) + return error; + +@@ -138,7 +138,7 @@ static int pwm_beeper_probe(struct platform_device *pdev) + /* Sync up PWM state and ensure it is off. */ + pwm_init_state(beeper->pwm, &state); + state.enabled = false; +- error = pwm_apply_state(beeper->pwm, &state); ++ error = pwm_apply_might_sleep(beeper->pwm, &state); + if (error) { + dev_err(dev, "failed to apply initial PWM state: %d\n", + error); +diff --git a/drivers/input/misc/pwm-vibra.c b/drivers/input/misc/pwm-vibra.c +index acac79c488aa..3e5ed685ed8f 100644 +--- a/drivers/input/misc/pwm-vibra.c ++++ b/drivers/input/misc/pwm-vibra.c +@@ -56,7 +56,7 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator) + pwm_set_relative_duty_cycle(&state, vibrator->level, 0xffff); + state.enabled = true; + +- err = pwm_apply_state(vibrator->pwm, &state); ++ err = pwm_apply_might_sleep(vibrator->pwm, &state); + if (err) { + dev_err(pdev, "failed to apply pwm state: %d\n", err); + return err; +@@ -67,7 +67,7 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator) + state.duty_cycle = vibrator->direction_duty_cycle; + state.enabled = true; + +- err = pwm_apply_state(vibrator->pwm_dir, &state); ++ err = pwm_apply_might_sleep(vibrator->pwm_dir, &state); + if (err) { + dev_err(pdev, "failed to apply dir-pwm state: %d\n", err); + pwm_disable(vibrator->pwm); +@@ -160,7 +160,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev) + /* Sync up PWM state and ensure it is off. */ + pwm_init_state(vibrator->pwm, &state); + state.enabled = false; +- err = pwm_apply_state(vibrator->pwm, &state); ++ err = pwm_apply_might_sleep(vibrator->pwm, &state); + if (err) { + dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n", + err); +@@ -174,7 +174,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev) + /* Sync up PWM state and ensure it is off. */ + pwm_init_state(vibrator->pwm_dir, &state); + state.enabled = false; +- err = pwm_apply_state(vibrator->pwm_dir, &state); ++ err = pwm_apply_might_sleep(vibrator->pwm_dir, &state); + if (err) { + dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n", + err); +diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c +index faea40dd66d0..262d23749440 100644 +--- a/drivers/input/touchscreen/ads7846.c ++++ b/drivers/input/touchscreen/ads7846.c +@@ -1114,6 +1114,16 @@ static const struct of_device_id ads7846_dt_ids = { + }; + MODULE_DEVICE_TABLE(of, ads7846_dt_ids); + ++static const struct spi_device_id ads7846_spi_ids = { ++ { "tsc2046", 0 }, ++ { "ads7843", 0 }, ++ { "ads7845", 0 }, ++ { "ads7846", 0 }, ++ { "ads7873", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(spi, ads7846_spi_ids); ++ + static const struct ads7846_platform_data *ads7846_get_props(struct device *dev) + { + struct ads7846_platform_data *pdata; +@@ -1390,6 +1400,7 @@ static struct spi_driver ads7846_driver = { + .pm = pm_sleep_ptr(&ads7846_pm), + .of_match_table = ads7846_dt_ids, + }, ++ .id_table = ads7846_spi_ids, + .probe = ads7846_probe, + .remove = ads7846_remove, + }; diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c -index 6ff81d48da86..9be7a6aba409 100644 +index 457d53337fbb..1d2b8df0aea9 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c -@@ -69,6 +69,8 @@ +@@ -69,6 +69,7 @@ + #define TOUCH_EVENT_RESERVED 0x03 + + #define EDT_NAME_LEN 23 ++#define EDT_NAME_PREFIX_LEN 8 + #define EDT_SWITCH_MODE_RETRIES 10 + #define EDT_SWITCH_MODE_DELAY 5 /* msec */ #define EDT_RAW_DATA_RETRIES 100 - #define EDT_RAW_DATA_DELAY 1000 /* usec */ +@@ -80,6 +81,10 @@ + #define M06_REG_CMD(factory) ((factory) ? 0xf3 : 0xfc) + #define M06_REG_ADDR(factory, addr) ((factory) ? (addr) & 0x7f : (addr) & 0x3f) ++#define RESET_DELAY_MS 300 /* reset deassert to I2C */ ++#define FIRST_POLL_DELAY_MS 300 /* in addition to the above */ +#define POLL_INTERVAL_MS 17 /* 17ms = 60fps */ + enum edt_pmode { EDT_PMODE_NOT_SUPPORTED, EDT_PMODE_HIBERNATE, -@@ -121,11 +123,15 @@ struct edt_ft5x06_ts_data { - int offset_y; - int report_rate; - int max_support_points; +@@ -139,14 +144,19 @@ struct edt_ft5x06_ts_data { + u8 tdata_cmd; + int tdata_len; + int tdata_offset; + unsigned int known_ids; - char nameEDT_NAME_LEN; +- char nameEDT_NAME_LEN; ++ char nameEDT_NAME_PREFIX_LEN + EDT_NAME_LEN; + char fw_versionEDT_NAME_LEN; ++ int init_td_status; struct edt_reg_addr reg_addr; enum edt_ver version; + unsigned int crc_errors; + unsigned int header_errors; + + struct timer_list timer; + struct work_struct work_i2c_poll; }; struct edt_i2c_chip_data { -@@ -192,6 +198,10 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) +@@ -303,17 +313,49 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) + u8 rdbuf63; int i, type, x, y, id; - int offset, tplen, datalen, crclen; int error; ++ int num_points; + unsigned int active_ids = 0, known_ids = tsdata->known_ids; + long released_ids; + int b = 0; -+ unsigned int num_points; - switch (tsdata->version) { - case EDT_M06: -@@ -239,9 +249,15 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) - - if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, datalen)) - goto out; + memset(rdbuf, 0, sizeof(rdbuf)); + error = regmap_bulk_read(tsdata->regmap, tsdata->tdata_cmd, rdbuf, + tsdata->tdata_len); ++ if (tsdata->version == EDT_M06) { + num_points = tsdata->max_support_points; + } else { + /* Register 2 is TD_STATUS, containing the number of touch + * points. + */ + num_points = min(rdbuf2 & 0xf, tsdata->max_support_points); ++ ++ /* When polling FT5x06 without IRQ: initial register contents ++ * could be stale or undefined; discard all readings until ++ * TD_STATUS changes for the first time (or num_points is 0). ++ */ ++ if (tsdata->init_td_status) { ++ if (tsdata->init_td_status < 0) ++ tsdata->init_td_status = rdbuf2; ++ ++ if (num_points && rdbuf2 == tsdata->init_td_status) ++ goto out; ++ ++ tsdata->init_td_status = 0; ++ } ++ ++ if (!error && num_points) ++ error = regmap_bulk_read(tsdata->regmap, ++ tsdata->tdata_offset, ++ &rdbuftsdata->tdata_offset, ++ tsdata->point_len * num_points); ++ } + if (error) { + dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n", + error); + goto out; } - for (i = 0; i < tsdata->max_support_points; i++) { + for (i = 0; i < num_points; i++) { - u8 *buf = &rdbufi * tplen + offset; + u8 *buf = &rdbufi * tsdata->point_len + tsdata->tdata_offset; type = buf0 >> 6; -@@ -263,10 +279,25 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) +@@ -335,11 +377,26 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) input_mt_slot(tsdata->input, id); if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, @@ -70106,8 +99789,8 @@ + } else { + known_ids &= ~BIT(id); + } -+ } -+ + } + + /* One issue with the device is the TOUCH_UP message is not always + * returned. Instead track which ids we know about and report when they + * are no longer updated @@ -70116,12 +99799,13 @@ + for_each_set_bit_from(b, &released_ids, tsdata->max_support_points) { + input_mt_slot(tsdata->input, b); + input_mt_report_slot_inactive(tsdata->input); - } ++ } + tsdata->known_ids = active_ids; - ++ input_mt_report_pointer_emulation(tsdata->input, true); input_sync(tsdata->input); -@@ -275,6 +306,22 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) + +@@ -347,6 +404,22 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) return IRQ_HANDLED; } @@ -70141,12 +99825,56 @@ + edt_ft5x06_ts_isr(0, tsdata); +} + - static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata, - u8 addr, u8 value) - { -@@ -1221,17 +1268,27 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, + struct edt_ft5x06_attribute { + struct device_attribute dattr; + size_t field_offset; +@@ -865,6 +938,9 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, + char *model_name = tsdata->name; + char *fw_version = tsdata->fw_version; + ++ snprintf(model_name, EDT_NAME_PREFIX_LEN + 1, "%s ", dev_name(&client->dev)); ++ model_name += strlen(model_name); ++ + /* see what we find if we assume it is a M06 * + * if we get less than EDT_NAME_LEN, we don't want + * to have garbage in there +@@ -1053,20 +1129,23 @@ static void edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) + static void edt_ft5x06_ts_set_tdata_parameters(struct edt_ft5x06_ts_data *tsdata) + { + int crclen; ++ int points; + + if (tsdata->version == EDT_M06) { + tsdata->tdata_cmd = 0xf9; + tsdata->tdata_offset = 5; + tsdata->point_len = 4; + crclen = 1; ++ points = tsdata->max_support_points; + } else { + tsdata->tdata_cmd = 0x0; + tsdata->tdata_offset = 3; + tsdata->point_len = 6; + crclen = 0; ++ points = 0; + } + +- tsdata->tdata_len = tsdata->point_len * tsdata->max_support_points + ++ tsdata->tdata_len = tsdata->point_len * points + + tsdata->tdata_offset + crclen; + } + +@@ -1243,7 +1322,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) + if (tsdata->reset_gpio) { + usleep_range(5000, 6000); + gpiod_set_value_cansleep(tsdata->reset_gpio, 0); +- msleep(300); ++ msleep(RESET_DELAY_MS); + } - i2c_set_clientdata(client, tsdata); + input = devm_input_allocate_device(&client->dev); +@@ -1317,17 +1396,28 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) + return error; + } - irq_flags = irq_get_trigger_type(client->irq); - if (irq_flags == IRQF_TRIGGER_NONE) @@ -70159,8 +99887,8 @@ + irq_flags |= IRQF_ONESHOT; - error = devm_request_threaded_irq(&client->dev, client->irq, -- NULL, edt_ft5x06_ts_isr, irq_flags, -- client->name, tsdata); +- NULL, edt_ft5x06_ts_isr, irq_flags, +- client->name, tsdata); - if (error) { - dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); - return error; @@ -70173,16 +99901,17 @@ + return error; + } + } else { ++ tsdata->init_td_status = -1; /* filter bogus initial data */ + INIT_WORK(&tsdata->work_i2c_poll, + edt_ft5x06_ts_work_i2c_poll); + timer_setup(&tsdata->timer, edt_ft5x06_ts_irq_poll_timer, 0); -+ tsdata->timer.expires = jiffies + -+ msecs_to_jiffies(POLL_INTERVAL_MS); ++ tsdata->timer.expires = ++ jiffies + msecs_to_jiffies(FIRST_POLL_DELAY_MS); + add_timer(&tsdata->timer); } error = devm_device_add_group(&client->dev, &edt_ft5x06_attr_group); -@@ -1257,6 +1314,10 @@ static int edt_ft5x06_ts_remove(struct i2c_client *client) +@@ -1353,6 +1443,10 @@ static void edt_ft5x06_ts_remove(struct i2c_client *client) { struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); @@ -70191,10 +99920,1389 @@ + cancel_work_sync(&tsdata->work_i2c_poll); + } edt_ft5x06_ts_teardown_debugfs(tsdata); + regmap_exit(tsdata->regmap); + } +diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c +index b068ff8afbc9..23134a20ef50 100644 +--- a/drivers/input/touchscreen/goodix.c ++++ b/drivers/input/touchscreen/goodix.c +@@ -48,6 +48,8 @@ + #define MAX_CONTACTS_LOC 5 + #define TRIGGER_LOC 6 - return 0; ++#define POLL_INTERVAL_MS 17 /* 17ms = 60fps */ ++ + /* Our special handling for GPIO accesses through ACPI is x86 specific */ + #if defined CONFIG_X86 && defined CONFIG_ACPI + #define ACPI_GPIO_SUPPORT +@@ -513,16 +515,67 @@ static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id) + return IRQ_HANDLED; + } + ++static void goodix_ts_irq_poll_timer(struct timer_list *t) ++{ ++ struct goodix_ts_data *ts = from_timer(ts, t, timer); ++ ++ schedule_work(&ts->work_i2c_poll); ++ mod_timer(&ts->timer, jiffies + msecs_to_jiffies(POLL_INTERVAL_MS)); ++} ++ ++static void goodix_ts_work_i2c_poll(struct work_struct *work) ++{ ++ struct goodix_ts_data *ts = container_of(work, ++ struct goodix_ts_data, work_i2c_poll); ++ ++ goodix_process_events(ts); ++ goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0); ++} ++ ++static void goodix_enable_irq(struct goodix_ts_data *ts) ++{ ++ if (ts->client->irq) { ++ enable_irq(ts->client->irq); ++ } else { ++ ts->timer.expires = jiffies + msecs_to_jiffies(POLL_INTERVAL_MS); ++ add_timer(&ts->timer); ++ } ++} ++ ++static void goodix_disable_irq(struct goodix_ts_data *ts) ++{ ++ if (ts->client->irq) { ++ disable_irq(ts->client->irq); ++ } else { ++ del_timer(&ts->timer); ++ cancel_work_sync(&ts->work_i2c_poll); ++ } ++} ++ + static void goodix_free_irq(struct goodix_ts_data *ts) + { +- devm_free_irq(&ts->client->dev, ts->client->irq, ts); ++ if (ts->client->irq) { ++ devm_free_irq(&ts->client->dev, ts->client->irq, ts); ++ } else { ++ del_timer(&ts->timer); ++ cancel_work_sync(&ts->work_i2c_poll); ++ } + } + + static int goodix_request_irq(struct goodix_ts_data *ts) + { +- return devm_request_threaded_irq(&ts->client->dev, ts->client->irq, +- NULL, goodix_ts_irq_handler, +- ts->irq_flags, ts->client->name, ts); ++ if (ts->client->irq) { ++ return devm_request_threaded_irq(&ts->client->dev, ts->client->irq, ++ NULL, goodix_ts_irq_handler, ++ ts->irq_flags, ts->client->name, ts); ++ } else { ++ INIT_WORK(&ts->work_i2c_poll, ++ goodix_ts_work_i2c_poll); ++ timer_setup(&ts->timer, goodix_ts_irq_poll_timer, 0); ++ if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) ++ goodix_enable_irq(ts); ++ return 0; ++ } + } + + static int goodix_check_cfg_8(struct goodix_ts_data *ts, const u8 *cfg, int len) +@@ -1141,7 +1194,10 @@ static int goodix_configure_dev(struct goodix_ts_data *ts) + return -ENOMEM; + } + +- ts->input_dev->name = "Goodix Capacitive TouchScreen"; ++ snprintf(ts->name, GOODIX_NAME_MAX_LEN, "%s Goodix Capacitive TouchScreen", ++ dev_name(&ts->client->dev)); ++ ++ ts->input_dev->name = ts->name; + ts->input_dev->phys = "input/ts"; + ts->input_dev->id.bustype = BUS_I2C; + ts->input_dev->id.vendor = 0x0416; +@@ -1407,6 +1463,11 @@ static void goodix_ts_remove(struct i2c_client *client) + { + struct goodix_ts_data *ts = i2c_get_clientdata(client); + ++ if (!client->irq) { ++ del_timer(&ts->timer); ++ cancel_work_sync(&ts->work_i2c_poll); ++ } ++ + if (ts->load_cfg_from_disk) + wait_for_completion(&ts->firmware_loading_complete); + } +@@ -1422,7 +1483,7 @@ static int goodix_suspend(struct device *dev) + + /* We need gpio pins to suspend/resume */ + if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) { +- disable_irq(client->irq); ++ goodix_disable_irq(ts); + return 0; + } + +@@ -1466,7 +1527,7 @@ static int goodix_resume(struct device *dev) + int error; + + if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) { +- enable_irq(client->irq); ++ goodix_enable_irq(ts); + return 0; + } + +diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h +index 87797cc88b32..235dd5f264c5 100644 +--- a/drivers/input/touchscreen/goodix.h ++++ b/drivers/input/touchscreen/goodix.h +@@ -57,6 +57,8 @@ + #define GOODIX_CONFIG_MAX_LENGTH 240 + #define GOODIX_MAX_KEYS 7 + ++#define GOODIX_NAME_MAX_LEN 38 ++ + enum goodix_irq_pin_access_method { + IRQ_PIN_ACCESS_NONE, + IRQ_PIN_ACCESS_GPIO, +@@ -91,6 +93,7 @@ struct goodix_ts_data { + enum gpiod_flags gpiod_rst_flags; + char idGOODIX_ID_MAX_LEN + 1; + char cfg_name64; ++ char nameGOODIX_NAME_MAX_LEN; + u16 version; + bool reset_controller_at_probe; + bool load_cfg_from_disk; +@@ -104,6 +107,8 @@ struct goodix_ts_data { + u8 main_clkGOODIX_MAIN_CLK_LEN; + int bak_ref_len; + u8 *bak_ref; ++ struct timer_list timer; ++ struct work_struct work_i2c_poll; + }; + + int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len); +diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig +index c59b1942d5bb..4b4461d56aaf 100644 +--- a/drivers/iommu/Kconfig ++++ b/drivers/iommu/Kconfig +@@ -527,4 +527,11 @@ config SMMU_BYPASS_DEV + E.g:SMMU allow iMR3408/3416 Raid bypass at DMA default domain + to support other devices Virtualization through. + ++config BCM2712_IOMMU ++ bool "BCM2712 IOMMU driver" ++ depends on ARM64 && ARCH_BCM ++ select IOMMU_API ++ help ++ IOMMU driver for BCM2712 ++ + endif # IOMMU_SUPPORT +diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile +index c2ea11d810ca..036793279696 100644 +--- a/drivers/iommu/Makefile ++++ b/drivers/iommu/Makefile +@@ -30,3 +30,4 @@ obj-$(CONFIG_IOMMU_SVA) += iommu-sva.o + obj-$(CONFIG_IOMMU_IOPF) += io-pgfault.o + obj-$(CONFIG_SPRD_IOMMU) += sprd-iommu.o + obj-$(CONFIG_APPLE_DART) += apple-dart.o ++obj-$(CONFIG_BCM2712_IOMMU) += bcm2712-iommu.o bcm2712-iommu-cache.o +diff --git a/drivers/iommu/bcm2712-iommu-cache.c b/drivers/iommu/bcm2712-iommu-cache.c +new file mode 100644 +index 000000000000..fdea69f5370b +--- /dev/null ++++ b/drivers/iommu/bcm2712-iommu-cache.c +@@ -0,0 +1,77 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * IOMMU driver for BCM2712 ++ * ++ * Copyright (c) 2023 Raspberry Pi Ltd. ++ */ ++ ++#include "bcm2712-iommu.h" ++ ++#include <linux/err.h> ++#include <linux/of_platform.h> ++#include <linux/platform_device.h> ++#include <linux/spinlock.h> ++ ++#define MMUC_CONTROL_ENABLE 1 ++#define MMUC_CONTROL_FLUSH 2 ++#define MMUC_CONTROL_FLUSHING 4 ++ ++void bcm2712_iommu_cache_flush(struct bcm2712_iommu_cache *cache) ++{ ++ unsigned long flags; ++ int i; ++ ++ spin_lock_irqsave(&cache->hw_lock, flags); ++ if (cache->reg_base) { ++ /* Enable and flush the TLB cache */ ++ writel(MMUC_CONTROL_ENABLE | MMUC_CONTROL_FLUSH, ++ cache->reg_base); ++ ++ /* Wait for flush to complete: it should be very quick */ ++ for (i = 0; i < 1024; i++) { ++ if (!(MMUC_CONTROL_FLUSHING & readl(cache->reg_base))) ++ break; ++ cpu_relax(); ++ } ++ } ++ spin_unlock_irqrestore(&cache->hw_lock, flags); ++} ++ ++static int bcm2712_iommu_cache_probe(struct platform_device *pdev) ++{ ++ struct bcm2712_iommu_cache *cache; ++ ++ dev_info(&pdev->dev, __func__); ++ cache = devm_kzalloc(&pdev->dev, sizeof(*cache), GFP_KERNEL); ++ if (!cache) ++ return -ENOMEM; ++ ++ cache->dev = &pdev->dev; ++ platform_set_drvdata(pdev, cache); ++ spin_lock_init(&cache->hw_lock); ++ ++ /* Get IOMMUC registers; we only use the first register (IOMMUC_CTRL) */ ++ cache->reg_base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(cache->reg_base)) { ++ dev_err(&pdev->dev, "Failed to get IOMMU Cache registers address\n"); ++ cache->reg_base = NULL; ++ } ++ return 0; ++} ++ ++static const struct of_device_id bcm2712_iommu_cache_of_match = { ++ { ++ . compatible = "brcm,bcm2712-iommuc" ++ }, ++ { /* sentinel */ }, ++}; ++ ++static struct platform_driver bcm2712_iommu_cache_driver = { ++ .probe = bcm2712_iommu_cache_probe, ++ .driver = { ++ .name = "bcm2712-iommu-cache", ++ .of_match_table = bcm2712_iommu_cache_of_match ++ }, ++}; ++ ++builtin_platform_driver(bcm2712_iommu_cache_driver); +diff --git a/drivers/iommu/bcm2712-iommu.c b/drivers/iommu/bcm2712-iommu.c +new file mode 100644 +index 000000000000..576550669f6f +--- /dev/null ++++ b/drivers/iommu/bcm2712-iommu.c +@@ -0,0 +1,665 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * IOMMU driver for BCM2712 ++ * ++ * Copyright (c) 2023 Raspberry Pi Ltd. ++ */ ++ ++#include "bcm2712-iommu.h" ++ ++#include <linux/dma-mapping.h> ++#include <linux/err.h> ++#include <linux/iommu.h> ++#include <linux/of_platform.h> ++#include <linux/platform_device.h> ++#include <linux/spinlock.h> ++ ++#define MMU_WR(off, val) writel(val, mmu->reg_base + (off)) ++#define MMU_RD(off) readl(mmu->reg_base + (off)) ++ ++#define domain_to_mmu(d) (container_of(d, struct bcm2712_iommu_domain, base)->mmu) ++ ++#define MMMU_CTRL_OFFSET 0x00 ++#define MMMU_CTRL_CAP_EXCEEDED BIT(27) ++#define MMMU_CTRL_CAP_EXCEEDED_ABORT_EN BIT(26) ++#define MMMU_CTRL_CAP_EXCEEDED_INT_EN BIT(25) ++#define MMMU_CTRL_CAP_EXCEEDED_EXCEPTION_EN BIT(24) ++#define MMMU_CTRL_PT_INVALID BIT(20) ++#define MMMU_CTRL_PT_INVALID_ABORT_EN BIT(19) ++#define MMMU_CTRL_PT_INVALID_EXCEPTION_EN BIT(18) ++#define MMMU_CTRL_PT_INVALID_EN BIT(17) ++#define MMMU_CTRL_WRITE_VIOLATION BIT(12) ++#define MMMU_CTRL_WRITE_VIOLATION_ABORT_EN BIT(11) ++#define MMMU_CTRL_WRITE_VIOLATION_INT_EN BIT(10) ++#define MMMU_CTRL_WRITE_VIOLATION_EXCEPTION_EN BIT(9) ++#define MMMU_CTRL_BYPASS BIT(8) ++#define MMMU_CTRL_TLB_CLEARING BIT(7) ++#define MMMU_CTRL_STATS_CLEAR BIT(3) ++#define MMMU_CTRL_TLB_CLEAR BIT(2) ++#define MMMU_CTRL_STATS_ENABLE BIT(1) ++#define MMMU_CTRL_ENABLE BIT(0) ++ ++#define MMMU_PT_PA_BASE_OFFSET 0x04 ++ ++#define MMMU_HIT_OFFSET 0x08 ++#define MMMU_MISS_OFFSET 0x0C ++#define MMMU_STALL_OFFSET 0x10 ++ ++#define MMMU_ADDR_CAP_OFFSET 0x14 ++#define MMMU_ADDR_CAP_ENABLE BIT(31) ++#define ADDR_CAP_SHIFT 28 /* ADDR_CAP is defined to be in 256 MByte units */ ++ ++#define MMMU_SHOOT_DOWN_OFFSET 0x18 ++#define MMMU_SHOOT_DOWN_SHOOTING BIT(31) ++#define MMMU_SHOOT_DOWN_SHOOT BIT(30) ++ ++#define MMMU_BYPASS_START_OFFSET 0x1C ++#define MMMU_BYPASS_START_ENABLE BIT(31) ++#define MMMU_BYPASS_START_INVERT BIT(30) ++ ++#define MMMU_BYPASS_END_OFFSET 0x20 ++#define MMMU_BYPASS_END_ENABLE BIT(31) ++ ++#define MMMU_MISC_OFFSET 0x24 ++#define MMMU_MISC_SINGLE_TABLE BIT(31) ++ ++#define MMMU_ILLEGAL_ADR_OFFSET 0x30 ++#define MMMU_ILLEGAL_ADR_ENABLE BIT(31) ++ ++#define MMMU_DEBUG_INFO_OFFSET 0x38 ++#define MMMU_DEBUG_INFO_VERSION_MASK 0x0000000Fu ++#define MMMU_DEBUG_INFO_VA_WIDTH_MASK 0x000000F0u ++#define MMMU_DEBUG_INFO_PA_WIDTH_MASK 0x00000F00u ++#define MMMU_DEBUG_INFO_BIGPAGE_WIDTH_MASK 0x000FF000u ++#define MMMU_DEBUG_INFO_SUPERPAGE_WIDTH_MASK 0x0FF00000u ++#define MMMU_DEBUG_INFO_BYPASS_4M BIT(28) ++#define MMMU_DEBUG_INFO_BYPASS BIT(29) ++ ++#define MMMU_PTE_PAGESIZE_MASK 0xC0000000u ++#define MMMU_PTE_WRITEABLE BIT(29) ++#define MMMU_PTE_VALID BIT(28) ++ ++/* ++ * BCM2712 IOMMU is organized around 4Kbyte pages (MMU_PAGE_SIZE). ++ * Linux PAGE_SIZE must not be smaller but may be larger (e.g. 4K, 16K). ++ * ++ * Unlike many larger MMUs, this one uses a 4-byte word size, allowing ++ * 1024 entries within each 4K table page, and two-level translation. ++ * ++ * Let's allocate enough table space for 2GB of translated memory (IOVA). ++ * This requires 512 4K pages (2MB) of level-2 tables, one page of ++ * top-level table (only half-filled in this particular configuration), ++ * plus one "default" page to catch illegal requests. ++ * ++ * The translated virtual address region is between 40GB and 42GB; ++ * addresses below this range pass straight through to the SDRAM. ++ * ++ * Currently we assume a 1:1:1 correspondence of IOMMU, group and domain. ++ */ ++ ++#define MMU_PAGE_SHIFT 12 ++#define MMU_PAGE_SIZE BIT(MMU_PAGE_SHIFT) ++ ++#define PAGEWORDS_SHIFT (MMU_PAGE_SHIFT - 2) ++#define HUGEPAGE_SHIFT (MMU_PAGE_SHIFT + PAGEWORDS_SHIFT) ++#define L1_CHUNK_SHIFT (MMU_PAGE_SHIFT + 2 * PAGEWORDS_SHIFT) ++ ++#define APERTURE_BASE (40ul << 30) ++#define APERTURE_SIZE (2ul << 30) ++#define APERTURE_TOP (APERTURE_BASE + APERTURE_SIZE) ++#define TRANSLATED_PAGES (APERTURE_SIZE >> MMU_PAGE_SHIFT) ++#define L2_PAGES (TRANSLATED_PAGES >> PAGEWORDS_SHIFT) ++#define TABLES_ALLOC_SIZE (L2_PAGES * MMU_PAGE_SIZE + 2 * PAGE_SIZE) ++ ++static void bcm2712_iommu_init(struct bcm2712_iommu *mmu) ++{ ++ unsigned int i, bypass_shift; ++ struct sg_dma_page_iter it; ++ u32 u = MMU_RD(MMMU_DEBUG_INFO_OFFSET); ++ ++ /* ++ * Check IOMMU version and hardware configuration. ++ * This driver is for VC IOMMU version >= 4 (with 2-level tables) ++ * and assumes at least 36 bits of virtual and physical address space. ++ * Bigpage and superpage sizes are typically 64K and 1M, but may vary ++ * (hugepage size is fixed at 4M, the range covered by an L2 page). ++ */ ++ dev_info(mmu->dev, "%s: DEBUG_INFO = 0x%08x\n", __func__, u); ++ WARN_ON(FIELD_GET(MMMU_DEBUG_INFO_VERSION_MASK, u) < 4 || ++ FIELD_GET(MMMU_DEBUG_INFO_VA_WIDTH_MASK, u) < 6 || ++ FIELD_GET(MMMU_DEBUG_INFO_PA_WIDTH_MASK, u) < 6 || ++ !(u & MMMU_DEBUG_INFO_BYPASS)); ++ ++ mmu->bigpage_mask = ++ ((1u << FIELD_GET(MMMU_DEBUG_INFO_BIGPAGE_WIDTH_MASK, u)) - 1u) << MMU_PAGE_SHIFT; ++ mmu->superpage_mask = ++ ((1u << FIELD_GET(MMMU_DEBUG_INFO_SUPERPAGE_WIDTH_MASK, u)) - 1u) << MMU_PAGE_SHIFT; ++ bypass_shift = (u & MMMU_DEBUG_INFO_BYPASS_4M) ? ++ HUGEPAGE_SHIFT : ADDR_CAP_SHIFT; ++ ++ /* Disable MMU and clear sticky flags; meanwhile flush the TLB */ ++ MMU_WR(MMMU_CTRL_OFFSET, ++ MMMU_CTRL_CAP_EXCEEDED | ++ MMMU_CTRL_PT_INVALID | ++ MMMU_CTRL_WRITE_VIOLATION | ++ MMMU_CTRL_STATS_CLEAR | ++ MMMU_CTRL_TLB_CLEAR); ++ ++ /* ++ * Put MMU into 2-level mode; set address cap and "bypass" range ++ * (note that some of these registers have unintuitive off-by-ones). ++ * Addresses below APERTURE_BASE are passed unchanged: this is ++ * useful for blocks which share an IOMMU with other blocks ++ * whose drivers are not IOMMU-aware. ++ */ ++ MMU_WR(MMMU_MISC_OFFSET, ++ MMU_RD(MMMU_MISC_OFFSET) & ~MMMU_MISC_SINGLE_TABLE); ++ MMU_WR(MMMU_ADDR_CAP_OFFSET, ++ MMMU_ADDR_CAP_ENABLE + ++ (APERTURE_TOP >> ADDR_CAP_SHIFT) - 1); ++ if (APERTURE_BASE > 0) { ++ MMU_WR(MMMU_BYPASS_START_OFFSET, ++ MMMU_BYPASS_START_ENABLE + MMMU_BYPASS_START_INVERT + ++ (APERTURE_BASE >> bypass_shift) - 1); ++ MMU_WR(MMMU_BYPASS_END_OFFSET, ++ MMMU_BYPASS_END_ENABLE + ++ (APERTURE_TOP >> bypass_shift)); ++ } else { ++ MMU_WR(MMMU_BYPASS_START_OFFSET, 0); ++ MMU_WR(MMMU_BYPASS_END_OFFSET, 0); ++ } ++ ++ /* Ensure tables are zeroed (which marks all pages as invalid) */ ++ dma_sync_sgtable_for_cpu(mmu->dev, mmu->sgt, DMA_TO_DEVICE); ++ memset(mmu->tables, 0, TABLES_ALLOC_SIZE); ++ mmu->nmapped_pages = 0; ++ ++ /* Initialize the high-level table to point to the low-level pages */ ++ __sg_page_iter_start(&it.base, mmu->sgt->sgl, mmu->sgt->nents, 0); ++ for (i = 0; i < L2_PAGES; i++) { ++ if (!(i % (PAGE_SIZE / MMU_PAGE_SIZE))) { ++ __sg_page_iter_dma_next(&it); ++ u = (sg_page_iter_dma_address(&it) >> MMU_PAGE_SHIFT); ++ } else { ++ u++; ++ } ++ mmu->tablesTRANSLATED_PAGES + i = MMMU_PTE_VALID + u; ++ } ++ ++ /* ++ * Configure the addresses of the top-level table (offset because ++ * the aperture does not start from zero), and of the default page. ++ * For simplicity, both these regions are whole Linux pages. ++ */ ++ __sg_page_iter_dma_next(&it); ++ u = (sg_page_iter_dma_address(&it) >> MMU_PAGE_SHIFT); ++ MMU_WR(MMMU_PT_PA_BASE_OFFSET, u - (APERTURE_BASE >> L1_CHUNK_SHIFT)); ++ __sg_page_iter_dma_next(&it); ++ u = (sg_page_iter_dma_address(&it) >> MMU_PAGE_SHIFT); ++ MMU_WR(MMMU_ILLEGAL_ADR_OFFSET, MMMU_ILLEGAL_ADR_ENABLE + u); ++ dma_sync_sgtable_for_device(mmu->dev, mmu->sgt, DMA_TO_DEVICE); ++ mmu->dirty = false; ++ ++ /* Flush (and enable) the shared TLB cache; enable this MMU. */ ++ if (mmu->cache) ++ bcm2712_iommu_cache_flush(mmu->cache); ++ MMU_WR(MMMU_CTRL_OFFSET, ++ MMMU_CTRL_CAP_EXCEEDED_ABORT_EN | ++ MMMU_CTRL_PT_INVALID_ABORT_EN | ++ MMMU_CTRL_WRITE_VIOLATION_ABORT_EN | ++ MMMU_CTRL_STATS_ENABLE | ++ MMMU_CTRL_ENABLE); ++} ++ ++static int bcm2712_iommu_attach_dev(struct iommu_domain *domain, struct device *dev) ++{ ++ struct bcm2712_iommu *mmu = dev ? dev_iommu_priv_get(dev) : 0; ++ struct bcm2712_iommu_domain *mydomain = ++ container_of(domain, struct bcm2712_iommu_domain, base); ++ ++ dev_info(dev, "%s: MMU %s\n", ++ __func__, mmu ? dev_name(mmu->dev) : ""); ++ ++ if (mmu) { ++ mydomain->mmu = mmu; ++ mmu->domain = mydomain; ++ ++ if (mmu->dma_iova_offset) { ++ domain->geometry.aperture_start = ++ mmu->dma_iova_offset + APERTURE_BASE; ++ domain->geometry.aperture_end = ++ mmu->dma_iova_offset + APERTURE_TOP - 1ul; ++ } ++ ++ return 0; ++ } ++ return -EINVAL; ++} ++ ++static int bcm2712_iommu_map(struct iommu_domain *domain, unsigned long iova, ++ phys_addr_t pa, size_t bytes, int prot, gfp_t gfp) ++{ ++ struct bcm2712_iommu *mmu = domain_to_mmu(domain); ++ ++ (void)gfp; ++ iova -= mmu->dma_iova_offset; ++ if (iova >= APERTURE_BASE && iova + bytes <= APERTURE_TOP) { ++ unsigned int p; ++ u32 entry = MMMU_PTE_VALID | (pa >> MMU_PAGE_SHIFT); ++ u32 align = (u32)(iova | pa | bytes); ++ ++ /* large page and write enable flags */ ++ if (!(align & ((1 << HUGEPAGE_SHIFT) - 1))) ++ entry |= FIELD_PREP(MMMU_PTE_PAGESIZE_MASK, 3); ++ else if (!(align & mmu->superpage_mask) && mmu->superpage_mask) ++ entry |= FIELD_PREP(MMMU_PTE_PAGESIZE_MASK, 2); ++ else if (!(align & mmu->bigpage_mask) && mmu->bigpage_mask) ++ entry |= FIELD_PREP(MMMU_PTE_PAGESIZE_MASK, 1); ++ if (prot & IOMMU_WRITE) ++ entry |= MMMU_PTE_WRITEABLE; ++ ++ /* Ensure tables are cache-coherent with CPU */ ++ if (!mmu->dirty) { ++ dma_sync_sgtable_for_cpu(mmu->dev, mmu->sgt, DMA_TO_DEVICE); ++ mmu->dirty = true; ++ } ++ ++ iova -= APERTURE_BASE; ++ for (p = iova >> MMU_PAGE_SHIFT; ++ p < (iova + bytes) >> MMU_PAGE_SHIFT; p++) { ++ mmu->nmapped_pages += !(mmu->tablesp); ++ mmu->tablesp = entry++; ++ } ++ } else if (iova + bytes > APERTURE_BASE || iova != pa) { ++ dev_warn(mmu->dev, "%s: iova=0x%lx pa=0x%llx size=0x%llx OUT OF RANGE!\n", ++ __func__, iova, ++ (unsigned long long)pa, (unsigned long long)bytes); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static size_t bcm2712_iommu_unmap(struct iommu_domain *domain, unsigned long iova, ++ size_t bytes, struct iommu_iotlb_gather *gather) ++{ ++ struct bcm2712_iommu *mmu = domain_to_mmu(domain); ++ ++ if (iova >= mmu->dma_iova_offset + APERTURE_BASE && ++ iova + bytes <= mmu->dma_iova_offset + APERTURE_TOP) { ++ unsigned int p; ++ ++ /* Record just the lower and upper bounds in "gather" */ ++ if (gather) { ++ bool empty = (gather->end <= gather->start); ++ ++ if (empty || gather->start < iova) ++ gather->start = iova; ++ if (empty || gather->end < iova + bytes) ++ gather->end = iova + bytes; ++ } ++ ++ /* Ensure tables are cache-coherent with CPU */ ++ if (!mmu->dirty) { ++ dma_sync_sgtable_for_cpu(mmu->dev, mmu->sgt, DMA_TO_DEVICE); ++ mmu->dirty = true; ++ } ++ ++ /* Clear table entries, this marks the addresses as illegal */ ++ iova -= (mmu->dma_iova_offset + APERTURE_BASE); ++ for (p = iova >> MMU_PAGE_SHIFT; ++ p < (iova + bytes) >> MMU_PAGE_SHIFT; ++ p++) { ++ mmu->nmapped_pages -= !!(mmu->tablesp); ++ mmu->tablesp = 0; ++ } ++ } ++ ++ return bytes; ++} ++ ++static void bcm2712_iommu_sync_range(struct iommu_domain *domain, ++ unsigned long iova, size_t size) ++{ ++ struct bcm2712_iommu *mmu = domain_to_mmu(domain); ++ unsigned long iova_end; ++ unsigned int i, p4; ++ ++ if (!mmu || !mmu->dirty) ++ return; ++ ++ /* Ensure tables are cleaned from CPU cache or write-buffer */ ++ dma_sync_sgtable_for_device(mmu->dev, mmu->sgt, DMA_TO_DEVICE); ++ mmu->dirty = false; ++ ++ /* Flush the shared TLB cache */ ++ if (mmu->cache) ++ bcm2712_iommu_cache_flush(mmu->cache); ++ ++ /* ++ * When flushing a large range or when nothing needs to be kept, ++ * it's quicker to use the"TLB_CLEAR" flag. Otherwise, invalidate ++ * TLB entries in lines of 4 words each. Each flush/clear operation ++ * should complete almost instantaneously. ++ */ ++ iova -= mmu->dma_iova_offset; ++ iova_end = min(APERTURE_TOP, iova + size); ++ iova = max(APERTURE_BASE, iova); ++ if (mmu->nmapped_pages == 0 || iova_end - iova >= APERTURE_SIZE / 8) { ++ MMU_WR(MMMU_CTRL_OFFSET, ++ MMMU_CTRL_CAP_EXCEEDED_ABORT_EN | ++ MMMU_CTRL_PT_INVALID_ABORT_EN | ++ MMMU_CTRL_WRITE_VIOLATION_ABORT_EN | ++ MMMU_CTRL_TLB_CLEAR | ++ MMMU_CTRL_STATS_ENABLE | ++ MMMU_CTRL_ENABLE); ++ for (i = 0; i < 1024; i++) { ++ if (!(MMMU_CTRL_TLB_CLEARING & MMU_RD(MMMU_CTRL_OFFSET))) ++ break; ++ cpu_relax(); ++ } ++ } else { ++ for (p4 = iova >> (MMU_PAGE_SHIFT + 2); ++ p4 < (iova_end + 3 * MMU_PAGE_SIZE) >> (MMU_PAGE_SHIFT + 2); ++ p4++) { ++ MMU_WR(MMMU_SHOOT_DOWN_OFFSET, ++ MMMU_SHOOT_DOWN_SHOOT + (p4 << 2)); ++ for (i = 0; i < 1024; i++) { ++ if (!(MMMU_SHOOT_DOWN_SHOOTING & MMU_RD(MMMU_SHOOT_DOWN_OFFSET))) ++ break; ++ cpu_relax(); ++ } ++ } ++ } ++} ++ ++static void bcm2712_iommu_sync(struct iommu_domain *domain, ++ struct iommu_iotlb_gather *gather) ++{ ++ bcm2712_iommu_sync_range(domain, gather->start, ++ gather->end - gather->start); ++} ++ ++static void bcm2712_iommu_sync_all(struct iommu_domain *domain) ++{ ++ bcm2712_iommu_sync_range(domain, APERTURE_BASE, APERTURE_SIZE); ++} ++ ++static phys_addr_t bcm2712_iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova) ++{ ++ struct bcm2712_iommu *mmu = domain_to_mmu(domain); ++ u32 p; ++ ++ iova -= mmu->dma_iova_offset; ++ if (iova >= APERTURE_BASE && iova < APERTURE_TOP) { ++ p = (iova - APERTURE_BASE) >> MMU_PAGE_SHIFT; ++ p = mmu->tablesp & 0x0FFFFFFFu; ++ return (((phys_addr_t)p) << MMU_PAGE_SHIFT) + (iova & (MMU_PAGE_SIZE - 1u)); ++ } else if (iova < APERTURE_BASE) { ++ return (phys_addr_t)iova; ++ } else { ++ return (phys_addr_t)-EINVAL; ++ } ++} ++ ++static void bcm2712_iommu_domain_free(struct iommu_domain *domain) ++{ ++ struct bcm2712_iommu_domain *mydomain = ++ container_of(domain, struct bcm2712_iommu_domain, base); ++ ++ kfree(mydomain); ++} ++ ++static const struct iommu_domain_ops bcm2712_iommu_domain_ops = { ++ .attach_dev = bcm2712_iommu_attach_dev, ++ .map = bcm2712_iommu_map, ++ .unmap = bcm2712_iommu_unmap, ++ .iotlb_sync = bcm2712_iommu_sync, ++ .iotlb_sync_map = bcm2712_iommu_sync_range, ++ .flush_iotlb_all = bcm2712_iommu_sync_all, ++ .iova_to_phys = bcm2712_iommu_iova_to_phys, ++ .free = bcm2712_iommu_domain_free, ++}; ++ ++static struct iommu_domain *bcm2712_iommu_domain_alloc(unsigned int type) ++{ ++ struct bcm2712_iommu_domain *domain; ++ ++ if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA) ++ return NULL; ++ ++ domain = kzalloc(sizeof(*domain), GFP_KERNEL); ++ if (!domain) ++ return NULL; ++ ++ domain->base.type = type; ++ domain->base.ops = &bcm2712_iommu_domain_ops; ++ domain->base.geometry.aperture_start = APERTURE_BASE; ++ domain->base.geometry.aperture_end = APERTURE_TOP - 1ul; ++ domain->base.geometry.force_aperture = true; ++ return &domain->base; ++} ++ ++static struct iommu_device *bcm2712_iommu_probe_device(struct device *dev) ++{ ++ struct bcm2712_iommu *mmu; ++ ++ /* ++ * For reasons I don't fully understand, we need to try both ++ * cases (dev_iommu_priv_get() and platform_get_drvdata()) ++ * in order to get both GPU and ISP-BE to probe successfully. ++ */ ++ mmu = dev_iommu_priv_get(dev); ++ if (!mmu) { ++ struct device_node *np; ++ struct platform_device *pdev; ++ ++ /* Ignore devices that don't have an "iommus" property with exactly one phandle */ ++ if (!dev->of_node || ++ of_property_count_elems_of_size(dev->of_node, "iommus", sizeof(phandle)) != 1) ++ return ERR_PTR(-ENODEV); ++ ++ np = of_parse_phandle(dev->of_node, "iommus", 0); ++ if (!np) ++ return ERR_PTR(-EINVAL); ++ ++ pdev = of_find_device_by_node(np); ++ of_node_put(np); ++ if (pdev) ++ mmu = platform_get_drvdata(pdev); ++ ++ if (!mmu) ++ return ERR_PTR(-ENODEV); ++ } ++ ++ dev_info(dev, "%s: MMU %s\n", __func__, dev_name(mmu->dev)); ++ dev_iommu_priv_set(dev, mmu); ++ return &mmu->iommu; ++} ++ ++static void bcm2712_iommu_release_device(struct device *dev) ++{ ++ dev_iommu_priv_set(dev, NULL); ++} ++ ++static struct iommu_group *bcm2712_iommu_device_group(struct device *dev) ++{ ++ struct bcm2712_iommu *mmu = dev_iommu_priv_get(dev); ++ ++ if (!mmu || !mmu->group) ++ return ERR_PTR(-EINVAL); ++ ++ dev_info(dev, "%s: MMU %s\n", __func__, dev_name(mmu->dev)); ++ return iommu_group_ref_get(mmu->group); ++} ++ ++static int bcm2712_iommu_of_xlate(struct device *dev, ++ struct of_phandle_args *args) ++{ ++ struct platform_device *iommu_dev; ++ struct bcm2712_iommu *mmu; ++ ++ iommu_dev = of_find_device_by_node(args->np); ++ mmu = platform_get_drvdata(iommu_dev); ++ dev_iommu_priv_set(dev, mmu); ++ dev_info(dev, "%s: MMU %s\n", __func__, dev_name(mmu->dev)); ++ ++ return 0; ++} ++ ++static bool bcm2712_iommu_capable(struct device *dev, enum iommu_cap cap) ++{ ++ return false; ++} ++ ++static const struct iommu_ops bcm2712_iommu_ops = { ++ .capable = bcm2712_iommu_capable, ++ .domain_alloc = bcm2712_iommu_domain_alloc, ++ .probe_device = bcm2712_iommu_probe_device, ++ .release_device = bcm2712_iommu_release_device, ++ .device_group = bcm2712_iommu_device_group, ++ /* Advertise native page sizes as well as 2M, 16K which Linux may prefer */ ++ .pgsize_bitmap = (SZ_4M | SZ_2M | SZ_1M | SZ_64K | SZ_16K | SZ_4K), ++ .default_domain_ops = &bcm2712_iommu_domain_ops, ++ .of_xlate = bcm2712_iommu_of_xlate, ++}; ++ ++static int bcm2712_iommu_probe(struct platform_device *pdev) ++{ ++ struct bcm2712_iommu *mmu; ++ struct bcm2712_iommu_cache *cache = NULL; ++ int ret; ++ ++ /* First of all, check for an IOMMU shared cache */ ++ if (pdev->dev.of_node) { ++ struct device_node *cache_np; ++ struct platform_device *cache_pdev; ++ ++ cache_np = of_parse_phandle(pdev->dev.of_node, "cache", 0); ++ if (cache_np) { ++ cache_pdev = of_find_device_by_node(cache_np); ++ of_node_put(cache_np); ++ if (cache_pdev && !IS_ERR(cache_pdev)) ++ cache = platform_get_drvdata(cache_pdev); ++ if (!cache) ++ return -EPROBE_DEFER; ++ } ++ } ++ ++ /* Allocate private data */ ++ mmu = devm_kzalloc(&pdev->dev, sizeof(*mmu), GFP_KERNEL); ++ if (!mmu) ++ return -ENOMEM; ++ ++ mmu->name = dev_name(&pdev->dev); ++ mmu->dev = &pdev->dev; ++ mmu->cache = cache; ++ platform_set_drvdata(pdev, mmu); ++ spin_lock_init(&mmu->hw_lock); ++ ++ /* ++ * XXX When an IOMMU is downstream of a PCIe RC or some other chip/bus ++ * and serves some of the masters thereon (others using pass-through), ++ * we seem to fumble and lose the "dma-ranges" address offset for ++ * masters using IOMMU. This property restores it, where needed. ++ */ ++ if (!pdev->dev.of_node || ++ of_property_read_u64(pdev->dev.of_node, "dma-iova-offset", ++ &mmu->dma_iova_offset)) ++ mmu->dma_iova_offset = 0; ++ ++ /* ++ * The IOMMU is itself a device that allocates DMA-able memory ++ * to hold its translation tables. Provided the IOVA aperture ++ * is no larger than 4 GBytes (so that the L1 table fits within ++ * a single 4K page), we don't need the tables to be contiguous. ++ * Assume we can address at least 36 bits (64 GB). ++ */ ++ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36)); ++ WARN_ON(ret); ++ mmu->sgt = dma_alloc_noncontiguous(&pdev->dev, TABLES_ALLOC_SIZE, ++ DMA_TO_DEVICE, GFP_KERNEL, ++ DMA_ATTR_ALLOC_SINGLE_PAGES); ++ if (!mmu->sgt) { ++ ret = -ENOMEM; ++ goto done_err; ++ } ++ mmu->tables = dma_vmap_noncontiguous(&pdev->dev, TABLES_ALLOC_SIZE, ++ mmu->sgt); ++ if (!mmu->tables) { ++ ret = -ENOMEM; ++ goto done_err; ++ } ++ ++ /* Get IOMMU registers */ ++ mmu->reg_base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(mmu->reg_base)) { ++ dev_err(&pdev->dev, "Failed to get IOMMU registers address\n"); ++ ret = PTR_ERR(mmu->reg_base); ++ goto done_err; ++ } ++ ++ /* Stuff */ ++ mmu->group = iommu_group_alloc(); ++ if (IS_ERR(mmu->group)) { ++ ret = PTR_ERR(mmu->group); ++ mmu->group = NULL; ++ goto done_err; ++ } ++ ret = iommu_device_sysfs_add(&mmu->iommu, mmu->dev, NULL, mmu->name); ++ if (ret) ++ goto done_err; ++ ++ /* Initialize table and hardware */ ++ bcm2712_iommu_init(mmu); ++ ret = iommu_device_register(&mmu->iommu, &bcm2712_iommu_ops, &pdev->dev); ++ ++ dev_info(&pdev->dev, "%s: Success\n", __func__); ++ return 0; ++ ++done_err: ++ dev_info(&pdev->dev, "%s: Failure %d\n", __func__, ret); ++ if (mmu->group) ++ iommu_group_put(mmu->group); ++ if (mmu->tables) ++ dma_vunmap_noncontiguous(&pdev->dev, ++ (void *)(mmu->tables)); ++ mmu->tables = NULL; ++ if (mmu->sgt) ++ dma_free_noncontiguous(&pdev->dev, TABLES_ALLOC_SIZE, ++ mmu->sgt, DMA_TO_DEVICE); ++ mmu->sgt = NULL; ++ kfree(mmu); ++ return ret; ++} ++ ++static int bcm2712_iommu_remove(struct platform_device *pdev) ++{ ++ struct bcm2712_iommu *mmu = platform_get_drvdata(pdev); ++ ++ if (mmu->reg_base) ++ MMU_WR(MMMU_CTRL_OFFSET, 0); /* disable the MMU */ ++ if (mmu->sgt) ++ dma_free_noncontiguous(&pdev->dev, TABLES_ALLOC_SIZE, ++ mmu->sgt, DMA_TO_DEVICE); ++ ++ return 0; ++} ++ ++static const struct of_device_id bcm2712_iommu_of_match = { ++ { ++ . compatible = "brcm,bcm2712-iommu" ++ }, ++ { /* sentinel */ }, ++}; ++ ++static struct platform_driver bcm2712_iommu_driver = { ++ .probe = bcm2712_iommu_probe, ++ .remove = bcm2712_iommu_remove, ++ .driver = { ++ .name = "bcm2712-iommu", ++ .of_match_table = bcm2712_iommu_of_match ++ }, ++}; ++ ++builtin_platform_driver(bcm2712_iommu_driver); +diff --git a/drivers/iommu/bcm2712-iommu.h b/drivers/iommu/bcm2712-iommu.h +new file mode 100644 +index 000000000000..31b811e426dd +--- /dev/null ++++ b/drivers/iommu/bcm2712-iommu.h +@@ -0,0 +1,45 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * IOMMU driver for BCM2712 ++ * ++ * Copyright (c) 2023 Raspberry Pi Ltd. ++ */ ++ ++#ifndef _BCM2712_IOMMU_H ++#define _BCM2712_IOMMU_H ++ ++#include <linux/iommu.h> ++#include <linux/scatterlist.h> ++ ++struct bcm2712_iommu_cache { ++ struct device *dev; ++ spinlock_t hw_lock; /* to protect HW registers */ ++ void __iomem *reg_base; ++}; ++ ++void bcm2712_iommu_cache_flush(struct bcm2712_iommu_cache *cache); ++ ++struct bcm2712_iommu { ++ struct device *dev; ++ struct iommu_device iommu; ++ struct iommu_group *group; ++ struct bcm2712_iommu_domain *domain; ++ char const *name; ++ struct sg_table *sgt; /* allocated memory for page tables */ ++ u32 *tables; /* kernel mapping for page tables */ ++ struct bcm2712_iommu_cache *cache; ++ spinlock_t hw_lock; /* to protect HW registers */ ++ void __iomem *reg_base; ++ u64 dma_iova_offset; /* Hack for IOMMU attached to PCIe RC */ ++ u32 bigpage_mask; ++ u32 superpage_mask; ++ unsigned int nmapped_pages; ++ bool dirty; /* true when tables are oriented towards CPU */ ++}; ++ ++struct bcm2712_iommu_domain { ++ struct iommu_domain base; ++ struct bcm2712_iommu *mmu; ++}; ++ ++#endif +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index 58e7d03fc27c..f98a8f13ecbe 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -2476,11 +2476,8 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, + return -EINVAL; + + ret = __iommu_map(domain, iova, paddr, size, prot, gfp); +- if (ret == 0 && ops->iotlb_sync_map) { +- ret = ops->iotlb_sync_map(domain, iova, size); +- if (ret) +- goto out_err; +- } ++ if (ret == 0 && ops->iotlb_sync_map) ++ ops->iotlb_sync_map(domain, iova, size); + + return ret; + +@@ -2614,11 +2611,8 @@ ssize_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova, + sg = sg_next(sg); + } + +- if (ops->iotlb_sync_map) { +- ret = ops->iotlb_sync_map(domain, iova, mapped); +- if (ret) +- goto out_err; +- } ++ if (ops->iotlb_sync_map) ++ ops->iotlb_sync_map(domain, iova, mapped); + return mapped; + + out_err: +diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig +index e0408e9016b9..023a963012f7 100644 +--- a/drivers/irqchip/Kconfig ++++ b/drivers/irqchip/Kconfig +@@ -152,6 +152,14 @@ config I8259 + bool + select IRQ_DOMAIN + ++config BCM2712_MIP ++ bool "Broadcom 2712 MSI-X Interrupt Peripheral support" ++ depends on ARM_GIC ++ select GENERIC_IRQ_CHIP ++ select IRQ_DOMAIN ++ help ++ Enable support for the Broadcom BCM2712 MSI-X target peripheral. ++ + config BCM6345_L1_IRQ + bool + select GENERIC_IRQ_CHIP +diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile +index 246aa0603d6e..a9f13a66b191 100644 +--- a/drivers/irqchip/Makefile ++++ b/drivers/irqchip/Makefile +@@ -74,6 +74,7 @@ obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o + obj-$(CONFIG_XILINX_INTC) += irq-xilinx-intc.o + obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o + obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o ++obj-$(CONFIG_BCM2712_MIP) += irq-bcm2712-mip.o + obj-$(CONFIG_BCM6345_L1_IRQ) += irq-bcm6345-l1.o + obj-$(CONFIG_BCM7038_L1_IRQ) += irq-bcm7038-l1.o + obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o +diff --git a/drivers/irqchip/irq-bcm2712-mip.c b/drivers/irqchip/irq-bcm2712-mip.c +new file mode 100644 +index 000000000000..2eaa3ac10cb6 +--- /dev/null ++++ b/drivers/irqchip/irq-bcm2712-mip.c +@@ -0,0 +1,323 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2021 Raspberry Pi Ltd., All Rights Reserved. ++ */ ++ ++#include <linux/pci.h> ++#include <linux/msi.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/of_irq.h> ++#include <linux/of_pci.h> ++ ++#include <linux/irqchip.h> ++ ++#define MIP_INT_RAISED 0x00 ++#define MIP_INT_CLEARED 0x10 ++#define MIP_INT_CFGL_HOST 0x20 ++#define MIP_INT_CFGH_HOST 0x30 ++#define MIP_INT_MASKL_HOST 0x40 ++#define MIP_INT_MASKH_HOST 0x50 ++#define MIP_INT_MASKL_VPU 0x60 ++#define MIP_INT_MASKH_VPU 0x70 ++#define MIP_INT_STATUSL_HOST 0x80 ++#define MIP_INT_STATUSH_HOST 0x90 ++#define MIP_INT_STATUSL_VPU 0xa0 ++#define MIP_INT_STATUSH_VPU 0xb0 ++ ++struct mip_priv { ++ spinlock_t msi_map_lock; ++ spinlock_t hw_lock; ++ void * __iomem base; ++ phys_addr_t msg_addr; ++ u32 msi_base; /* The SGI number that MSIs start */ ++ u32 num_msis; /* The number of SGIs for MSIs */ ++ u32 msi_offset; /* Shift the allocated msi up by N */ ++ unsigned long *msi_map; ++}; ++ ++static void mip_mask_msi_irq(struct irq_data *d) ++{ ++ pci_msi_mask_irq(d); ++ irq_chip_mask_parent(d); ++} ++ ++static void mip_unmask_msi_irq(struct irq_data *d) ++{ ++ pci_msi_unmask_irq(d); ++ irq_chip_unmask_parent(d); ++} ++ ++static void mip_compose_msi_msg(struct irq_data *d, struct msi_msg *msg) ++{ ++ struct mip_priv *priv = irq_data_get_irq_chip_data(d); ++ ++ msg->address_hi = upper_32_bits(priv->msg_addr); ++ msg->address_lo = lower_32_bits(priv->msg_addr); ++ msg->data = d->hwirq; ++} ++ ++// The "bus-specific" irq_chip (the MIP doesn't _have_ to be used with PCIe) ++ ++static struct irq_chip mip_msi_irq_chip = { ++ .name = "MIP-MSI", ++ .irq_unmask = mip_unmask_msi_irq, ++ .irq_mask = mip_mask_msi_irq, ++ .irq_eoi = irq_chip_eoi_parent, ++ .irq_set_affinity = irq_chip_set_affinity_parent, ++}; ++ ++static struct msi_domain_info mip_msi_domain_info = { ++ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | ++ MSI_FLAG_PCI_MSIX), ++ .chip = &mip_msi_irq_chip, ++}; ++ ++// The "middle" irq_chip (the hardware control part) ++ ++static struct irq_chip mip_irq_chip = { ++ .name = "MIP", ++ .irq_mask = irq_chip_mask_parent, ++ .irq_unmask = irq_chip_unmask_parent, ++ .irq_eoi = irq_chip_eoi_parent, ++ .irq_set_affinity = irq_chip_set_affinity_parent, ++ .irq_set_type = irq_chip_set_type_parent, ++ .irq_compose_msi_msg = mip_compose_msi_msg, ++}; ++ ++ ++// And a domain to connect it to its parent (the GIC) ++ ++static int mip_irq_domain_alloc(struct irq_domain *domain, ++ unsigned int virq, unsigned int nr_irqs, ++ void *args) ++{ ++ struct mip_priv *priv = domain->host_data; ++ struct irq_fwspec fwspec; ++ struct irq_data *irqd; ++ int hwirq, ret, i; ++ ++ spin_lock(&priv->msi_map_lock); ++ ++ hwirq = bitmap_find_free_region(priv->msi_map, priv->num_msis, ilog2(nr_irqs)); ++ ++ spin_unlock(&priv->msi_map_lock); ++ ++ if (hwirq < 0) ++ return -ENOSPC; ++ ++ hwirq += priv->msi_offset; ++ fwspec.fwnode = domain->parent->fwnode; ++ fwspec.param_count = 3; ++ fwspec.param0 = 0; ++ fwspec.param1 = hwirq + priv->msi_base; ++ fwspec.param2 = IRQ_TYPE_EDGE_RISING; ++ ++ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &fwspec); ++ if (ret) ++ return ret; ++ ++ for (i = 0; i < nr_irqs; i++) { ++ irqd = irq_domain_get_irq_data(domain->parent, virq + i); ++ irqd->chip->irq_set_type(irqd, IRQ_TYPE_EDGE_RISING); ++ ++ irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, ++ &mip_irq_chip, priv); ++ irqd = irq_get_irq_data(virq + i); ++ irqd_set_single_target(irqd); ++ irqd_set_affinity_on_activate(irqd); ++ } ++ ++ return 0; ++} ++ ++static void mip_irq_domain_free(struct irq_domain *domain, ++ unsigned int virq, unsigned int nr_irqs) ++{ ++ struct irq_data *d = irq_domain_get_irq_data(domain, virq); ++ struct mip_priv *priv = irq_data_get_irq_chip_data(d); ++ ++ irq_domain_free_irqs_parent(domain, virq, nr_irqs); ++ d->hwirq -= priv->msi_offset; ++ ++ spin_lock(&priv->msi_map_lock); ++ ++ bitmap_release_region(priv->msi_map, d->hwirq, ilog2(nr_irqs)); ++ ++ spin_unlock(&priv->msi_map_lock); ++} ++ ++#if 0 ++static int mip_irq_domain_activate(struct irq_domain *domain, ++ struct irq_data *d, bool reserve) ++{ ++ struct mip_priv *priv = irq_data_get_irq_chip_data(d); ++ unsigned long flags; ++ unsigned int irq = d->hwirq; ++ void *__iomem reg = priv->base + ++ ((irq < 32) ? MIP_INT_MASKL_HOST : MIP_INT_MASKH_HOST); ++ u32 val; ++ ++ spin_lock_irqsave(&priv->hw_lock, flags); ++ val = readl(reg); ++ val &= ~(1 << (irq % 32)); // Clear the mask ++ writel(val, reg); ++ spin_unlock_irqrestore(&priv->hw_lock, flags); ++ return 0; ++} ++ ++static void mip_irq_domain_deactivate(struct irq_domain *domain, ++ struct irq_data *d) ++{ ++ struct mip_priv *priv = irq_data_get_irq_chip_data(d); ++ unsigned long flags; ++ unsigned int irq = d->hwirq - priv->msi_base; ++ void *__iomem reg = priv->base + ++ ((irq < 32) ? MIP_INT_MASKL_HOST : MIP_INT_MASKH_HOST); ++ u32 val; ++ ++ spin_lock_irqsave(&priv->hw_lock, flags); ++ val = readl(reg); ++ val |= (1 << (irq % 32)); // Mask it out ++ writel(val, reg); ++ spin_unlock_irqrestore(&priv->hw_lock, flags); ++} ++#endif ++ ++static const struct irq_domain_ops mip_irq_domain_ops = { ++ .alloc = mip_irq_domain_alloc, ++ .free = mip_irq_domain_free, ++ //.activate = mip_irq_domain_activate, ++ //.deactivate = mip_irq_domain_deactivate, ++}; ++ ++static int mip_init_domains(struct mip_priv *priv, ++ struct device_node *node) ++{ ++ struct irq_domain *middle_domain, *msi_domain, *gic_domain; ++ struct device_node *gic_node; ++ ++ gic_node = of_irq_find_parent(node); ++ if (!gic_node) { ++ pr_err("Failed to find the GIC node\n"); ++ return -ENODEV; ++ } ++ ++ gic_domain = irq_find_host(gic_node); ++ if (!gic_domain) { ++ pr_err("Failed to find the GIC domain\n"); ++ return -ENXIO; ++ } ++ ++ middle_domain = irq_domain_add_hierarchy(gic_domain, 0, 0, NULL, ++ &mip_irq_domain_ops, ++ priv); ++ if (!middle_domain) { ++ pr_err("Failed to create the MIP middle domain\n"); ++ return -ENOMEM; ++ } ++ ++ msi_domain = pci_msi_create_irq_domain(of_node_to_fwnode(node), ++ &mip_msi_domain_info, ++ middle_domain); ++ if (!msi_domain) { ++ pr_err("Failed to create MSI domain\n"); ++ irq_domain_remove(middle_domain); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static int __init mip_of_msi_init(struct device_node *node, ++ struct device_node *parent) ++{ ++ struct mip_priv *priv; ++ struct resource res; ++ int ret; ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ spin_lock_init(&priv->msi_map_lock); ++ spin_lock_init(&priv->hw_lock); ++ ++ ret = of_address_to_resource(node, 0, &res); ++ if (ret) { ++ pr_err("Failed to allocate resource\n"); ++ goto err_priv; ++ } ++ ++ if (of_property_read_u32(node, "brcm,msi-base-spi", &priv->msi_base)) { ++ pr_err("Unable to parse MSI base\n"); ++ ret = -EINVAL; ++ goto err_priv; ++ } ++ ++ if (of_property_read_u32(node, "brcm,msi-num-spis", &priv->num_msis)) { ++ pr_err("Unable to parse MSI numbers\n"); ++ ret = -EINVAL; ++ goto err_priv; ++ } ++ ++ if (of_property_read_u32(node, "brcm,msi-offset", &priv->msi_offset)) ++ priv->msi_offset = 0; ++ ++ if (of_property_read_u64(node, "brcm,msi-pci-addr", &priv->msg_addr)) { ++ pr_err("Unable to parse MSI address\n"); ++ ret = -EINVAL; ++ goto err_priv; ++ } ++ ++ priv->base = ioremap(res.start, resource_size(&res)); ++ if (!priv->base) { ++ pr_err("Failed to ioremap regs\n"); ++ ret = -ENOMEM; ++ goto err_priv; ++ } ++ ++ priv->msi_map = kcalloc(BITS_TO_LONGS(priv->num_msis), ++ sizeof(*priv->msi_map), ++ GFP_KERNEL); ++ if (!priv->msi_map) { ++ ret = -ENOMEM; ++ goto err_base; ++ } ++ ++ pr_debug("Registering %d msixs, starting at %d\n", ++ priv->num_msis, priv->msi_base); ++ ++ /* ++ * Begin with all MSI-Xs masked in for the host, masked out for the ++ * VPU, and edge-triggered. ++ */ ++ writel(0, priv->base + MIP_INT_MASKL_HOST); ++ writel(0, priv->base + MIP_INT_MASKH_HOST); ++ writel(~0, priv->base + MIP_INT_MASKL_VPU); ++ writel(~0, priv->base + MIP_INT_MASKH_VPU); ++ writel(~0, priv->base + MIP_INT_CFGL_HOST); ++ writel(~0, priv->base + MIP_INT_CFGH_HOST); ++ ++ ret = mip_init_domains(priv, node); ++ if (ret) { ++ pr_err("Failed to allocate msi_map\n"); ++ goto err_map; ++ } ++ ++ return 0; ++ ++err_map: ++ kfree(priv->msi_map); ++ ++err_base: ++ iounmap(priv->base); ++ ++err_priv: ++ kfree(priv); ++ ++ pr_err("%s: failed - err %d\n", __func__, ret); ++ ++ return ret; ++} ++IRQCHIP_DECLARE(bcm_mip, "brcm,bcm2712-mip-intc", mip_of_msi_init); diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c -index a1e004af23e7..0e6c0811dc1e 100644 +index e94e2882286c..8e995ade76d6 100644 --- a/drivers/irqchip/irq-bcm2835.c +++ b/drivers/irqchip/irq-bcm2835.c @@ -43,9 +43,12 @@ @@ -70253,807 +101361,6355 @@ + if (hwirq >= 32) + return hwirq - 32; + -+ return hwirq + 64; ++ return hwirq + 64; ++} ++ + static void armctrl_mask_irq(struct irq_data *d) + { +- writel_relaxed(HWIRQ_BIT(d->hwirq), intc.disableHWIRQ_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.disableHWIRQ_BANK(d->hwirq)); + } + + static void armctrl_unmask_irq(struct irq_data *d) + { +- writel_relaxed(HWIRQ_BIT(d->hwirq), intc.enableHWIRQ_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.enableHWIRQ_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, +@@ -135,15 +201,16 @@ static int __init armctrl_of_init(struct device_node *node, + 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); + +@@ -174,6 +241,8 @@ static int __init armctrl_of_init(struct device_node *node, + 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); + +@@ -186,6 +255,27 @@ static int __init armctrl_of_init(struct device_node *node, + 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_irqsb; 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; + } + +@@ -253,7 +343,8 @@ static void bcm2836_chained_handle_irq(struct irq_desc *desc) + { + u32 hwirq; + +- while ((hwirq = get_next_armctrl_hwirq()) != ~0) ++ hwirq = get_next_armctrl_hwirq(); ++ if (hwirq != ~0) + generic_handle_domain_irq(intc.domain, hwirq); + } + +diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c +index e5f1059b989f..42660f14aaf6 100644 +--- a/drivers/irqchip/irq-bcm2836.c ++++ b/drivers/irqchip/irq-bcm2836.c +@@ -22,6 +22,9 @@ struct bcm2836_arm_irqchip_intc { + + 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) +@@ -84,6 +87,27 @@ static void bcm2836_arm_irqchip_unmask_gpu_irq(struct irq_data *d) + { + } + ++#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, +@@ -128,7 +152,7 @@ static int bcm2836_map(struct irq_domain *d, unsigned int irq, + 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; + } +@@ -320,6 +344,8 @@ static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node, + 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 --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c +index 2b0b3175cea0..3bc73c71114e 100644 +--- a/drivers/irqchip/irq-brcmstb-l2.c ++++ b/drivers/irqchip/irq-brcmstb-l2.c +@@ -51,6 +51,16 @@ static const struct brcmstb_intc_init_params l2_lvl_intc_init = { + .cpu_mask_clear = 0x0C + }; + ++/* Register offsets in the 2711 L2 level interrupt controller */ ++static const struct brcmstb_intc_init_params l2_2711_lvl_intc_init = { ++ .handler = handle_level_irq, ++ .cpu_status = 0x00, ++ .cpu_clear = 0x08, ++ .cpu_mask_status = 0x0c, ++ .cpu_mask_set = 0x10, ++ .cpu_mask_clear = 0x14 ++}; ++ + /* L2 intc private data structure */ + struct brcmstb_l2_intc_data { + struct irq_domain *domain; +@@ -288,11 +298,18 @@ static int __init brcmstb_l2_lvl_intc_of_init(struct device_node *np, + return brcmstb_l2_intc_of_init(np, parent, &l2_lvl_intc_init); + } + ++static int __init brcmstb_l2_2711_lvl_intc_of_init(struct device_node *np, ++ struct device_node *parent) ++{ ++ return brcmstb_l2_intc_of_init(np, parent, &l2_2711_lvl_intc_init); ++} ++ + IRQCHIP_PLATFORM_DRIVER_BEGIN(brcmstb_l2) + IRQCHIP_MATCH("brcm,l2-intc", brcmstb_l2_edge_intc_of_init) + IRQCHIP_MATCH("brcm,hif-spi-l2-intc", brcmstb_l2_edge_intc_of_init) + IRQCHIP_MATCH("brcm,upg-aux-aon-l2-intc", brcmstb_l2_edge_intc_of_init) + IRQCHIP_MATCH("brcm,bcm7271-l2-intc", brcmstb_l2_lvl_intc_of_init) ++IRQCHIP_MATCH("brcm,bcm2711-l2-intc", brcmstb_l2_2711_lvl_intc_of_init) + IRQCHIP_PLATFORM_DRIVER_END(brcmstb_l2) + MODULE_DESCRIPTION("Broadcom STB generic L2 interrupt controller"); + MODULE_LICENSE("GPL v2"); +diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c +index 7bfe40a6bfdd..def1bc25194f 100644 +--- a/drivers/leds/leds-gpio.c ++++ b/drivers/leds/leds-gpio.c +@@ -48,8 +48,15 @@ static void gpio_led_set(struct led_classdev *led_cdev, + 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); +@@ -63,6 +70,13 @@ static int gpio_led_set_blocking(struct led_classdev *led_cdev, + 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) + { +@@ -92,6 +106,7 @@ static int create_gpio_led(const struct gpio_led *template, + 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 --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c +index 2b3bf1353b70..4e3936a39d0e 100644 +--- a/drivers/leds/leds-pwm.c ++++ b/drivers/leds/leds-pwm.c +@@ -54,7 +54,7 @@ static int led_pwm_set(struct led_classdev *led_cdev, + + led_dat->pwmstate.duty_cycle = duty; + led_dat->pwmstate.enabled = true; +- return pwm_apply_state(led_dat->pwm, &led_dat->pwmstate); ++ return pwm_apply_might_sleep(led_dat->pwm, &led_dat->pwmstate); + } + + __attribute__((nonnull)) +diff --git a/drivers/leds/rgb/leds-pwm-multicolor.c b/drivers/leds/rgb/leds-pwm-multicolor.c +index 46cd062b8b24..e1a81e0109e8 100644 +--- a/drivers/leds/rgb/leds-pwm-multicolor.c ++++ b/drivers/leds/rgb/leds-pwm-multicolor.c +@@ -51,8 +51,8 @@ static int led_pwm_mc_set(struct led_classdev *cdev, + + priv->ledsi.state.duty_cycle = duty; + priv->ledsi.state.enabled = duty > 0; +- ret = pwm_apply_state(priv->ledsi.pwm, +- &priv->ledsi.state); ++ ret = pwm_apply_might_sleep(priv->ledsi.pwm, ++ &priv->ledsi.state); + if (ret) + break; + } +diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig +index 2a57328eca20..6100c9690734 100644 +--- a/drivers/leds/trigger/Kconfig ++++ b/drivers/leds/trigger/Kconfig +@@ -116,6 +116,13 @@ config LEDS_TRIGGER_CAMERA + 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 +@@ -155,4 +162,15 @@ config LEDS_TRIGGER_TTY + + When build as a module this driver will be called ledtrig-tty. + ++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 --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile +index 25c4db97cdd4..8bcb57669549 100644 +--- a/drivers/leds/trigger/Makefile ++++ b/drivers/leds/trigger/Makefile +@@ -11,8 +11,10 @@ obj-$(CONFIG_LEDS_TRIGGER_ACTIVITY) += ledtrig-activity.o + 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_TTY) += ledtrig-tty.o ++obj-$(CONFIG_LEDS_TRIGGER_ACTPWR) += ledtrig-actpwr.o +diff --git a/drivers/leds/trigger/ledtrig-actpwr.c b/drivers/leds/trigger/ledtrig-actpwr.c +new file mode 100644 +index 000000000000..1a52107ceb03 +--- /dev/null ++++ b/drivers/leds/trigger/ledtrig-actpwr.c +@@ -0,0 +1,190 @@ ++// 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_ledsTRIG_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_sourcesTRIG_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_ledstrig->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_ledsi; ++ struct led_classdev *cdev = &vled->cdev; ++ const struct actpwr_trig_src *src = &actpwr_trig_sourcesi; ++ ++ 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_ledsi.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_ledsi.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 --git a/drivers/leds/trigger/ledtrig-input.c b/drivers/leds/trigger/ledtrig-input.c +new file mode 100644 +index 000000000000..8a974a355656 +--- /dev/null ++++ b/drivers/leds/trigger/ledtrig-input.c +@@ -0,0 +1,55 @@ ++/* ++ * 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 --git a/drivers/mailbox/bcm2835-mailbox.c b/drivers/mailbox/bcm2835-mailbox.c +index fbfd0202047c..7e0d62fbc83e 100644 +--- a/drivers/mailbox/bcm2835-mailbox.c ++++ b/drivers/mailbox/bcm2835-mailbox.c +@@ -45,12 +45,15 @@ + #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; +@@ -144,7 +147,7 @@ static int bcm2835_mbox_probe(struct platform_device *pdev) + 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", +@@ -192,7 +195,18 @@ static struct platform_driver bcm2835_mbox_driver = { + }, + .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 --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c +index cf6727d9c81f..9bd4cfefa24d 100644 +--- a/drivers/media/common/videobuf2/videobuf2-core.c ++++ b/drivers/media/common/videobuf2/videobuf2-core.c +@@ -2229,12 +2229,12 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off, + 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) { +@@ -2286,6 +2286,21 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type, + 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 --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig +index 53b443be5a59..ba7bdf78e268 100644 +--- a/drivers/media/i2c/Kconfig ++++ b/drivers/media/i2c/Kconfig +@@ -50,6 +50,28 @@ config VIDEO_AR0521 + To compile this driver as a module, choose M here: the + module will be called ar0521. + ++config VIDEO_ARDUCAM_64MP ++ tristate "Arducam 64MP sensor support" ++ depends on I2C && VIDEO_DEV ++ select VIDEO_V4L2_SUBDEV_API ++ help ++ This is a Video4Linux2 sensor driver for the Arducam ++ 64MP camera. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called arducam_64mp. ++ ++config VIDEO_ARDUCAM_PIVARIETY ++ tristate "Arducam Pivariety sensor support" ++ depends on I2C && VIDEO_DEV ++ select VIDEO_V4L2_SUBDEV_API ++ help ++ This is a Video4Linux2 sensor driver for the Arducam ++ Pivariety camera series. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called arducam-pivariety. ++ + config VIDEO_HI556 + tristate "Hynix Hi-556 sensor support" + help +@@ -201,6 +223,43 @@ config VIDEO_IMX415 + To compile this driver as a module, choose M here: the + module will be called imx415. + ++config VIDEO_IMX477 ++ tristate "Sony IMX477 sensor support" ++ depends on I2C && VIDEO_DEV ++ select VIDEO_V4L2_SUBDEV_API ++ select MEDIA_CONTROLLER ++ select V4L2_FWNODE ++ help ++ This is a Video4Linux2 sensor driver for the Sony ++ IMX477 camera. Also supports the Sony IMX378. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called imx477. ++ ++config VIDEO_IMX519 ++ tristate "Arducam IMX519 sensor support" ++ depends on I2C && VIDEO_DEV ++ select VIDEO_V4L2_SUBDEV_API ++ help ++ This is a Video4Linux2 sensor driver for the Arducam ++ IMX519 camera. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called IMX519. ++ ++config VIDEO_IMX708 ++ tristate "Sony IMX708 sensor support" ++ depends on I2C && VIDEO_DEV ++ select MEDIA_CONTROLLER ++ select VIDEO_V4L2_SUBDEV_API ++ select V4L2_FWNODE ++ help ++ This is a Video4Linux2 sensor driver for the Sony ++ IMX708 camera. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called imx708. ++ + config VIDEO_MAX9271_LIB + tristate + +@@ -312,6 +371,16 @@ config VIDEO_OV13B10 + This is a Video4Linux2 sensor driver for the OmniVision + OV13B10 camera. + ++config VIDEO_OV2311 ++ tristate "OmniVision OV2311 sensor support" ++ depends on I2C && VIDEO_DEV ++ help ++ This is a Video4Linux2 sensor-level driver for the OmniVision ++ OV2311 camera. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ov2311. ++ + config VIDEO_OV2640 + tristate "OmniVision OV2640 sensor support" + help +@@ -445,6 +514,20 @@ config VIDEO_OV5695 + To compile this driver as a module, choose M here: the + module will be called ov5695. + ++config VIDEO_OV64A40 ++ tristate "OmniVision OV64A40 sensor support" ++ depends on I2C && VIDEO_DEV ++ select MEDIA_CONTROLLER ++ select VIDEO_V4L2_SUBDEV_API ++ select V4L2_FWNODE ++ select V4L2_CCI_I2C ++ help ++ This is a Video4Linux2 sensor driver for the OmniVision ++ OV64A40 camera. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ov64a40. ++ + config VIDEO_OV6650 + tristate "OmniVision OV6650 sensor support" + help +@@ -621,6 +704,13 @@ endif + menu "Lens drivers" + visible if MEDIA_CAMERA_SUPPORT + ++config VIDEO_AD5398 ++ tristate "AD5398 lens voice coil support" ++ depends on GPIOLIB && I2C && VIDEO_DEV ++ select MEDIA_CONTROLLER ++ help ++ This is a driver for the AD5398 camera lens voice coil. ++ + config VIDEO_AD5820 + tristate "AD5820 lens voice coil support" + depends on GPIOLIB && I2C && VIDEO_DEV +@@ -642,6 +732,19 @@ config VIDEO_AK7375 + capability. This is designed for linear control of + voice coil motors, controlled via I2C serial interface. + ++config VIDEO_BU64754 ++ tristate "BU64754 Motor Driver for Camera Autofocus" ++ depends on I2C && VIDEO_DEV ++ select MEDIA_CONTROLLER ++ select VIDEO_V4L2_SUBDEV_API ++ select V4L2_ASYNC ++ select V4L2_CCI_I2C ++ help ++ This is a driver for the BU64754 Motor Driver for Camera ++ Autofocus. The BU64754GWZ is an actuator driver IC which ++ can be controlled the actuator position precisely using ++ with internal Hall Sensor. ++ + config VIDEO_DW9714 + tristate "DW9714 lens voice coil support" + depends on I2C && VIDEO_DEV +@@ -1206,6 +1309,18 @@ config VIDEO_TW9910 + To compile this driver as a module, choose M here: the + module will be called tw9910. + ++config VIDEO_IRS1125 ++ tristate "Infineon IRS1125 sensor support" ++ depends on I2C && VIDEO_DEV ++ select VIDEO_V4L2_SUBDEV_API ++ 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_VPX3220 + tristate "vpx3220a, vpx3216b & vpx3214c video decoders" + depends on VIDEO_DEV && I2C +diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile +index 80b00d39b48f..40132cf56ad9 100644 +--- a/drivers/media/i2c/Makefile ++++ b/drivers/media/i2c/Makefile +@@ -3,6 +3,7 @@ + msp3400-objs := msp3400-driver.o msp3400-kthreads.o + + obj-$(CONFIG_SDR_MAX2175) += max2175.o ++obj-$(CONFIG_VIDEO_AD5398) += ad5398_vcm.o + obj-$(CONFIG_VIDEO_AD5820) += ad5820.o + obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o + obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o +@@ -19,9 +20,12 @@ obj-$(CONFIG_VIDEO_AK7375) += ak7375.o + obj-$(CONFIG_VIDEO_AK881X) += ak881x.o + obj-$(CONFIG_VIDEO_APTINA_PLL) += aptina-pll.o + obj-$(CONFIG_VIDEO_AR0521) += ar0521.o ++obj-$(CONFIG_VIDEO_ARDUCAM_64MP) += arducam_64mp.o ++obj-$(CONFIG_VIDEO_ARDUCAM_PIVARIETY) += arducam-pivariety.o + obj-$(CONFIG_VIDEO_BT819) += bt819.o + obj-$(CONFIG_VIDEO_BT856) += bt856.o + obj-$(CONFIG_VIDEO_BT866) += bt866.o ++obj-$(CONFIG_VIDEO_BU64754) += bu64754.o + obj-$(CONFIG_VIDEO_CCS) += ccs/ + obj-$(CONFIG_VIDEO_CCS_PLL) += ccs-pll.o + obj-$(CONFIG_VIDEO_CS3308) += cs3308.o +@@ -53,7 +57,11 @@ obj-$(CONFIG_VIDEO_IMX335) += imx335.o + obj-$(CONFIG_VIDEO_IMX355) += imx355.o + obj-$(CONFIG_VIDEO_IMX412) += imx412.o + obj-$(CONFIG_VIDEO_IMX415) += imx415.o ++obj-$(CONFIG_VIDEO_IMX477) += imx477.o ++obj-$(CONFIG_VIDEO_IMX519) += imx519.o ++obj-$(CONFIG_VIDEO_IMX708) += imx708.o + obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o ++obj-$(CONFIG_VIDEO_IRS1125) += irs1125.o + obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o + obj-$(CONFIG_VIDEO_KS0127) += ks0127.o + obj-$(CONFIG_VIDEO_LM3560) += lm3560.o +@@ -77,6 +85,7 @@ obj-$(CONFIG_VIDEO_OV08D10) += ov08d10.o + obj-$(CONFIG_VIDEO_OV08X40) += ov08x40.o + obj-$(CONFIG_VIDEO_OV13858) += ov13858.o + obj-$(CONFIG_VIDEO_OV13B10) += ov13b10.o ++obj-$(CONFIG_VIDEO_OV2311) += ov2311.o + obj-$(CONFIG_VIDEO_OV2640) += ov2640.o + obj-$(CONFIG_VIDEO_OV2659) += ov2659.o + obj-$(CONFIG_VIDEO_OV2680) += ov2680.o +@@ -91,6 +100,7 @@ obj-$(CONFIG_VIDEO_OV5670) += ov5670.o + obj-$(CONFIG_VIDEO_OV5675) += ov5675.o + obj-$(CONFIG_VIDEO_OV5693) += ov5693.o + obj-$(CONFIG_VIDEO_OV5695) += ov5695.o ++obj-$(CONFIG_VIDEO_OV64A40) += ov64a40.o + obj-$(CONFIG_VIDEO_OV6650) += ov6650.o + obj-$(CONFIG_VIDEO_OV7251) += ov7251.o + obj-$(CONFIG_VIDEO_OV7640) += ov7640.o +diff --git a/drivers/media/i2c/ad5398_vcm.c b/drivers/media/i2c/ad5398_vcm.c +new file mode 100644 +index 000000000000..649ff0b9e9c8 +--- /dev/null ++++ b/drivers/media/i2c/ad5398_vcm.c +@@ -0,0 +1,340 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * AD5398 DAC driver for camera voice coil focus. ++ * Copyright (C) 2021 Raspberry Pi (Trading) Ltd. ++ * ++ * Based on AD5820 DAC driver by Nokia and TI. ++ * ++ * This driver uses the regulator framework notification hooks on the ++ * assumption that the VCM and sensor share a regulator. This means the VCM ++ * position will be restored when either the sensor or VCM subdevices are opened ++ * or powered up. The client can therefore choose to ignore the VCM subdevice, ++ * and the lens position will be as previously requested. Without that, there ++ * is a hard requirement to have the VCM subdevice open in order for the VCM ++ * to be powered and at the requested position. ++ */ ++ ++#include <linux/errno.h> ++#include <linux/i2c.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/regulator/consumer.h> ++#include <linux/gpio/consumer.h> ++ ++#include <media/v4l2-ctrls.h> ++#include <media/v4l2-device.h> ++#include <media/v4l2-subdev.h> ++ ++/* Register definitions */ ++#define AD5398_POWER_DOWN BIT(15) ++#define AD5398_DAC_SHIFT 4 ++ ++#define to_ad5398_device(sd) container_of(sd, struct ad5398_device, subdev) ++ ++struct ad5398_device { ++ struct v4l2_subdev subdev; ++ struct ad5398_platform_data *platform_data; ++ struct regulator *vana; ++ struct notifier_block nb; ++ ++ struct v4l2_ctrl_handler ctrls; ++ u32 focus_absolute; ++ ++ bool standby; ++}; ++ ++static int ad5398_write(struct ad5398_device *coil, u16 data) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&coil->subdev); ++ struct i2c_msg msg; ++ __be16 be_data; ++ int r; ++ ++ if (!client->adapter) ++ return -ENODEV; ++ ++ be_data = cpu_to_be16(data); ++ msg.addr = client->addr; ++ msg.flags = 0; ++ msg.len = 2; ++ msg.buf = (u8 *)&be_data; ++ ++ r = i2c_transfer(client->adapter, &msg, 1); ++ if (r < 0) { ++ dev_err(&client->dev, "write failed, error %d\n", r); ++ return r; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Calculate status word and write it to the device based on current ++ * values of V4L2 controls. It is assumed that the stored V4L2 control ++ * values are properly limited and rounded. ++ */ ++static int ad5398_update_hw(struct ad5398_device *coil) ++{ ++ u16 status; ++ ++ status = coil->focus_absolute << AD5398_DAC_SHIFT; ++ ++ if (coil->standby) ++ status |= AD5398_POWER_DOWN; ++ ++ return ad5398_write(coil, status); ++} ++ ++/* ++ * Power handling ++ */ ++static int ad5398_power_off(struct ad5398_device *coil) ++{ ++ int ret = 0; ++ ++ coil->standby = true; ++ ret = ad5398_update_hw(coil); ++ ++ return ret; ++} ++ ++static int ad5398_power_on(struct ad5398_device *coil) ++{ ++ int ret; ++ ++ /* Restore the hardware settings. */ ++ coil->standby = false; ++ ret = ad5398_update_hw(coil); ++ if (ret) ++ goto fail; ++ ++ return 0; ++ ++fail: ++ coil->standby = true; ++ ++ return ret; ++} ++ ++/* ++ * V4L2 controls ++ */ ++static int ad5398_set_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct ad5398_device *coil = ++ container_of(ctrl->handler, struct ad5398_device, ctrls); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_FOCUS_ABSOLUTE: ++ coil->focus_absolute = ctrl->val; ++ return ad5398_update_hw(coil); ++ } ++ ++ return 0; ++} ++ ++static const struct v4l2_ctrl_ops ad5398_ctrl_ops = { ++ .s_ctrl = ad5398_set_ctrl, ++}; ++ ++static int ad5398_init_controls(struct ad5398_device *coil) ++{ ++ v4l2_ctrl_handler_init(&coil->ctrls, 1); ++ ++ /* ++ * V4L2_CID_FOCUS_ABSOLUTE ++ * ++ * Minimum current is 0 mA, maximum is 120 mA. Thus, 1 code is ++ * equivalent to 120/1023 = 0.1173 mA. Nevertheless, we do not use mA ++ * for focus position, because it is meaningless for user. Meaningful ++ * would be to use focus distance or even its inverse, but since the ++ * driver doesn't have sufficient knowledge to do the conversion, we ++ * will just use abstract codes here. In any case, smaller value = focus ++ * position farther from camera. The default zero value means focus at ++ * infinity, and also least current consumption. ++ */ ++ v4l2_ctrl_new_std(&coil->ctrls, &ad5398_ctrl_ops, ++ V4L2_CID_FOCUS_ABSOLUTE, 0, 1023, 1, 0); ++ ++ if (coil->ctrls.error) ++ return coil->ctrls.error; ++ ++ coil->focus_absolute = 0; ++ ++ coil->subdev.ctrl_handler = &coil->ctrls; ++ ++ return 0; ++} ++ ++/* ++ * V4L2 subdev operations ++ */ ++static int ad5398_registered(struct v4l2_subdev *subdev) ++{ ++ struct ad5398_device *coil = to_ad5398_device(subdev); ++ ++ return ad5398_init_controls(coil); ++} ++ ++static int ++ad5398_set_power(struct v4l2_subdev *subdev, int on) ++{ ++ struct ad5398_device *coil = to_ad5398_device(subdev); ++ int ret; ++ ++ if (on) ++ ret = regulator_enable(coil->vana); ++ else ++ ret = regulator_disable(coil->vana); ++ ++ return ret; ++} ++ ++static int ad5398_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) ++{ ++ struct ad5398_device *coil = to_ad5398_device(sd); ++ ++ return regulator_enable(coil->vana); ++} ++ ++static int ad5398_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) ++{ ++ struct ad5398_device *coil = to_ad5398_device(sd); ++ ++ return regulator_disable(coil->vana); ++} ++ ++static const struct v4l2_subdev_core_ops ad5398_core_ops = { ++ .s_power = ad5398_set_power, ++}; ++ ++static const struct v4l2_subdev_ops ad5398_ops = { ++ .core = &ad5398_core_ops, ++}; ++ ++static const struct v4l2_subdev_internal_ops ad5398_internal_ops = { ++ .registered = ad5398_registered, ++ .open = ad5398_open, ++ .close = ad5398_close, ++}; ++ ++/* ++ * I2C driver ++ */ ++static int __maybe_unused ad5398_suspend(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *subdev = i2c_get_clientdata(client); ++ struct ad5398_device *coil = to_ad5398_device(subdev); ++ ++ return regulator_enable(coil->vana); ++} ++ ++static int __maybe_unused ad5398_resume(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *subdev = i2c_get_clientdata(client); ++ struct ad5398_device *coil = to_ad5398_device(subdev); ++ ++ return regulator_disable(coil->vana); ++} ++ ++static int ad5398_regulator_notifier(struct notifier_block *nb, ++ unsigned long event, ++ void *ignored) ++{ ++ struct ad5398_device *coil = container_of(nb, struct ad5398_device, nb); ++ ++ if (event == REGULATOR_EVENT_ENABLE) ++ ad5398_power_on(coil); ++ else if (event == REGULATOR_EVENT_PRE_DISABLE) ++ ad5398_power_off(coil); ++ ++ return NOTIFY_OK; ++} ++ ++static int ad5398_probe(struct i2c_client *client) ++{ ++ struct ad5398_device *coil; ++ int ret; ++ ++ coil = devm_kzalloc(&client->dev, sizeof(*coil), GFP_KERNEL); ++ if (!coil) ++ return -ENOMEM; ++ ++ coil->vana = devm_regulator_get(&client->dev, "VANA"); ++ if (IS_ERR(coil->vana)) { ++ ret = PTR_ERR(coil->vana); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&client->dev, "could not get regulator for vana\n"); ++ return ret; ++ } ++ ++ v4l2_i2c_subdev_init(&coil->subdev, client, &ad5398_ops); ++ coil->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ coil->subdev.internal_ops = &ad5398_internal_ops; ++ coil->subdev.entity.function = MEDIA_ENT_F_LENS; ++ strscpy(coil->subdev.name, "ad5398 focus", sizeof(coil->subdev.name)); ++ ++ coil->nb.notifier_call = &ad5398_regulator_notifier; ++ ret = regulator_register_notifier(coil->vana, &coil->nb); ++ if (ret < 0) ++ return ret; ++ ++ ret = media_entity_pads_init(&coil->subdev.entity, 0, NULL); ++ if (ret < 0) ++ goto cleanup2; ++ ++ ret = v4l2_async_register_subdev(&coil->subdev); ++ if (ret < 0) ++ goto cleanup; ++ ++ return ret; ++ ++cleanup: ++ media_entity_cleanup(&coil->subdev.entity); ++cleanup2: ++ regulator_unregister_notifier(coil->vana, &coil->nb); ++ return ret; ++} ++ ++static void ad5398_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *subdev = i2c_get_clientdata(client); ++ struct ad5398_device *coil = to_ad5398_device(subdev); ++ ++ v4l2_async_unregister_subdev(&coil->subdev); ++ v4l2_ctrl_handler_free(&coil->ctrls); ++ media_entity_cleanup(&coil->subdev.entity); ++} ++ ++static const struct i2c_device_id ad5398_id_table = { ++ { "ad5398", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ad5398_id_table); ++ ++static const struct of_device_id ad5398_of_table = { ++ { .compatible = "adi,ad5398" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ad5398_of_table); ++ ++static SIMPLE_DEV_PM_OPS(ad5398_pm, ad5398_suspend, ad5398_resume); ++ ++static struct i2c_driver ad5398_i2c_driver = { ++ .driver = { ++ .name = "ad5398", ++ .pm = &ad5398_pm, ++ .of_match_table = ad5398_of_table, ++ }, ++ .probe = ad5398_probe, ++ .remove = ad5398_remove, ++ .id_table = ad5398_id_table, ++}; ++ ++module_i2c_driver(ad5398_i2c_driver); ++ ++MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com>"); ++MODULE_DESCRIPTION("AD5398 camera lens driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c +index 99ba925e8ec8..413021887f96 100644 +--- a/drivers/media/i2c/adv7180.c ++++ b/drivers/media/i2c/adv7180.c +@@ -188,6 +188,20 @@ + /* Initial number of frames to skip to avoid possible garbage */ + #define ADV7180_NUM_OF_SKIP_FRAMES 2 + ++enum adv7180_link_freq_idx { ++ INTERLACED_IDX, ++ I2P_IDX, ++}; ++ ++static const s64 adv7180_link_freqs = { ++ INTERLACED_IDX = 108000000, ++ I2P_IDX = 216000000, ++}; ++ ++static int dbg_input; ++module_param(dbg_input, int, 0644); ++MODULE_PARM_DESC(dbg_input, "Input number (0-31)"); ++ + struct adv7180_state; + + #define ADV7180_FLAG_RESET_POWERED BIT(0) +@@ -223,6 +237,7 @@ struct adv7180_state { + const struct adv7180_chip_info *chip_info; + enum v4l2_field field; + bool force_bt656_4; ++ struct v4l2_ctrl *link_freq; + }; + #define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \ + struct adv7180_state, \ +@@ -406,10 +421,24 @@ static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input, + return ret; + } + ++static void adv7180_check_input(struct v4l2_subdev *sd) ++{ ++ struct adv7180_state *state = to_state(sd); ++ ++ if (state->input != dbg_input) ++ if (adv7180_s_routing(sd, dbg_input, 0, 0)) ++ /* Failed - reset dbg_input */ ++ dbg_input = state->input; ++} ++ + static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status) + { + struct adv7180_state *state = to_state(sd); +- int ret = mutex_lock_interruptible(&state->mutex); ++ int ret; ++ ++ adv7180_check_input(sd); ++ ++ ret = mutex_lock_interruptible(&state->mutex); + if (ret) + return ret; + +@@ -435,7 +464,11 @@ static int adv7180_program_std(struct adv7180_state *state) + static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std) + { + struct adv7180_state *state = to_state(sd); +- int ret = mutex_lock_interruptible(&state->mutex); ++ int ret; ++ ++ adv7180_check_input(sd); ++ ++ ret = mutex_lock_interruptible(&state->mutex); + + if (ret) + return ret; +@@ -457,6 +490,8 @@ static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) + { + struct adv7180_state *state = to_state(sd); + ++ adv7180_check_input(sd); ++ + *norm = state->curr_norm; + + return 0; +@@ -596,6 +631,9 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl) + + if (ret) + return ret; ++ if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) ++ goto unlock; ++ + val = ctrl->val; + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: +@@ -637,6 +675,7 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl) + ret = -EINVAL; + } + ++unlock: + mutex_unlock(&state->mutex); + return ret; + } +@@ -657,7 +696,7 @@ static const struct v4l2_ctrl_config adv7180_ctrl_fast_switch = { + + static int adv7180_init_controls(struct adv7180_state *state) + { +- v4l2_ctrl_handler_init(&state->ctrl_hdl, 4); ++ v4l2_ctrl_handler_init(&state->ctrl_hdl, 5); + + v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, + V4L2_CID_BRIGHTNESS, ADV7180_BRI_MIN, +@@ -679,6 +718,17 @@ static int adv7180_init_controls(struct adv7180_state *state) + 0, ARRAY_SIZE(test_pattern_menu) - 1, + test_pattern_menu); + ++ if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { ++ state->link_freq = ++ v4l2_ctrl_new_int_menu(&state->ctrl_hdl, ++ &adv7180_ctrl_ops, ++ V4L2_CID_LINK_FREQ, ++ ARRAY_SIZE(adv7180_link_freqs) - 1, ++ 0, adv7180_link_freqs); ++ if (state->link_freq) ++ state->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ } ++ + state->sd.ctrl_handler = &state->ctrl_hdl; + if (state->ctrl_hdl.error) { + int err = state->ctrl_hdl.error; +@@ -699,10 +749,15 @@ static int adv7180_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) + { ++ struct adv7180_state *state = to_state(sd); ++ + if (code->index != 0) + return -EINVAL; + +- code->code = MEDIA_BUS_FMT_UYVY8_2X8; ++ if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) ++ code->code = MEDIA_BUS_FMT_UYVY8_1X16; ++ else ++ code->code = MEDIA_BUS_FMT_UYVY8_2X8; + + return 0; + } +@@ -712,7 +767,10 @@ static int adv7180_mbus_fmt(struct v4l2_subdev *sd, + { + struct adv7180_state *state = to_state(sd); + +- fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; ++ if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) ++ fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; ++ else ++ fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + fmt->width = 720; + fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576; +@@ -803,6 +861,10 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd, + adv7180_set_power(state, false); + adv7180_set_field_mode(state); + adv7180_set_power(state, true); ++ if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) ++ __v4l2_ctrl_s_ctrl(state->link_freq, ++ (state->field == V4L2_FIELD_NONE) ? ++ I2P_IDX : INTERLACED_IDX); + } + } else { + framefmt = v4l2_subdev_get_try_format(sd, sd_state, 0); +@@ -886,6 +948,8 @@ static int adv7180_s_stream(struct v4l2_subdev *sd, int enable) + return 0; + } + ++ adv7180_check_input(sd); ++ + /* Must wait until querystd released the lock */ + ret = mutex_lock_interruptible(&state->mutex); + if (ret) +@@ -1329,6 +1393,7 @@ static const struct adv7180_chip_info adv7282_m_info = { + 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), +@@ -1340,6 +1405,7 @@ static const struct adv7180_chip_info adv7282_m_info = { + static int init_device(struct adv7180_state *state) + { + int ret; ++ int i; + + mutex_lock(&state->mutex); + +@@ -1387,6 +1453,18 @@ static int init_device(struct adv7180_state *state) + 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 --git a/drivers/media/i2c/arducam-pivariety.c b/drivers/media/i2c/arducam-pivariety.c +new file mode 100644 +index 000000000000..6bb9e9c48e5c +--- /dev/null ++++ b/drivers/media/i2c/arducam-pivariety.c +@@ -0,0 +1,1472 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * A V4L2 driver for Arducam Pivariety Cameras ++ * Copyright (C) 2022 Arducam Technology co., Ltd. ++ * ++ * Based on Sony IMX219 camera driver ++ * Copyright (C) 2019, Raspberry Pi (Trading) Ltd ++ * ++ * I2C read and write method is taken from the OV9281 driver ++ * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. ++ */ ++ ++#include <linux/clk.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 <media/v4l2-ctrls.h> ++#include <media/v4l2-device.h> ++#include <media/v4l2-event.h> ++#include <media/v4l2-fwnode.h> ++#include "arducam-pivariety.h" ++ ++static int debug; ++module_param(debug, int, 0644); ++ ++/* regulator supplies */ ++static const char * const pivariety_supply_name = { ++ /* Supplies can be enabled in any order */ ++ "VANA", /* Analog (2.8V) supply */ ++ "VDIG", /* Digital Core (1.8V) supply */ ++ "VDDL", /* IF (1.2V) supply */ ++}; ++ ++/* The supported raw formats. */ ++static const u32 codes = { ++ MEDIA_BUS_FMT_SBGGR8_1X8, ++ MEDIA_BUS_FMT_SGBRG8_1X8, ++ MEDIA_BUS_FMT_SGRBG8_1X8, ++ MEDIA_BUS_FMT_SRGGB8_1X8, ++ MEDIA_BUS_FMT_Y8_1X8, ++ ++ MEDIA_BUS_FMT_SBGGR10_1X10, ++ MEDIA_BUS_FMT_SGBRG10_1X10, ++ MEDIA_BUS_FMT_SGRBG10_1X10, ++ MEDIA_BUS_FMT_SRGGB10_1X10, ++ MEDIA_BUS_FMT_Y10_1X10, ++ ++ MEDIA_BUS_FMT_SBGGR12_1X12, ++ MEDIA_BUS_FMT_SGBRG12_1X12, ++ MEDIA_BUS_FMT_SGRBG12_1X12, ++ MEDIA_BUS_FMT_SRGGB12_1X12, ++ MEDIA_BUS_FMT_Y12_1X12, ++}; ++ ++#define ARDUCAM_NUM_SUPPLIES ARRAY_SIZE(pivariety_supply_name) ++ ++#define ARDUCAM_XCLR_MIN_DELAY_US 10000 ++#define ARDUCAM_XCLR_DELAY_RANGE_US 1000 ++ ++#define MAX_CTRLS 32 ++ ++struct pivariety { ++ struct v4l2_subdev sd; ++ struct media_pad pad; ++ ++ struct v4l2_mbus_config_mipi_csi2 bus; ++ struct clk *xclk; ++ u32 xclk_freq; ++ ++ struct gpio_desc *reset_gpio; ++ struct regulator_bulk_data suppliesARDUCAM_NUM_SUPPLIES; ++ ++ struct arducam_format *supported_formats; ++ int num_supported_formats; ++ int current_format_idx; ++ int current_resolution_idx; ++ int lanes; ++ int bayer_order_volatile; ++ bool wait_until_free; ++ ++ struct v4l2_ctrl_handler ctrl_handler; ++ struct v4l2_ctrl *ctrlsMAX_CTRLS; ++ /* V4L2 Controls */ ++ struct v4l2_ctrl *vflip; ++ struct v4l2_ctrl *hflip; ++ ++ struct v4l2_rect crop; ++ /* ++ * Mutex for serialized access: ++ * Protect sensor module set pad format and start/stop streaming safely. ++ */ ++ struct mutex mutex; ++ ++ /* Streaming on/off */ ++ bool streaming; ++}; ++ ++static inline struct pivariety *to_pivariety(struct v4l2_subdev *_sd) ++{ ++ return container_of(_sd, struct pivariety, sd); ++} ++ ++/* Write registers up to 4 at a time */ ++static int pivariety_write_reg(struct i2c_client *client, u16 reg, u32 val) ++{ ++ unsigned int len = sizeof(u32); ++ u32 buf_i, val_i = 0; ++ u8 buf6; ++ u8 *val_p; ++ __be32 val_be; ++ ++ buf0 = reg >> 8; ++ buf1 = reg & 0xff; ++ ++ val_be = cpu_to_be32(val); ++ val_p = (u8 *)&val_be; ++ buf_i = 2; ++ ++ while (val_i < 4) ++ bufbuf_i++ = val_pval_i++; ++ ++ if (i2c_master_send(client, buf, len + 2) != len + 2) ++ return -EIO; ++ ++ return 0; ++} ++ ++/* Read registers up to 4 at a time */ ++static int pivariety_read_reg(struct i2c_client *client, u16 reg, u32 *val) ++{ ++ struct i2c_msg msgs2; ++ unsigned int len = sizeof(u32); ++ u8 *data_be_p; ++ __be32 data_be = 0; ++ __be16 reg_addr_be = cpu_to_be16(reg); ++ int ret; ++ ++ data_be_p = (u8 *)&data_be; ++ /* Write register address */ ++ msgs0.addr = client->addr; ++ msgs0.flags = 0; ++ msgs0.len = 2; ++ msgs0.buf = (u8 *)®_addr_be; ++ ++ /* Read data from register */ ++ msgs1.addr = client->addr; ++ msgs1.flags = I2C_M_RD; ++ msgs1.len = len; ++ msgs1.buf = data_be_p; ++ ++ 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 ++pivariety_read(struct pivariety *pivariety, u16 addr, u32 *value) ++{ ++ struct v4l2_subdev *sd = &pivariety->sd; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret, count = 0; ++ ++ while (count++ < I2C_READ_RETRY_COUNT) { ++ ret = pivariety_read_reg(client, addr, value); ++ if (!ret) { ++ v4l2_dbg(2, debug, sd, "%s: 0x%02x 0x%04x\n", ++ __func__, addr, *value); ++ return ret; ++ } ++ } ++ ++ v4l2_err(sd, "%s: Reading register 0x%02x failed\n", ++ __func__, addr); ++ ++ return ret; ++} ++ ++static int pivariety_write(struct pivariety *pivariety, u16 addr, u32 value) ++{ ++ struct v4l2_subdev *sd = &pivariety->sd; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret, count = 0; ++ ++ while (count++ < I2C_WRITE_RETRY_COUNT) { ++ ret = pivariety_write_reg(client, addr, value); ++ if (!ret) ++ return ret; ++ } ++ ++ v4l2_err(sd, "%s: Write 0x%04x to register 0x%02x failed\n", ++ __func__, value, addr); ++ ++ return ret; ++} ++ ++static int wait_for_free(struct pivariety *pivariety, int interval) ++{ ++ u32 value; ++ u32 count = 0; ++ ++ while (count++ < (1000 / interval)) { ++ int ret = pivariety_read(pivariety, SYSTEM_IDLE_REG, &value); ++ ++ if (!ret && !value) ++ break; ++ msleep(interval); ++ } ++ ++ v4l2_dbg(2, debug, &pivariety->sd, "%s: End wait, Count: %d.\n", ++ __func__, count); ++ ++ return 0; ++} ++ ++static int is_raw(int pixformat) ++{ ++ return pixformat >= 0x28 && pixformat <= 0x2D; ++} ++ ++static u32 bayer_to_mbus_code(int data_type, int bayer_order) ++{ ++ const u32 depth8 = { ++ MEDIA_BUS_FMT_SBGGR8_1X8, ++ MEDIA_BUS_FMT_SGBRG8_1X8, ++ MEDIA_BUS_FMT_SGRBG8_1X8, ++ MEDIA_BUS_FMT_SRGGB8_1X8, ++ MEDIA_BUS_FMT_Y8_1X8, ++ }; ++ ++ const u32 depth10 = { ++ MEDIA_BUS_FMT_SBGGR10_1X10, ++ MEDIA_BUS_FMT_SGBRG10_1X10, ++ MEDIA_BUS_FMT_SGRBG10_1X10, ++ MEDIA_BUS_FMT_SRGGB10_1X10, ++ MEDIA_BUS_FMT_Y10_1X10, ++ }; ++ ++ const u32 depth12 = { ++ MEDIA_BUS_FMT_SBGGR12_1X12, ++ MEDIA_BUS_FMT_SGBRG12_1X12, ++ MEDIA_BUS_FMT_SGRBG12_1X12, ++ MEDIA_BUS_FMT_SRGGB12_1X12, ++ MEDIA_BUS_FMT_Y12_1X12, ++ }; ++ ++ if (bayer_order < 0 || bayer_order > 4) ++ return 0; ++ ++ switch (data_type) { ++ case IMAGE_DT_RAW8: ++ return depth8bayer_order; ++ case IMAGE_DT_RAW10: ++ return depth10bayer_order; ++ case IMAGE_DT_RAW12: ++ return depth12bayer_order; ++ } ++ ++ return 0; ++} ++ ++static u32 yuv422_to_mbus_code(int data_type, int order) ++{ ++ const u32 depth8 = { ++ MEDIA_BUS_FMT_YUYV8_1X16, ++ MEDIA_BUS_FMT_YVYU8_1X16, ++ MEDIA_BUS_FMT_UYVY8_1X16, ++ MEDIA_BUS_FMT_VYUY8_1X16, ++ }; ++ ++ const u32 depth10 = { ++ MEDIA_BUS_FMT_YUYV10_1X20, ++ MEDIA_BUS_FMT_YVYU10_1X20, ++ MEDIA_BUS_FMT_UYVY10_1X20, ++ MEDIA_BUS_FMT_VYUY10_1X20, ++ }; ++ ++ if (order < 0 || order > 3) ++ return 0; ++ ++ switch (data_type) { ++ case IMAGE_DT_YUV422_8: ++ return depth8order; ++ case IMAGE_DT_YUV422_10: ++ return depth10order; ++ } ++ ++ return 0; ++} ++ ++static u32 data_type_to_mbus_code(int data_type, int bayer_order) ++{ ++ if (is_raw(data_type)) ++ return bayer_to_mbus_code(data_type, bayer_order); ++ ++ switch (data_type) { ++ case IMAGE_DT_YUV422_8: ++ case IMAGE_DT_YUV422_10: ++ return yuv422_to_mbus_code(data_type, bayer_order); ++ case IMAGE_DT_RGB565: ++ return MEDIA_BUS_FMT_RGB565_2X8_LE; ++ case IMAGE_DT_RGB888: ++ return MEDIA_BUS_FMT_RGB888_1X24; ++ } ++ ++ return 0; ++} ++ ++/* Get bayer order based on flip setting. */ ++static u32 pivariety_get_format_code(struct pivariety *pivariety, ++ struct arducam_format *format) ++{ ++ unsigned int order, origin_order; ++ ++ lockdep_assert_held(&pivariety->mutex); ++ ++ /* ++ * Only the bayer format needs to transform the format. ++ */ ++ if (!is_raw(format->data_type) || ++ !pivariety->bayer_order_volatile || ++ format->bayer_order == BAYER_ORDER_GRAY) ++ return data_type_to_mbus_code(format->data_type, ++ format->bayer_order); ++ ++ order = format->bayer_order; ++ ++ origin_order = order; ++ ++ order = (pivariety->hflip && pivariety->hflip->val ? order ^ 1 : order); ++ order = (pivariety->vflip && pivariety->vflip->val ? order ^ 2 : order); ++ ++ v4l2_dbg(1, debug, &pivariety->sd, "%s: before: %d, after: %d.\n", ++ __func__, origin_order, order); ++ ++ return data_type_to_mbus_code(format->data_type, order); ++} ++ ++/* Power/clock management functions */ ++static int pivariety_power_on(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct pivariety *pivariety = to_pivariety(sd); ++ int ret; ++ ++ ret = regulator_bulk_enable(ARDUCAM_NUM_SUPPLIES, ++ pivariety->supplies); ++ if (ret) { ++ dev_err(dev, "%s: failed to enable regulators\n", ++ __func__); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(pivariety->xclk); ++ if (ret) { ++ dev_err(dev, "%s: failed to enable clock\n", ++ __func__); ++ goto reg_off; ++ } ++ ++ gpiod_set_value_cansleep(pivariety->reset_gpio, 1); ++ usleep_range(ARDUCAM_XCLR_MIN_DELAY_US, ++ ARDUCAM_XCLR_MIN_DELAY_US + ARDUCAM_XCLR_DELAY_RANGE_US); ++ ++ return 0; ++ ++reg_off: ++ regulator_bulk_disable(ARDUCAM_NUM_SUPPLIES, pivariety->supplies); ++ ++ return ret; ++} ++ ++static int pivariety_power_off(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct pivariety *pivariety = to_pivariety(sd); ++ ++ gpiod_set_value_cansleep(pivariety->reset_gpio, 0); ++ regulator_bulk_disable(ARDUCAM_NUM_SUPPLIES, pivariety->supplies); ++ clk_disable_unprepare(pivariety->xclk); ++ ++ return 0; ++} ++ ++static int pivariety_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) ++{ ++ struct pivariety *pivariety = to_pivariety(sd); ++ struct v4l2_mbus_framefmt *try_fmt = ++ v4l2_subdev_get_try_format(sd, fh->state, 0); ++ struct arducam_format *def_fmt = &pivariety->supported_formats0; ++ ++ /* Initialize try_fmt */ ++ try_fmt->width = def_fmt->resolution_set->width; ++ try_fmt->height = def_fmt->resolution_set->height; ++ try_fmt->code = def_fmt->mbus_code; ++ try_fmt->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int pivariety_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ int ret, i; ++ struct pivariety *pivariety = ++ container_of(ctrl->handler, struct pivariety, ++ ctrl_handler); ++ struct arducam_format *supported_fmts = pivariety->supported_formats; ++ int num_supported_formats = pivariety->num_supported_formats; ++ ++ v4l2_dbg(3, debug, &pivariety->sd, "%s: cid = (0x%X), value = (%d).\n", ++ __func__, ctrl->id, ctrl->val); ++ ++ ret = pivariety_write(pivariety, CTRL_ID_REG, ctrl->id); ++ ret += pivariety_write(pivariety, CTRL_VALUE_REG, ctrl->val); ++ if (ret < 0) ++ return -EINVAL; ++ ++ /* When flip is set, modify all bayer formats */ ++ if (ctrl->id == V4L2_CID_VFLIP || ctrl->id == V4L2_CID_HFLIP) { ++ for (i = 0; i < num_supported_formats; i++) { ++ supported_fmtsi.mbus_code = ++ pivariety_get_format_code(pivariety, ++ &supported_fmtsi); ++ } ++ } ++ ++ /* ++ * When starting streaming, controls are set in batches, ++ * and the short interval will cause some controls to be unsuccessfully ++ * set. ++ */ ++ if (pivariety->wait_until_free) ++ wait_for_free(pivariety, 1); ++ else ++ usleep_range(200, 210); ++ ++ return 0; ++} ++ ++static const struct v4l2_ctrl_ops pivariety_ctrl_ops = { ++ .s_ctrl = pivariety_s_ctrl, ++}; ++ ++static int pivariety_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ struct pivariety *pivariety = to_pivariety(sd); ++ struct arducam_format *supported_formats = pivariety->supported_formats; ++ int num_supported_formats = pivariety->num_supported_formats; ++ ++ v4l2_dbg(1, debug, sd, "%s: index = (%d)\n", __func__, code->index); ++ ++ if (code->index >= num_supported_formats) ++ return -EINVAL; ++ ++ code->code = supported_formatscode->index.mbus_code; ++ ++ return 0; ++} ++ ++static int pivariety_enum_framesizes(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ int i; ++ struct pivariety *pivariety = to_pivariety(sd); ++ struct arducam_format *supported_formats = pivariety->supported_formats; ++ int num_supported_formats = pivariety->num_supported_formats; ++ struct arducam_format *format; ++ struct arducam_resolution *resolution; ++ ++ v4l2_dbg(1, debug, sd, "%s: code = (0x%X), index = (%d)\n", ++ __func__, fse->code, fse->index); ++ ++ for (i = 0; i < num_supported_formats; i++) { ++ format = &supported_formatsi; ++ if (fse->code == format->mbus_code) { ++ if (fse->index >= format->num_resolution_set) ++ return -EINVAL; ++ ++ resolution = &format->resolution_setfse->index; ++ fse->min_width = resolution->width; ++ fse->max_width = resolution->width; ++ fse->min_height = resolution->height; ++ fse->max_height = resolution->height; ++ ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++static int pivariety_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_format *format) ++{ ++ struct pivariety *pivariety = to_pivariety(sd); ++ struct arducam_format *current_format; ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int cur_res_idx; ++ ++ if (format->pad != 0) ++ return -EINVAL; ++ ++ mutex_lock(&pivariety->mutex); ++ ++ current_format = ++ &pivariety->supported_formatspivariety->current_format_idx; ++ cur_res_idx = pivariety->current_resolution_idx; ++ format->format.width = ++ current_format->resolution_setcur_res_idx.width; ++ format->format.height = ++ current_format->resolution_setcur_res_idx.height; ++ format->format.code = current_format->mbus_code; ++ format->format.field = V4L2_FIELD_NONE; ++ fmt->colorspace = V4L2_COLORSPACE_RAW; ++ 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); ++ ++ v4l2_dbg(1, debug, sd, "%s: width: (%d) height: (%d) code: (0x%X)\n", ++ __func__, format->format.width, format->format.height, ++ format->format.code); ++ ++ mutex_unlock(&pivariety->mutex); ++ return 0; ++} ++ ++static int pivariety_get_fmt_idx_by_code(struct pivariety *pivariety, ++ u32 mbus_code) ++{ ++ int i; ++ u32 data_type; ++ struct arducam_format *formats = pivariety->supported_formats; ++ ++ for (i = 0; i < pivariety->num_supported_formats; i++) { ++ if (formatsi.mbus_code == mbus_code) ++ return i; ++ } ++ ++ /* ++ * If the specified format is not found in the list of supported ++ * formats, try to find a format of the same data type. ++ */ ++ for (i = 0; i < ARRAY_SIZE(codes); i++) ++ if (codesi == mbus_code) ++ break; ++ ++ if (i >= ARRAY_SIZE(codes)) ++ return -EINVAL; ++ ++ data_type = i / 5 + IMAGE_DT_RAW8; ++ ++ for (i = 0; i < pivariety->num_supported_formats; i++) { ++ if (formatsi.data_type == data_type) ++ return i; ++ } ++ ++ return -EINVAL; ++} ++ ++static struct v4l2_ctrl *get_control(struct pivariety *pivariety, ++ u32 id) ++{ ++ int index = 0; ++ ++ while (index < MAX_CTRLS && pivariety->ctrlsindex) { ++ if (pivariety->ctrlsindex->id == id) ++ return pivariety->ctrlsindex; ++ index++; ++ } ++ ++ return NULL; ++} ++ ++static int update_control(struct pivariety *pivariety, u32 id) ++{ ++ struct v4l2_subdev *sd = &pivariety->sd; ++ struct v4l2_ctrl *ctrl; ++ u32 min, max, step, def, id2; ++ int ret = 0; ++ ++ pivariety_write(pivariety, CTRL_ID_REG, id); ++ pivariety_read(pivariety, CTRL_ID_REG, &id2); ++ ++ v4l2_dbg(1, debug, sd, "%s: Write ID: 0x%08X Read ID: 0x%08X\n", ++ __func__, id, id2); ++ ++ pivariety_write(pivariety, CTRL_VALUE_REG, 0); ++ wait_for_free(pivariety, 1); ++ ++ ret += pivariety_read(pivariety, CTRL_MAX_REG, &max); ++ ret += pivariety_read(pivariety, CTRL_MIN_REG, &min); ++ ret += pivariety_read(pivariety, CTRL_DEF_REG, &def); ++ ret += pivariety_read(pivariety, CTRL_STEP_REG, &step); ++ ++ if (ret < 0) ++ goto err; ++ ++ if (id == NO_DATA_AVAILABLE || max == NO_DATA_AVAILABLE || ++ min == NO_DATA_AVAILABLE || def == NO_DATA_AVAILABLE || ++ step == NO_DATA_AVAILABLE) ++ goto err; ++ ++ v4l2_dbg(1, debug, sd, "%s: min: %d, max: %d, step: %d, def: %d\n", ++ __func__, min, max, step, def); ++ ++ ctrl = get_control(pivariety, id); ++ return __v4l2_ctrl_modify_range(ctrl, min, max, step, def); ++ ++err: ++ return -EINVAL; ++} ++ ++static int update_controls(struct pivariety *pivariety) ++{ ++ int ret = 0; ++ int index = 0; ++ ++ wait_for_free(pivariety, 5); ++ ++ while (index < MAX_CTRLS && pivariety->ctrlsindex) { ++ ret += update_control(pivariety, pivariety->ctrlsindex->id); ++ index++; ++ } ++ ++ return ret; ++} ++ ++static int pivariety_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_format *format) ++{ ++ int i, j; ++ struct pivariety *pivariety = to_pivariety(sd); ++ struct arducam_format *supported_formats = pivariety->supported_formats; ++ ++ if (format->pad != 0) ++ return -EINVAL; ++ ++ mutex_lock(&pivariety->mutex); ++ ++ format->format.colorspace = V4L2_COLORSPACE_RAW; ++ format->format.field = V4L2_FIELD_NONE; ++ ++ v4l2_dbg(1, debug, sd, "%s: code: 0x%X, width: %d, height: %d\n", ++ __func__, format->format.code, format->format.width, ++ format->format.height); ++ ++ i = pivariety_get_fmt_idx_by_code(pivariety, format->format.code); ++ if (i < 0) ++ i = 0; ++ ++ format->format.code = supported_formatsi.mbus_code; ++ ++ for (j = 0; j < supported_formatsi.num_resolution_set; j++) { ++ if (supported_formatsi.resolution_setj.width == ++ format->format.width && ++ supported_formatsi.resolution_setj.height == ++ format->format.height) { ++ v4l2_dbg(1, debug, sd, ++ "%s: format match.\n", __func__); ++ v4l2_dbg(1, debug, sd, ++ "%s: set format to device: %d %d.\n", ++ __func__, supported_formatsi.index, j); ++ ++ pivariety_write(pivariety, PIXFORMAT_INDEX_REG, ++ supported_formatsi.index); ++ pivariety_write(pivariety, RESOLUTION_INDEX_REG, j); ++ ++ pivariety->current_format_idx = i; ++ pivariety->current_resolution_idx = j; ++ ++ update_controls(pivariety); ++ ++ goto unlock; ++ } ++ } ++ ++ format->format.width = supported_formatsi.resolution_set0.width; ++ format->format.height = supported_formatsi.resolution_set0.height; ++ ++ pivariety_write(pivariety, PIXFORMAT_INDEX_REG, ++ supported_formatsi.index); ++ pivariety_write(pivariety, RESOLUTION_INDEX_REG, 0); ++ ++ pivariety->current_format_idx = i; ++ pivariety->current_resolution_idx = 0; ++ update_controls(pivariety); ++ ++unlock: ++ ++ mutex_unlock(&pivariety->mutex); ++ ++ return 0; ++} ++ ++/* Start streaming */ ++static int pivariety_start_streaming(struct pivariety *pivariety) ++{ ++ int ret; ++ ++ /* set stream on register */ ++ ret = pivariety_write(pivariety, MODE_SELECT_REG, ++ ARDUCAM_MODE_STREAMING); ++ ++ if (ret) ++ return ret; ++ ++ wait_for_free(pivariety, 2); ++ ++ /* ++ * When starting streaming, controls are set in batches, ++ * and the short interval will cause some controls to be unsuccessfully ++ * set. ++ */ ++ pivariety->wait_until_free = true; ++ /* Apply customized values from user */ ++ ret = __v4l2_ctrl_handler_setup(pivariety->sd.ctrl_handler); ++ ++ pivariety->wait_until_free = false; ++ if (ret) ++ return ret; ++ ++ wait_for_free(pivariety, 2); ++ ++ return ret; ++} ++ ++static int pivariety_read_sel(struct pivariety *pivariety, ++ struct v4l2_rect *rect) ++{ ++ int ret = 0; ++ ++ ret += pivariety_read(pivariety, IPC_SEL_TOP_REG, &rect->top); ++ ret += pivariety_read(pivariety, IPC_SEL_LEFT_REG, &rect->left); ++ ret += pivariety_read(pivariety, IPC_SEL_WIDTH_REG, &rect->width); ++ ret += pivariety_read(pivariety, IPC_SEL_HEIGHT_REG, &rect->height); ++ ++ if (ret || rect->top == NO_DATA_AVAILABLE || ++ rect->left == NO_DATA_AVAILABLE || ++ rect->width == NO_DATA_AVAILABLE || ++ rect->height == NO_DATA_AVAILABLE) { ++ v4l2_err(&pivariety->sd, "%s: Failed to read selection.\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static const struct v4l2_rect * ++__pivariety_get_pad_crop(struct pivariety *pivariety, ++ struct v4l2_subdev_state *sd_state, ++ unsigned int pad, ++ enum v4l2_subdev_format_whence which) ++{ ++ int ret; ++ ++ switch (which) { ++ case V4L2_SUBDEV_FORMAT_TRY: ++ return v4l2_subdev_get_try_crop(&pivariety->sd, sd_state, pad); ++ case V4L2_SUBDEV_FORMAT_ACTIVE: ++ ret = pivariety_read_sel(pivariety, &pivariety->crop); ++ if (ret) ++ return NULL; ++ return &pivariety->crop; ++ } ++ ++ return NULL; ++} ++ ++static int pivariety_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_selection *sel) ++{ ++ int ret = 0; ++ struct v4l2_rect rect; ++ struct pivariety *pivariety = to_pivariety(sd); ++ ++ ret = pivariety_write(pivariety, IPC_SEL_TARGET_REG, sel->target); ++ if (ret) { ++ v4l2_err(sd, "%s: Write register 0x%02x failed\n", ++ __func__, IPC_SEL_TARGET_REG); ++ return -EINVAL; ++ } ++ ++ wait_for_free(pivariety, 2); ++ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP: { ++ mutex_lock(&pivariety->mutex); ++ sel->r = *__pivariety_get_pad_crop(pivariety, sd_state, ++ sel->pad, ++ sel->which); ++ mutex_unlock(&pivariety->mutex); ++ ++ return 0; ++ } ++ ++ case V4L2_SEL_TGT_NATIVE_SIZE: ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ ret = pivariety_read_sel(pivariety, &rect); ++ if (ret) ++ return -EINVAL; ++ ++ sel->r = rect; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++/* Stop streaming */ ++static int pivariety_stop_streaming(struct pivariety *pivariety) ++{ ++ int ret; ++ ++ /* set stream off register */ ++ ret = pivariety_write(pivariety, MODE_SELECT_REG, ARDUCAM_MODE_STANDBY); ++ if (ret) ++ v4l2_err(&pivariety->sd, "%s failed to set stream\n", __func__); ++ ++ /* ++ * Return success even if it was an error, as there is nothing the ++ * caller can do about it. ++ */ ++ return 0; ++} ++ ++static int pivariety_set_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct pivariety *pivariety = to_pivariety(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret = 0; ++ ++ mutex_lock(&pivariety->mutex); ++ if (pivariety->streaming == enable) { ++ mutex_unlock(&pivariety->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 = pivariety_start_streaming(pivariety); ++ if (ret) ++ goto err_rpm_put; ++ } else { ++ pivariety_stop_streaming(pivariety); ++ pm_runtime_put(&client->dev); ++ } ++ ++ pivariety->streaming = enable; ++ ++ /* ++ * vflip and hflip cannot change during streaming ++ * Pivariety may not implement flip control. ++ */ ++ if (pivariety->vflip) ++ __v4l2_ctrl_grab(pivariety->vflip, enable); ++ ++ if (pivariety->hflip) ++ __v4l2_ctrl_grab(pivariety->hflip, enable); ++ ++ mutex_unlock(&pivariety->mutex); ++ ++ return ret; ++ ++err_rpm_put: ++ pm_runtime_put(&client->dev); ++err_unlock: ++ mutex_unlock(&pivariety->mutex); ++ ++ return ret; ++} ++ ++static int __maybe_unused pivariety_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct pivariety *pivariety = to_pivariety(sd); ++ ++ if (pivariety->streaming) ++ pivariety_stop_streaming(pivariety); ++ ++ return 0; ++} ++ ++static int __maybe_unused pivariety_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct pivariety *pivariety = to_pivariety(sd); ++ int ret; ++ ++ if (pivariety->streaming) { ++ ret = pivariety_start_streaming(pivariety); ++ if (ret) ++ goto error; ++ } ++ ++ return 0; ++ ++error: ++ pivariety_stop_streaming(pivariety); ++ pivariety->streaming = 0; ++ return ret; ++} ++ ++static int pivariety_get_regulators(struct pivariety *pivariety) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&pivariety->sd); ++ int i; ++ ++ for (i = 0; i < ARDUCAM_NUM_SUPPLIES; i++) ++ pivariety->suppliesi.supply = pivariety_supply_namei; ++ ++ return devm_regulator_bulk_get(&client->dev, ++ ARDUCAM_NUM_SUPPLIES, ++ pivariety->supplies); ++} ++ ++static int pivariety_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad, ++ struct v4l2_mbus_config *cfg) ++{ ++ struct pivariety *pivariety = to_pivariety(sd); ++ ++ if (pivariety->lanes > pivariety->bus.num_data_lanes) ++ return -EINVAL; ++ ++ cfg->type = V4L2_MBUS_CSI2_DPHY; ++ cfg->bus.mipi_csi2.flags = pivariety->bus.flags; ++ cfg->bus.mipi_csi2.num_data_lanes = pivariety->lanes; ++ ++ return 0; ++} ++ ++static const struct v4l2_subdev_core_ops pivariety_core_ops = { ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++}; ++ ++static const struct v4l2_subdev_video_ops pivariety_video_ops = { ++ .s_stream = pivariety_set_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops pivariety_pad_ops = { ++ .enum_mbus_code = pivariety_enum_mbus_code, ++ .get_fmt = pivariety_get_fmt, ++ .set_fmt = pivariety_set_fmt, ++ .enum_frame_size = pivariety_enum_framesizes, ++ .get_selection = pivariety_get_selection, ++ .get_mbus_config = pivariety_get_mbus_config, ++}; ++ ++static const struct v4l2_subdev_ops pivariety_subdev_ops = { ++ .core = &pivariety_core_ops, ++ .video = &pivariety_video_ops, ++ .pad = &pivariety_pad_ops, ++}; ++ ++static const struct v4l2_subdev_internal_ops pivariety_internal_ops = { ++ .open = pivariety_open, ++}; ++ ++static void pivariety_free_controls(struct pivariety *pivariety) ++{ ++ v4l2_ctrl_handler_free(pivariety->sd.ctrl_handler); ++ mutex_destroy(&pivariety->mutex); ++} ++ ++static int pivariety_get_length_of_set(struct pivariety *pivariety, ++ u16 idx_reg, u16 val_reg) ++{ ++ int ret; ++ int index = 0; ++ u32 val; ++ ++ while (1) { ++ ret = pivariety_write(pivariety, idx_reg, index); ++ ret += pivariety_read(pivariety, val_reg, &val); ++ ++ if (ret < 0) ++ return -1; ++ ++ if (val == NO_DATA_AVAILABLE) ++ break; ++ index++; ++ } ++ pivariety_write(pivariety, idx_reg, 0); ++ return index; ++} ++ ++static int pivariety_enum_resolution(struct pivariety *pivariety, ++ struct arducam_format *format) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&pivariety->sd); ++ int index = 0; ++ u32 width, height; ++ int num_resolution = 0; ++ int ret; ++ ++ num_resolution = pivariety_get_length_of_set(pivariety, ++ RESOLUTION_INDEX_REG, ++ FORMAT_WIDTH_REG); ++ if (num_resolution < 0) ++ goto err; ++ ++ format->resolution_set = devm_kzalloc(&client->dev, ++ sizeof(*format->resolution_set) * ++ num_resolution, ++ GFP_KERNEL); ++ while (1) { ++ ret = pivariety_write(pivariety, RESOLUTION_INDEX_REG, index); ++ ret += pivariety_read(pivariety, FORMAT_WIDTH_REG, &width); ++ ret += pivariety_read(pivariety, FORMAT_HEIGHT_REG, &height); ++ ++ if (ret < 0) ++ goto err; ++ ++ if (width == NO_DATA_AVAILABLE || height == NO_DATA_AVAILABLE) ++ break; ++ ++ format->resolution_setindex.width = width; ++ format->resolution_setindex.height = height; ++ ++ index++; ++ } ++ ++ format->num_resolution_set = index; ++ pivariety_write(pivariety, RESOLUTION_INDEX_REG, 0); ++ return 0; ++err: ++ return -ENODEV; ++} ++ ++static int pivariety_enum_pixformat(struct pivariety *pivariety) ++{ ++ int ret = 0; ++ u32 mbus_code = 0; ++ int pixfmt_type; ++ int bayer_order; ++ int bayer_order_not_volatile; ++ int lanes; ++ int index = 0; ++ int num_pixformat = 0; ++ struct arducam_format *arducam_fmt; ++ struct i2c_client *client = v4l2_get_subdevdata(&pivariety->sd); ++ ++ num_pixformat = pivariety_get_length_of_set(pivariety, ++ PIXFORMAT_INDEX_REG, ++ PIXFORMAT_TYPE_REG); ++ ++ if (num_pixformat < 0) ++ goto err; ++ ++ ret = pivariety_read(pivariety, FLIPS_DONT_CHANGE_ORDER_REG, ++ &bayer_order_not_volatile); ++ if (bayer_order_not_volatile == NO_DATA_AVAILABLE) ++ pivariety->bayer_order_volatile = 1; ++ else ++ pivariety->bayer_order_volatile = !bayer_order_not_volatile; ++ ++ if (ret < 0) ++ goto err; ++ ++ pivariety->supported_formats = ++ devm_kzalloc(&client->dev, ++ sizeof(*pivariety->supported_formats) * ++ num_pixformat, ++ GFP_KERNEL); ++ ++ while (1) { ++ ret = pivariety_write(pivariety, PIXFORMAT_INDEX_REG, index); ++ ret += pivariety_read(pivariety, PIXFORMAT_TYPE_REG, ++ &pixfmt_type); ++ ++ if (pixfmt_type == NO_DATA_AVAILABLE) ++ break; ++ ++ ret += pivariety_read(pivariety, MIPI_LANES_REG, &lanes); ++ if (lanes == NO_DATA_AVAILABLE) ++ break; ++ ++ ret += pivariety_read(pivariety, PIXFORMAT_ORDER_REG, ++ &bayer_order); ++ if (ret < 0) ++ goto err; ++ ++ mbus_code = data_type_to_mbus_code(pixfmt_type, bayer_order); ++ arducam_fmt = &pivariety->supported_formatsindex; ++ arducam_fmt->index = index; ++ arducam_fmt->mbus_code = mbus_code; ++ arducam_fmt->bayer_order = bayer_order; ++ arducam_fmt->data_type = pixfmt_type; ++ if (pivariety_enum_resolution(pivariety, arducam_fmt)) ++ goto err; ++ ++ index++; ++ } ++ ++ pivariety_write(pivariety, PIXFORMAT_INDEX_REG, 0); ++ pivariety->num_supported_formats = index; ++ pivariety->current_format_idx = 0; ++ pivariety->current_resolution_idx = 0; ++ pivariety->lanes = lanes; ++ ++ return 0; ++ ++err: ++ return -ENODEV; ++} ++ ++static const char *pivariety_ctrl_get_name(u32 id) ++{ ++ switch (id) { ++ case V4L2_CID_ARDUCAM_EXT_TRI: ++ return "trigger_mode"; ++ case V4L2_CID_ARDUCAM_IRCUT: ++ return "ircut"; ++ case V4L2_CID_ARDUCAM_STROBE_SHIFT: ++ return "strobe_shift"; ++ case V4L2_CID_ARDUCAM_STROBE_WIDTH: ++ return "strobe_width"; ++ case V4L2_CID_ARDUCAM_MODE: ++ return "mode"; ++ default: ++ return NULL; ++ } ++} ++ ++enum v4l2_ctrl_type pivariety_get_v4l2_ctrl_type(u32 id) ++{ ++ switch (id) { ++ case V4L2_CID_ARDUCAM_EXT_TRI: ++ return V4L2_CTRL_TYPE_BOOLEAN; ++ case V4L2_CID_ARDUCAM_IRCUT: ++ return V4L2_CTRL_TYPE_BOOLEAN; ++ default: ++ return V4L2_CTRL_TYPE_INTEGER; ++ } ++} ++ ++static struct v4l2_ctrl *v4l2_ctrl_new_arducam(struct v4l2_ctrl_handler *hdl, ++ const struct v4l2_ctrl_ops *ops, ++ u32 id, s64 min, s64 max, ++ u64 step, s64 def) ++{ ++ struct v4l2_ctrl_config ctrl_cfg = { ++ .ops = ops, ++ .id = id, ++ .name = NULL, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .flags = 0, ++ .min = min, ++ .max = max, ++ .def = def, ++ .step = step, ++ }; ++ ++ ctrl_cfg.name = pivariety_ctrl_get_name(id); ++ ctrl_cfg.type = pivariety_get_v4l2_ctrl_type(id); ++ ++ return v4l2_ctrl_new_custom(hdl, &ctrl_cfg, NULL); ++} ++ ++static int pivariety_enum_controls(struct pivariety *pivariety) ++{ ++ struct v4l2_subdev *sd = &pivariety->sd; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct v4l2_ctrl_handler *ctrl_hdlr = &pivariety->ctrl_handler; ++ struct v4l2_fwnode_device_properties props; ++ struct v4l2_ctrl **ctrl = pivariety->ctrls; ++ int ret, index, num_ctrls; ++ u32 id, min, max, def, step; ++ ++ num_ctrls = pivariety_get_length_of_set(pivariety, CTRL_INDEX_REG, ++ CTRL_ID_REG); ++ if (num_ctrls < 0) ++ goto err; ++ ++ v4l2_dbg(1, debug, sd, "%s: num_ctrls = %d\n", ++ __func__, num_ctrls); ++ ++ ret = v4l2_ctrl_handler_init(ctrl_hdlr, num_ctrls); ++ if (ret) ++ return ret; ++ ++ index = 0; ++ while (1) { ++ ret = pivariety_write(pivariety, CTRL_INDEX_REG, index); ++ pivariety_write(pivariety, CTRL_VALUE_REG, 0); ++ wait_for_free(pivariety, 1); ++ ++ ret += pivariety_read(pivariety, CTRL_ID_REG, &id); ++ ret += pivariety_read(pivariety, CTRL_MAX_REG, &max); ++ ret += pivariety_read(pivariety, CTRL_MIN_REG, &min); ++ ret += pivariety_read(pivariety, CTRL_DEF_REG, &def); ++ ret += pivariety_read(pivariety, CTRL_STEP_REG, &step); ++ if (ret < 0) ++ goto err; ++ ++ if (id == NO_DATA_AVAILABLE || max == NO_DATA_AVAILABLE || ++ min == NO_DATA_AVAILABLE || def == NO_DATA_AVAILABLE || ++ step == NO_DATA_AVAILABLE) ++ break; ++ ++ v4l2_dbg(1, debug, sd, ++ "%s: index = %d, id = 0x%x, max = %d, min = %d, def = %d, step = %d\n", ++ __func__, index, id, max, min, def, step); ++ ++ if (v4l2_ctrl_get_name(id)) { ++ *ctrl = v4l2_ctrl_new_std(ctrl_hdlr, ++ &pivariety_ctrl_ops, ++ id, min, ++ max, step, ++ def); ++ v4l2_dbg(1, debug, sd, "%s: ctrl: 0x%p\n", ++ __func__, *ctrl); ++ } else if (pivariety_ctrl_get_name(id)) { ++ *ctrl = v4l2_ctrl_new_arducam(ctrl_hdlr, ++ &pivariety_ctrl_ops, ++ id, min, max, step, def); ++ ++ v4l2_dbg(1, debug, sd, ++ "%s: new custom ctrl, ctrl: 0x%p.\n", ++ __func__, *ctrl); ++ } else { ++ index++; ++ continue; ++ } ++ ++ if (!*ctrl) ++ goto err; ++ ++ switch (id) { ++ case V4L2_CID_HFLIP: ++ pivariety->hflip = *ctrl; ++ if (pivariety->bayer_order_volatile) ++ pivariety->hflip->flags |= ++ V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ break; ++ ++ case V4L2_CID_VFLIP: ++ pivariety->vflip = *ctrl; ++ if (pivariety->bayer_order_volatile) ++ pivariety->vflip->flags |= ++ V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ break; ++ ++ case V4L2_CID_HBLANK: ++ (*ctrl)->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ break; ++ } ++ ++ ctrl++; ++ index++; ++ } ++ ++ pivariety_write(pivariety, CTRL_INDEX_REG, 0); ++ ++ ret = v4l2_fwnode_device_parse(&client->dev, &props); ++ if (ret) ++ goto err; ++ ++ ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, ++ &pivariety_ctrl_ops, ++ &props); ++ if (ret) ++ goto err; ++ ++ pivariety->sd.ctrl_handler = ctrl_hdlr; ++ v4l2_ctrl_handler_setup(ctrl_hdlr); ++ return 0; ++err: ++ return -ENODEV; ++} ++ ++static int pivariety_parse_dt(struct pivariety *pivariety, struct device *dev) ++{ ++ struct fwnode_handle *endpoint; ++ struct v4l2_fwnode_endpoint ep_cfg = { ++ .bus_type = V4L2_MBUS_CSI2_DPHY ++ }; ++ int ret = -EINVAL; ++ ++ /* 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; ++ } ++ ++ if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) { ++ dev_err(dev, "could not parse endpoint\n"); ++ goto error_out; ++ } ++ ++ pivariety->bus = ep_cfg.bus.mipi_csi2; ++ ++ ret = 0; ++ ++error_out: ++ v4l2_fwnode_endpoint_free(&ep_cfg); ++ fwnode_handle_put(endpoint); ++ ++ return ret; ++} ++ ++static int pivariety_probe(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ struct pivariety *pivariety; ++ u32 device_id, firmware_version; ++ int ret; ++ ++ pivariety = devm_kzalloc(&client->dev, sizeof(*pivariety), GFP_KERNEL); ++ if (!pivariety) ++ return -ENOMEM; ++ ++ /* Initialize subdev */ ++ v4l2_i2c_subdev_init(&pivariety->sd, client, ++ &pivariety_subdev_ops); ++ ++ if (pivariety_parse_dt(pivariety, dev)) ++ return -EINVAL; ++ ++ /* Get system clock (xclk) */ ++ pivariety->xclk = devm_clk_get(dev, "xclk"); ++ if (IS_ERR(pivariety->xclk)) { ++ dev_err(dev, "failed to get xclk\n"); ++ return PTR_ERR(pivariety->xclk); ++ } ++ ++ pivariety->xclk_freq = clk_get_rate(pivariety->xclk); ++ if (pivariety->xclk_freq != 24000000) { ++ dev_err(dev, "xclk frequency not supported: %d Hz\n", ++ pivariety->xclk_freq); ++ return -EINVAL; ++ } ++ ++ ret = pivariety_get_regulators(pivariety); ++ if (ret) ++ return ret; ++ ++ /* Request optional enable pin */ ++ pivariety->reset_gpio = devm_gpiod_get_optional(dev, "reset", ++ GPIOD_OUT_HIGH); ++ ++ ret = pivariety_power_on(dev); ++ if (ret) ++ return ret; ++ ++ ret = pivariety_read(pivariety, DEVICE_ID_REG, &device_id); ++ if (ret || device_id != DEVICE_ID) { ++ dev_err(dev, "probe failed\n"); ++ ret = -ENODEV; ++ goto error_power_off; ++ } ++ ++ ret = pivariety_read(pivariety, DEVICE_VERSION_REG, &firmware_version); ++ if (ret) ++ dev_err(dev, "read firmware version failed\n"); ++ ++ dev_info(dev, "firmware version: 0x%04X\n", firmware_version); ++ ++ if (pivariety_enum_pixformat(pivariety)) { ++ dev_err(dev, "enum pixformat failed.\n"); ++ ret = -ENODEV; ++ goto error_power_off; ++ } ++ ++ if (pivariety_enum_controls(pivariety)) { ++ dev_err(dev, "enum controls failed.\n"); ++ ret = -ENODEV; ++ goto error_power_off; ++ } ++ ++ /* Initialize subdev */ ++ pivariety->sd.internal_ops = &pivariety_internal_ops; ++ pivariety->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ pivariety->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ /* Initialize source pad */ ++ pivariety->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&pivariety->sd.entity, 1, &pivariety->pad); ++ if (ret) ++ goto error_handler_free; ++ ++ ret = v4l2_async_register_subdev_sensor(&pivariety->sd); ++ if (ret < 0) ++ goto error_media_entity; ++ ++ pm_runtime_set_active(dev); ++ pm_runtime_enable(dev); ++ pm_runtime_idle(dev); ++ ++ return 0; ++ ++error_media_entity: ++ media_entity_cleanup(&pivariety->sd.entity); ++ ++error_handler_free: ++ pivariety_free_controls(pivariety); ++ ++error_power_off: ++ pivariety_power_off(dev); ++ ++ return ret; ++} ++ ++static void pivariety_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct pivariety *pivariety = to_pivariety(sd); ++ ++ v4l2_async_unregister_subdev(sd); ++ media_entity_cleanup(&sd->entity); ++ pivariety_free_controls(pivariety); ++ ++ pm_runtime_disable(&client->dev); ++ pm_runtime_set_suspended(&client->dev); ++} ++ ++static const struct dev_pm_ops pivariety_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(pivariety_suspend, pivariety_resume) ++ SET_RUNTIME_PM_OPS(pivariety_power_off, pivariety_power_on, NULL) ++}; ++ ++static const struct of_device_id arducam_pivariety_dt_ids = { ++ { .compatible = "arducam,arducam-pivariety" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, arducam_pivariety_dt_ids); ++ ++static struct i2c_driver arducam_pivariety_i2c_driver = { ++ .driver = { ++ .name = "arducam-pivariety", ++ .of_match_table = arducam_pivariety_dt_ids, ++ .pm = &pivariety_pm_ops, ++ }, ++ .probe = pivariety_probe, ++ .remove = pivariety_remove, ++}; ++ ++module_i2c_driver(arducam_pivariety_i2c_driver); ++ ++MODULE_AUTHOR("Lee Jackson <info@arducam.com>"); ++MODULE_DESCRIPTION("Arducam Pivariety v4l2 driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/media/i2c/arducam-pivariety.h b/drivers/media/i2c/arducam-pivariety.h +new file mode 100644 +index 000000000000..99d5ada309e8 +--- /dev/null ++++ b/drivers/media/i2c/arducam-pivariety.h +@@ -0,0 +1,110 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef _ARDUCAM_PIVARIETY_H_ ++#define _ARDUCAM_PIVARIETY_H_ ++ ++#define DEVICE_REG_BASE 0x0100 ++#define PIXFORMAT_REG_BASE 0x0200 ++#define FORMAT_REG_BASE 0x0300 ++#define CTRL_REG_BASE 0x0400 ++#define IPC_REG_BASE 0x0600 ++ ++#define ARDUCAM_MODE_STANDBY 0x00 ++#define ARDUCAM_MODE_STREAMING 0x01 ++ ++#define MODE_SELECT_REG (DEVICE_REG_BASE | 0x0000) ++#define DEVICE_VERSION_REG (DEVICE_REG_BASE | 0x0001) ++#define SENSOR_ID_REG (DEVICE_REG_BASE | 0x0002) ++#define DEVICE_ID_REG (DEVICE_REG_BASE | 0x0003) ++#define SYSTEM_IDLE_REG (DEVICE_REG_BASE | 0x0007) ++ ++#define PIXFORMAT_INDEX_REG (PIXFORMAT_REG_BASE | 0x0000) ++#define PIXFORMAT_TYPE_REG (PIXFORMAT_REG_BASE | 0x0001) ++#define PIXFORMAT_ORDER_REG (PIXFORMAT_REG_BASE | 0x0002) ++#define MIPI_LANES_REG (PIXFORMAT_REG_BASE | 0x0003) ++#define FLIPS_DONT_CHANGE_ORDER_REG (PIXFORMAT_REG_BASE | 0x0004) ++ ++#define RESOLUTION_INDEX_REG (FORMAT_REG_BASE | 0x0000) ++#define FORMAT_WIDTH_REG (FORMAT_REG_BASE | 0x0001) ++#define FORMAT_HEIGHT_REG (FORMAT_REG_BASE | 0x0002) ++ ++#define CTRL_INDEX_REG (CTRL_REG_BASE | 0x0000) ++#define CTRL_ID_REG (CTRL_REG_BASE | 0x0001) ++#define CTRL_MIN_REG (CTRL_REG_BASE | 0x0002) ++#define CTRL_MAX_REG (CTRL_REG_BASE | 0x0003) ++#define CTRL_STEP_REG (CTRL_REG_BASE | 0x0004) ++#define CTRL_DEF_REG (CTRL_REG_BASE | 0x0005) ++#define CTRL_VALUE_REG (CTRL_REG_BASE | 0x0006) ++ ++#define IPC_SEL_TARGET_REG (IPC_REG_BASE | 0x0000) ++#define IPC_SEL_TOP_REG (IPC_REG_BASE | 0x0001) ++#define IPC_SEL_LEFT_REG (IPC_REG_BASE | 0x0002) ++#define IPC_SEL_WIDTH_REG (IPC_REG_BASE | 0x0003) ++#define IPC_SEL_HEIGHT_REG (IPC_REG_BASE | 0x0004) ++#define IPC_DELAY_REG (IPC_REG_BASE | 0x0005) ++ ++#define NO_DATA_AVAILABLE 0xFFFFFFFE ++ ++#define DEVICE_ID 0x0030 ++ ++#define I2C_READ_RETRY_COUNT 3 ++#define I2C_WRITE_RETRY_COUNT 2 ++ ++#define V4L2_CID_ARDUCAM_BASE (V4L2_CID_USER_BASE + 0x1000) ++#define V4L2_CID_ARDUCAM_EXT_TRI (V4L2_CID_ARDUCAM_BASE + 1) ++#define V4L2_CID_ARDUCAM_IRCUT (V4L2_CID_ARDUCAM_BASE + 8) ++#define V4L2_CID_ARDUCAM_STROBE_SHIFT (V4L2_CID_ARDUCAM_BASE + 14) ++#define V4L2_CID_ARDUCAM_STROBE_WIDTH (V4L2_CID_ARDUCAM_BASE + 15) ++#define V4L2_CID_ARDUCAM_MODE (V4L2_CID_ARDUCAM_BASE + 16) ++ ++enum image_dt { ++ IMAGE_DT_YUV420_8 = 0x18, ++ IMAGE_DT_YUV420_10, ++ ++ IMAGE_DT_YUV420CSPS_8 = 0x1C, ++ IMAGE_DT_YUV420CSPS_10, ++ IMAGE_DT_YUV422_8, ++ IMAGE_DT_YUV422_10, ++ IMAGE_DT_RGB444, ++ IMAGE_DT_RGB555, ++ IMAGE_DT_RGB565, ++ IMAGE_DT_RGB666, ++ IMAGE_DT_RGB888, ++ ++ IMAGE_DT_RAW6 = 0x28, ++ IMAGE_DT_RAW7, ++ IMAGE_DT_RAW8, ++ IMAGE_DT_RAW10, ++ IMAGE_DT_RAW12, ++ IMAGE_DT_RAW14, ++}; ++ ++enum bayer_order { ++ BAYER_ORDER_BGGR = 0, ++ BAYER_ORDER_GBRG = 1, ++ BAYER_ORDER_GRBG = 2, ++ BAYER_ORDER_RGGB = 3, ++ BAYER_ORDER_GRAY = 4, ++}; ++ ++enum yuv_order { ++ YUV_ORDER_YUYV = 0, ++ YUV_ORDER_YVYU = 1, ++ YUV_ORDER_UYVY = 2, ++ YUV_ORDER_VYUY = 3, ++}; ++ ++struct arducam_resolution { ++ u32 width; ++ u32 height; ++}; ++ ++struct arducam_format { ++ u32 index; ++ u32 mbus_code; ++ u32 bayer_order; ++ u32 data_type; ++ u32 num_resolution_set; ++ struct arducam_resolution *resolution_set; ++}; ++ ++#endif +diff --git a/drivers/media/i2c/arducam_64mp.c b/drivers/media/i2c/arducam_64mp.c +new file mode 100644 +index 000000000000..0d6a2c463ee4 +--- /dev/null ++++ b/drivers/media/i2c/arducam_64mp.c +@@ -0,0 +1,2618 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * A V4L2 driver for Arducam 64MP cameras. ++ * Copyright (C) 2021 Arducam Technology co., Ltd. ++ * ++ * Based on Sony IMX477 camera driver ++ * Copyright (C) 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 ARDUCAM_64MP_REG_VALUE_08BIT 1 ++#define ARDUCAM_64MP_REG_VALUE_16BIT 2 ++ ++/* Chip ID */ ++#define ARDUCAM_64MP_REG_CHIP_ID 0x005E ++#define ARDUCAM_64MP_CHIP_ID 0x4136 ++ ++#define ARDUCAM_64MP_REG_MODE_SELECT 0x0100 ++#define ARDUCAM_64MP_MODE_STANDBY 0x00 ++#define ARDUCAM_64MP_MODE_STREAMING 0x01 ++ ++#define ARDUCAM_64MP_REG_ORIENTATION 0x101 ++ ++#define ARDUCAM_64MP_XCLK_FREQ 24000000 ++ ++#define ARDUCAM_64MP_DEFAULT_LINK_FREQ 456000000 ++ ++/* Pixel rate is fixed at 900MHz for all the modes */ ++#define ARDUCAM_64MP_PIXEL_RATE 900000000 ++ ++/* V_TIMING internal */ ++#define ARDUCAM_64MP_REG_FRAME_LENGTH 0x0340 ++#define ARDUCAM_64MP_FRAME_LENGTH_MAX 0xffff ++ ++/* Long exposure multiplier */ ++#define ARDUCAM_64MP_LONG_EXP_SHIFT_MAX 7 ++#define ARDUCAM_64MP_LONG_EXP_SHIFT_REG 0x3100 ++ ++/* Exposure control */ ++#define ARDUCAM_64MP_REG_EXPOSURE 0x0202 ++#define ARDUCAM_64MP_EXPOSURE_OFFSET 48 ++#define ARDUCAM_64MP_EXPOSURE_MIN 9 ++#define ARDUCAM_64MP_EXPOSURE_STEP 1 ++#define ARDUCAM_64MP_EXPOSURE_DEFAULT 0x3e8 ++#define ARDUCAM_64MP_EXPOSURE_MAX (ARDUCAM_64MP_FRAME_LENGTH_MAX - \ ++ ARDUCAM_64MP_EXPOSURE_OFFSET) ++ ++/* Analog gain control */ ++#define ARDUCAM_64MP_REG_ANALOG_GAIN 0x0204 ++#define ARDUCAM_64MP_ANA_GAIN_MIN 0 ++#define ARDUCAM_64MP_ANA_GAIN_MAX 1008 ++#define ARDUCAM_64MP_ANA_GAIN_STEP 1 ++#define ARDUCAM_64MP_ANA_GAIN_DEFAULT 0x0 ++ ++/* Digital gain control */ ++#define ARDUCAM_64MP_REG_DIGITAL_GAIN 0x020e ++#define ARDUCAM_64MP_DGTL_GAIN_MIN 0x0100 ++#define ARDUCAM_64MP_DGTL_GAIN_MAX 0x0fff ++#define ARDUCAM_64MP_DGTL_GAIN_DEFAULT 0x0100 ++#define ARDUCAM_64MP_DGTL_GAIN_STEP 1 ++ ++/* Test Pattern Control */ ++#define ARDUCAM_64MP_REG_TEST_PATTERN 0x0600 ++#define ARDUCAM_64MP_TEST_PATTERN_DISABLE 0 ++#define ARDUCAM_64MP_TEST_PATTERN_SOLID_COLOR 1 ++#define ARDUCAM_64MP_TEST_PATTERN_COLOR_BARS 2 ++#define ARDUCAM_64MP_TEST_PATTERN_GREY_COLOR 3 ++#define ARDUCAM_64MP_TEST_PATTERN_PN9 4 ++ ++/* Test pattern colour components */ ++#define ARDUCAM_64MP_REG_TEST_PATTERN_R 0x0602 ++#define ARDUCAM_64MP_REG_TEST_PATTERN_GR 0x0604 ++#define ARDUCAM_64MP_REG_TEST_PATTERN_B 0x0606 ++#define ARDUCAM_64MP_REG_TEST_PATTERN_GB 0x0608 ++#define ARDUCAM_64MP_TEST_PATTERN_COLOUR_MIN 0 ++#define ARDUCAM_64MP_TEST_PATTERN_COLOUR_MAX 0x0fff ++#define ARDUCAM_64MP_TEST_PATTERN_COLOUR_STEP 1 ++#define ARDUCAM_64MP_TEST_PATTERN_R_DEFAULT \ ++ ARDUCAM_64MP_TEST_PATTERN_COLOUR_MAX ++#define ARDUCAM_64MP_TEST_PATTERN_GR_DEFAULT 0 ++#define ARDUCAM_64MP_TEST_PATTERN_B_DEFAULT 0 ++#define ARDUCAM_64MP_TEST_PATTERN_GB_DEFAULT 0 ++ ++/* Embedded metadata stream structure */ ++#define ARDUCAM_64MP_EMBEDDED_LINE_WIDTH (11560 * 3) ++#define ARDUCAM_64MP_NUM_EMBEDDED_LINES 1 ++ ++enum pad_types { ++ IMAGE_PAD, ++ METADATA_PAD, ++ NUM_PADS ++}; ++ ++/* ARDUCAM_64MP native and active pixel array size. */ ++#define ARDUCAM_64MP_NATIVE_WIDTH 9344U ++#define ARDUCAM_64MP_NATIVE_HEIGHT 7032U ++#define ARDUCAM_64MP_PIXEL_ARRAY_LEFT 48U ++#define ARDUCAM_64MP_PIXEL_ARRAY_TOP 40U ++#define ARDUCAM_64MP_PIXEL_ARRAY_WIDTH 9248U ++#define ARDUCAM_64MP_PIXEL_ARRAY_HEIGHT 6944U ++ ++struct arducam_64mp_reg { ++ u16 address; ++ u8 val; ++}; ++ ++struct arducam_64mp_reg_list { ++ unsigned int num_of_regs; ++ const struct arducam_64mp_reg *regs; ++}; ++ ++/* Mode : resolution and related config&values */ ++struct arducam_64mp_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; ++ ++ /* Default framerate. */ ++ struct v4l2_fract timeperframe_default; ++ ++ /* Default register values */ ++ struct arducam_64mp_reg_list reg_list; ++}; ++ ++static const s64 arducam_64mp_link_freq_menu = { ++ ARDUCAM_64MP_DEFAULT_LINK_FREQ, ++}; ++ ++static const struct arducam_64mp_reg mode_common_regs = { ++ {0x0100, 0x00}, ++ {0x0136, 0x18}, ++ {0x0137, 0x00}, ++ {0x33F0, 0x01}, ++ {0x33F1, 0x03}, ++ {0x0111, 0x02}, ++ {0x3062, 0x00}, ++ {0x3063, 0x30}, ++ {0x3076, 0x00}, ++ {0x3077, 0x30}, ++ {0x1f06, 0x06}, ++ {0x1f07, 0x82}, ++ {0x1f04, 0x71}, ++ {0x1f05, 0x01}, ++ {0x1f08, 0x01}, ++ {0x5bfe, 0x14}, ++ {0x5c0d, 0x2d}, ++ {0x5c1c, 0x30}, ++ {0x5c2b, 0x32}, ++ {0x5c37, 0x2e}, ++ {0x5c40, 0x30}, ++ {0x5c50, 0x14}, ++ {0x5c5f, 0x28}, ++ {0x5c6e, 0x28}, ++ {0x5c7d, 0x32}, ++ {0x5c89, 0x37}, ++ {0x5c92, 0x56}, ++ {0x5bfc, 0x12}, ++ {0x5c0b, 0x2a}, ++ {0x5c1a, 0x2c}, ++ {0x5c29, 0x2f}, ++ {0x5c36, 0x2e}, ++ {0x5c3f, 0x2e}, ++ {0x5c4e, 0x06}, ++ {0x5c5d, 0x1e}, ++ {0x5c6c, 0x20}, ++ {0x5c7b, 0x1e}, ++ {0x5c88, 0x32}, ++ {0x5c91, 0x32}, ++ {0x5c02, 0x14}, ++ {0x5c11, 0x2f}, ++ {0x5c20, 0x32}, ++ {0x5c2f, 0x34}, ++ {0x5c39, 0x31}, ++ {0x5c42, 0x31}, ++ {0x5c8b, 0x28}, ++ {0x5c94, 0x28}, ++ {0x5c00, 0x10}, ++ {0x5c0f, 0x2c}, ++ {0x5c1e, 0x2e}, ++ {0x5c2d, 0x32}, ++ {0x5c38, 0x2e}, ++ {0x5c41, 0x2b}, ++ {0x5c61, 0x0a}, ++ {0x5c70, 0x0a}, ++ {0x5c7f, 0x0a}, ++ {0x5c8a, 0x1e}, ++ {0x5c93, 0x2a}, ++ {0x5bfa, 0x2b}, ++ {0x5c09, 0x2d}, ++ {0x5c18, 0x2e}, ++ {0x5c27, 0x30}, ++ {0x5c5b, 0x28}, ++ {0x5c6a, 0x22}, ++ {0x5c79, 0x42}, ++ {0x5bfb, 0x2c}, ++ {0x5c0a, 0x2f}, ++ {0x5c19, 0x2e}, ++ {0x5c28, 0x2e}, ++ {0x5c4d, 0x20}, ++ {0x5c5c, 0x1e}, ++ {0x5c6b, 0x32}, ++ {0x5c7a, 0x32}, ++ {0x5bfd, 0x30}, ++ {0x5c0c, 0x32}, ++ {0x5c1b, 0x2e}, ++ {0x5c2a, 0x30}, ++ {0x5c4f, 0x28}, ++ {0x5c5e, 0x32}, ++ {0x5c6d, 0x37}, ++ {0x5c7c, 0x56}, ++ {0x5bff, 0x2e}, ++ {0x5c0e, 0x32}, ++ {0x5c1d, 0x2e}, ++ {0x5c2c, 0x2b}, ++ {0x5c51, 0x0a}, ++ {0x5c60, 0x0a}, ++ {0x5c6f, 0x1e}, ++ {0x5c7e, 0x2a}, ++ {0x5c01, 0x32}, ++ {0x5c10, 0x34}, ++ {0x5c1f, 0x31}, ++ {0x5c2e, 0x31}, ++ {0x5c71, 0x28}, ++ {0x5c80, 0x28}, ++ {0x5c4c, 0x2a}, ++ {0x33f2, 0x01}, ++ {0x1f04, 0x73}, ++ {0x1f05, 0x01}, ++ {0x5bfa, 0x35}, ++ {0x5c09, 0x38}, ++ {0x5c18, 0x3a}, ++ {0x5c27, 0x38}, ++ {0x5c5b, 0x25}, ++ {0x5c6a, 0x24}, ++ {0x5c79, 0x47}, ++ {0x5bfc, 0x15}, ++ {0x5c0b, 0x2e}, ++ {0x5c1a, 0x36}, ++ {0x5c29, 0x38}, ++ {0x5c36, 0x36}, ++ {0x5c3f, 0x36}, ++ {0x5c4e, 0x0b}, ++ {0x5c5d, 0x20}, ++ {0x5c6c, 0x2a}, ++ {0x5c7b, 0x25}, ++ {0x5c88, 0x25}, ++ {0x5c91, 0x22}, ++ {0x5bfe, 0x15}, ++ {0x5c0d, 0x32}, ++ {0x5c1c, 0x36}, ++ {0x5c2b, 0x36}, ++ {0x5c37, 0x3a}, ++ {0x5c40, 0x39}, ++ {0x5c50, 0x06}, ++ {0x5c5f, 0x22}, ++ {0x5c6e, 0x23}, ++ {0x5c7d, 0x2e}, ++ {0x5c89, 0x44}, ++ {0x5c92, 0x51}, ++ {0x5d7f, 0x0a}, ++ {0x5c00, 0x17}, ++ {0x5c0f, 0x36}, ++ {0x5c1e, 0x38}, ++ {0x5c2d, 0x3c}, ++ {0x5c38, 0x38}, ++ {0x5c41, 0x36}, ++ {0x5c52, 0x0a}, ++ {0x5c61, 0x21}, ++ {0x5c70, 0x23}, ++ {0x5c7f, 0x1b}, ++ {0x5c8a, 0x22}, ++ {0x5c93, 0x20}, ++ {0x5c02, 0x1a}, ++ {0x5c11, 0x3e}, ++ {0x5c20, 0x3f}, ++ {0x5c2f, 0x3d}, ++ {0x5c39, 0x3e}, ++ {0x5c42, 0x3c}, ++ {0x5c54, 0x02}, ++ {0x5c63, 0x12}, ++ {0x5c72, 0x14}, ++ {0x5c81, 0x24}, ++ {0x5c8b, 0x1c}, ++ {0x5c94, 0x4e}, ++ {0x5d8a, 0x09}, ++ {0x5bfb, 0x36}, ++ {0x5c0a, 0x38}, ++ {0x5c19, 0x36}, ++ {0x5c28, 0x36}, ++ {0x5c4d, 0x2a}, ++ {0x5c5c, 0x25}, ++ {0x5c6b, 0x25}, ++ {0x5c7a, 0x22}, ++ {0x5bfd, 0x36}, ++ {0x5c0c, 0x36}, ++ {0x5c1b, 0x3a}, ++ {0x5c2a, 0x39}, ++ {0x5c4f, 0x23}, ++ {0x5c5e, 0x2e}, ++ {0x5c6d, 0x44}, ++ {0x5c7c, 0x51}, ++ {0x5d63, 0x0a}, ++ {0x5bff, 0x38}, ++ {0x5c0e, 0x3c}, ++ {0x5c1d, 0x38}, ++ {0x5c2c, 0x36}, ++ {0x5c51, 0x23}, ++ {0x5c60, 0x1b}, ++ {0x5c6f, 0x22}, ++ {0x5c7e, 0x20}, ++ {0x5c01, 0x3f}, ++ {0x5c10, 0x3d}, ++ {0x5c1f, 0x3e}, ++ {0x5c2e, 0x3c}, ++ {0x5c53, 0x14}, ++ {0x5c62, 0x24}, ++ {0x5c71, 0x1c}, ++ {0x5c80, 0x4e}, ++ {0x5d76, 0x09}, ++ {0x5c4c, 0x2a}, ++ {0x33f2, 0x02}, ++ {0x1f04, 0x78}, ++ {0x1f05, 0x01}, ++ {0x5bfa, 0x37}, ++ {0x5c09, 0x36}, ++ {0x5c18, 0x39}, ++ {0x5c27, 0x38}, ++ {0x5c5b, 0x27}, ++ {0x5c6a, 0x2b}, ++ {0x5c79, 0x48}, ++ {0x5bfc, 0x16}, ++ {0x5c0b, 0x32}, ++ {0x5c1a, 0x33}, ++ {0x5c29, 0x37}, ++ {0x5c36, 0x36}, ++ {0x5c3f, 0x35}, ++ {0x5c4e, 0x0d}, ++ {0x5c5d, 0x2d}, ++ {0x5c6c, 0x23}, ++ {0x5c7b, 0x25}, ++ {0x5c88, 0x31}, ++ {0x5c91, 0x2e}, ++ {0x5bfe, 0x15}, ++ {0x5c0d, 0x31}, ++ {0x5c1c, 0x35}, ++ {0x5c2b, 0x36}, ++ {0x5c37, 0x35}, ++ {0x5c40, 0x37}, ++ {0x5c50, 0x0f}, ++ {0x5c5f, 0x31}, ++ {0x5c6e, 0x30}, ++ {0x5c7d, 0x33}, ++ {0x5c89, 0x36}, ++ {0x5c92, 0x5b}, ++ {0x5c00, 0x13}, ++ {0x5c0f, 0x2f}, ++ {0x5c1e, 0x2e}, ++ {0x5c2d, 0x34}, ++ {0x5c38, 0x33}, ++ {0x5c41, 0x32}, ++ {0x5c52, 0x0d}, ++ {0x5c61, 0x27}, ++ {0x5c70, 0x28}, ++ {0x5c7f, 0x1f}, ++ {0x5c8a, 0x25}, ++ {0x5c93, 0x2c}, ++ {0x5c02, 0x15}, ++ {0x5c11, 0x36}, ++ {0x5c20, 0x39}, ++ {0x5c2f, 0x3a}, ++ {0x5c39, 0x37}, ++ {0x5c42, 0x37}, ++ {0x5c54, 0x04}, ++ {0x5c63, 0x1c}, ++ {0x5c72, 0x1c}, ++ {0x5c81, 0x1c}, ++ {0x5c8b, 0x28}, ++ {0x5c94, 0x24}, ++ {0x5bfb, 0x33}, ++ {0x5c0a, 0x37}, ++ {0x5c19, 0x36}, ++ {0x5c28, 0x35}, ++ {0x5c4d, 0x23}, ++ {0x5c5c, 0x25}, ++ {0x5c6b, 0x31}, ++ {0x5c7a, 0x2e}, ++ {0x5bfd, 0x35}, ++ {0x5c0c, 0x36}, ++ {0x5c1b, 0x35}, ++ {0x5c2a, 0x37}, ++ {0x5c4f, 0x30}, ++ {0x5c5e, 0x33}, ++ {0x5c6d, 0x36}, ++ {0x5c7c, 0x5b}, ++ {0x5bff, 0x2e}, ++ {0x5c0e, 0x34}, ++ {0x5c1d, 0x33}, ++ {0x5c2c, 0x32}, ++ {0x5c51, 0x28}, ++ {0x5c60, 0x1f}, ++ {0x5c6f, 0x25}, ++ {0x5c7e, 0x2c}, ++ {0x5c01, 0x39}, ++ {0x5c10, 0x3a}, ++ {0x5c1f, 0x37}, ++ {0x5c2e, 0x37}, ++ {0x5c53, 0x1c}, ++ {0x5c62, 0x1c}, ++ {0x5c71, 0x28}, ++ {0x5c80, 0x24}, ++ {0x5c4c, 0x2c}, ++ {0x33f2, 0x03}, ++ {0x1f08, 0x00}, ++ {0x32c8, 0x00}, ++ {0x4017, 0x40}, ++ {0x40a2, 0x01}, ++ {0x40ac, 0x01}, ++ {0x4328, 0x00}, ++ {0x4329, 0xb3}, ++ {0x4e15, 0x10}, ++ {0x4e19, 0x2f}, ++ {0x4e21, 0x0f}, ++ {0x4e2f, 0x10}, ++ {0x4e3d, 0x10}, ++ {0x4e41, 0x2f}, ++ {0x4e57, 0x29}, ++ {0x4ffb, 0x2f}, ++ {0x5011, 0x24}, ++ {0x501d, 0x03}, ++ {0x505f, 0x41}, ++ {0x5060, 0xdf}, ++ {0x5065, 0xdf}, ++ {0x5066, 0x37}, ++ {0x506e, 0x57}, ++ {0x5070, 0xc5}, ++ {0x5072, 0x57}, ++ {0x5075, 0x53}, ++ {0x5076, 0x55}, ++ {0x5077, 0xc1}, ++ {0x5078, 0xc3}, ++ {0x5079, 0x53}, ++ {0x507a, 0x55}, ++ {0x507d, 0x57}, ++ {0x507e, 0xdf}, ++ {0x507f, 0xc5}, ++ {0x5081, 0x57}, ++ {0x53c8, 0x01}, ++ {0x53c9, 0xe2}, ++ {0x53ca, 0x03}, ++ {0x5422, 0x7a}, ++ {0x548e, 0x40}, ++ {0x5497, 0x5e}, ++ {0x54a1, 0x40}, ++ {0x54a9, 0x40}, ++ {0x54b2, 0x5e}, ++ {0x54bc, 0x40}, ++ {0x57c6, 0x00}, ++ {0x583d, 0x0e}, ++ {0x583e, 0x0e}, ++ {0x583f, 0x0e}, ++ {0x5840, 0x0e}, ++ {0x5841, 0x0e}, ++ {0x5842, 0x0e}, ++ {0x5900, 0x12}, ++ {0x5901, 0x12}, ++ {0x5902, 0x14}, ++ {0x5903, 0x12}, ++ {0x5904, 0x14}, ++ {0x5905, 0x12}, ++ {0x5906, 0x14}, ++ {0x5907, 0x12}, ++ {0x590f, 0x12}, ++ {0x5911, 0x12}, ++ {0x5913, 0x12}, ++ {0x591c, 0x12}, ++ {0x591e, 0x12}, ++ {0x5920, 0x12}, ++ {0x5948, 0x08}, ++ {0x5949, 0x08}, ++ {0x594a, 0x08}, ++ {0x594b, 0x08}, ++ {0x594c, 0x08}, ++ {0x594d, 0x08}, ++ {0x594e, 0x08}, ++ {0x594f, 0x08}, ++ {0x595c, 0x08}, ++ {0x595e, 0x08}, ++ {0x5960, 0x08}, ++ {0x596e, 0x08}, ++ {0x5970, 0x08}, ++ {0x5972, 0x08}, ++ {0x597e, 0x0f}, ++ {0x597f, 0x0f}, ++ {0x599a, 0x0f}, ++ {0x59de, 0x08}, ++ {0x59df, 0x08}, ++ {0x59fa, 0x08}, ++ {0x5a59, 0x22}, ++ {0x5a5b, 0x22}, ++ {0x5a5d, 0x1a}, ++ {0x5a5f, 0x22}, ++ {0x5a61, 0x1a}, ++ {0x5a63, 0x22}, ++ {0x5a65, 0x1a}, ++ {0x5a67, 0x22}, ++ {0x5a77, 0x22}, ++ {0x5a7b, 0x22}, ++ {0x5a7f, 0x22}, ++ {0x5a91, 0x22}, ++ {0x5a95, 0x22}, ++ {0x5a99, 0x22}, ++ {0x5ae9, 0x66}, ++ {0x5aeb, 0x66}, ++ {0x5aed, 0x5e}, ++ {0x5aef, 0x66}, ++ {0x5af1, 0x5e}, ++ {0x5af3, 0x66}, ++ {0x5af5, 0x5e}, ++ {0x5af7, 0x66}, ++ {0x5b07, 0x66}, ++ {0x5b0b, 0x66}, ++ {0x5b0f, 0x66}, ++ {0x5b21, 0x66}, ++ {0x5b25, 0x66}, ++ {0x5b29, 0x66}, ++ {0x5b79, 0x46}, ++ {0x5b7b, 0x3e}, ++ {0x5b7d, 0x3e}, ++ {0x5b89, 0x46}, ++ {0x5b8b, 0x46}, ++ {0x5b97, 0x46}, ++ {0x5b99, 0x46}, ++ {0x5c9e, 0x0a}, ++ {0x5c9f, 0x08}, ++ {0x5ca0, 0x0a}, ++ {0x5ca1, 0x0a}, ++ {0x5ca2, 0x0b}, ++ {0x5ca3, 0x06}, ++ {0x5ca4, 0x04}, ++ {0x5ca5, 0x06}, ++ {0x5ca6, 0x04}, ++ {0x5cad, 0x0b}, ++ {0x5cae, 0x0a}, ++ {0x5caf, 0x0c}, ++ {0x5cb0, 0x0a}, ++ {0x5cb1, 0x0b}, ++ {0x5cb2, 0x08}, ++ {0x5cb3, 0x06}, ++ {0x5cb4, 0x08}, ++ {0x5cb5, 0x04}, ++ {0x5cbc, 0x0b}, ++ {0x5cbd, 0x09}, ++ {0x5cbe, 0x08}, ++ {0x5cbf, 0x09}, ++ {0x5cc0, 0x0a}, ++ {0x5cc1, 0x08}, ++ {0x5cc2, 0x06}, ++ {0x5cc3, 0x08}, ++ {0x5cc4, 0x06}, ++ {0x5ccb, 0x0a}, ++ {0x5ccc, 0x09}, ++ {0x5ccd, 0x0a}, ++ {0x5cce, 0x08}, ++ {0x5ccf, 0x0a}, ++ {0x5cd0, 0x08}, ++ {0x5cd1, 0x08}, ++ {0x5cd2, 0x08}, ++ {0x5cd3, 0x08}, ++ {0x5cda, 0x09}, ++ {0x5cdb, 0x09}, ++ {0x5cdc, 0x08}, ++ {0x5cdd, 0x08}, ++ {0x5ce3, 0x09}, ++ {0x5ce4, 0x08}, ++ {0x5ce5, 0x08}, ++ {0x5ce6, 0x08}, ++ {0x5cf4, 0x04}, ++ {0x5d04, 0x04}, ++ {0x5d13, 0x06}, ++ {0x5d22, 0x06}, ++ {0x5d23, 0x04}, ++ {0x5d2e, 0x06}, ++ {0x5d37, 0x06}, ++ {0x5d6f, 0x09}, ++ {0x5d72, 0x0f}, ++ {0x5d88, 0x0f}, ++ {0x5de6, 0x01}, ++ {0x5de7, 0x01}, ++ {0x5de8, 0x01}, ++ {0x5de9, 0x01}, ++ {0x5dea, 0x01}, ++ {0x5deb, 0x01}, ++ {0x5dec, 0x01}, ++ {0x5df2, 0x01}, ++ {0x5df3, 0x01}, ++ {0x5df4, 0x01}, ++ {0x5df5, 0x01}, ++ {0x5df6, 0x01}, ++ {0x5df7, 0x01}, ++ {0x5df8, 0x01}, ++ {0x5dfe, 0x01}, ++ {0x5dff, 0x01}, ++ {0x5e00, 0x01}, ++ {0x5e01, 0x01}, ++ {0x5e02, 0x01}, ++ {0x5e03, 0x01}, ++ {0x5e04, 0x01}, ++ {0x5e0a, 0x01}, ++ {0x5e0b, 0x01}, ++ {0x5e0c, 0x01}, ++ {0x5e0d, 0x01}, ++ {0x5e0e, 0x01}, ++ {0x5e0f, 0x01}, ++ {0x5e10, 0x01}, ++ {0x5e16, 0x01}, ++ {0x5e17, 0x01}, ++ {0x5e18, 0x01}, ++ {0x5e1e, 0x01}, ++ {0x5e1f, 0x01}, ++ {0x5e20, 0x01}, ++ {0x5e6e, 0x5a}, ++ {0x5e6f, 0x46}, ++ {0x5e70, 0x46}, ++ {0x5e71, 0x3c}, ++ {0x5e72, 0x3c}, ++ {0x5e73, 0x28}, ++ {0x5e74, 0x28}, ++ {0x5e75, 0x6e}, ++ {0x5e76, 0x6e}, ++ {0x5e81, 0x46}, ++ {0x5e83, 0x3c}, ++ {0x5e85, 0x28}, ++ {0x5e87, 0x6e}, ++ {0x5e92, 0x46}, ++ {0x5e94, 0x3c}, ++ {0x5e96, 0x28}, ++ {0x5e98, 0x6e}, ++ {0x5ecb, 0x26}, ++ {0x5ecc, 0x26}, ++ {0x5ecd, 0x26}, ++ {0x5ece, 0x26}, ++ {0x5ed2, 0x26}, ++ {0x5ed3, 0x26}, ++ {0x5ed4, 0x26}, ++ {0x5ed5, 0x26}, ++ {0x5ed9, 0x26}, ++ {0x5eda, 0x26}, ++ {0x5ee5, 0x08}, ++ {0x5ee6, 0x08}, ++ {0x5ee7, 0x08}, ++ {0x6006, 0x14}, ++ {0x6007, 0x14}, ++ {0x6008, 0x14}, ++ {0x6009, 0x14}, ++ {0x600a, 0x14}, ++ {0x600b, 0x14}, ++ {0x600c, 0x14}, ++ {0x600d, 0x22}, ++ {0x600e, 0x22}, ++ {0x600f, 0x14}, ++ {0x601a, 0x14}, ++ {0x601b, 0x14}, ++ {0x601c, 0x14}, ++ {0x601d, 0x14}, ++ {0x601e, 0x14}, ++ {0x601f, 0x14}, ++ {0x6020, 0x14}, ++ {0x6021, 0x22}, ++ {0x6022, 0x22}, ++ {0x6023, 0x14}, ++ {0x602e, 0x14}, ++ {0x602f, 0x14}, ++ {0x6030, 0x14}, ++ {0x6031, 0x22}, ++ {0x6039, 0x14}, ++ {0x603a, 0x14}, ++ {0x603b, 0x14}, ++ {0x603c, 0x22}, ++ {0x6132, 0x0f}, ++ {0x6133, 0x0f}, ++ {0x6134, 0x0f}, ++ {0x6135, 0x0f}, ++ {0x6136, 0x0f}, ++ {0x6137, 0x0f}, ++ {0x6138, 0x0f}, ++ {0x613e, 0x0f}, ++ {0x613f, 0x0f}, ++ {0x6140, 0x0f}, ++ {0x6141, 0x0f}, ++ {0x6142, 0x0f}, ++ {0x6143, 0x0f}, ++ {0x6144, 0x0f}, ++ {0x614a, 0x0f}, ++ {0x614b, 0x0f}, ++ {0x614c, 0x0f}, ++ {0x614d, 0x0f}, ++ {0x614e, 0x0f}, ++ {0x614f, 0x0f}, ++ {0x6150, 0x0f}, ++ {0x6156, 0x0f}, ++ {0x6157, 0x0f}, ++ {0x6158, 0x0f}, ++ {0x6159, 0x0f}, ++ {0x615a, 0x0f}, ++ {0x615b, 0x0f}, ++ {0x615c, 0x0f}, ++ {0x6162, 0x0f}, ++ {0x6163, 0x0f}, ++ {0x6164, 0x0f}, ++ {0x616a, 0x0f}, ++ {0x616b, 0x0f}, ++ {0x616c, 0x0f}, ++ {0x6226, 0x00}, ++ {0x84f8, 0x01}, ++ {0x8501, 0x00}, ++ {0x8502, 0x01}, ++ {0x8505, 0x00}, ++ {0x8744, 0x00}, ++ {0x883c, 0x01}, ++ {0x8845, 0x00}, ++ {0x8846, 0x01}, ++ {0x8849, 0x00}, ++ {0x9004, 0x1f}, ++ {0x9064, 0x4d}, ++ {0x9065, 0x3d}, ++ {0x922e, 0x91}, ++ {0x922f, 0x2a}, ++ {0x9230, 0xe2}, ++ {0x9231, 0xc0}, ++ {0x9232, 0xe2}, ++ {0x9233, 0xc1}, ++ {0x9234, 0xe2}, ++ {0x9235, 0xc2}, ++ {0x9236, 0xe2}, ++ {0x9237, 0xc3}, ++ {0x9238, 0xe2}, ++ {0x9239, 0xd4}, ++ {0x923a, 0xe2}, ++ {0x923b, 0xd5}, ++ {0x923c, 0x90}, ++ {0x923d, 0x64}, ++ {0xb0b9, 0x10}, ++ {0xbc76, 0x00}, ++ {0xbc77, 0x00}, ++ {0xbc78, 0x00}, ++ {0xbc79, 0x00}, ++ {0xbc7b, 0x28}, ++ {0xbc7c, 0x00}, ++ {0xbc7d, 0x00}, ++ {0xbc7f, 0xc0}, ++ {0xc6b9, 0x01}, ++ {0xecb5, 0x04}, ++ {0xecbf, 0x04}, ++ {0x0112, 0x0a}, ++ {0x0113, 0x0a}, ++ {0x0114, 0x01}, ++ {0x0301, 0x08}, ++ {0x0303, 0x02}, ++ {0x0305, 0x04}, ++ {0x0306, 0x01}, ++ {0x0307, 0x2c}, ++ {0x030b, 0x02}, ++ {0x030d, 0x04}, ++ {0x030e, 0x01}, ++ {0x030f, 0x30}, ++ {0x0310, 0x01}, ++ {0x4018, 0x00}, ++ {0x4019, 0x00}, ++ {0x401a, 0x00}, ++ {0x401b, 0x00}, ++ {0x3400, 0x01}, ++ {0x3092, 0x01}, ++ {0x3093, 0x00}, ++ {0x0350, 0x00}, ++ {0x3419, 0x00}, ++}; ++ ++/* 64 mpix 2.7fps */ ++static const struct arducam_64mp_reg mode_9152x6944_regs = { ++ {0x0342, 0xb6}, ++ {0x0343, 0xb2}, ++ {0x0340, 0x1b}, ++ {0x0341, 0x76}, ++ {0x0344, 0x00}, ++ {0x0345, 0x00}, ++ {0x0346, 0x00}, ++ {0x0347, 0x00}, ++ {0x0348, 0x24}, ++ {0x0349, 0x1f}, ++ {0x034a, 0x1b}, ++ {0x034b, 0x1f}, ++ {0x0900, 0x00}, ++ {0x0901, 0x11}, ++ {0x0902, 0x0a}, ++ {0x30d8, 0x00}, ++ {0x3200, 0x01}, ++ {0x3201, 0x01}, ++ {0x0408, 0x00}, ++ {0x0409, 0x00}, ++ {0x040a, 0x00}, ++ {0x040b, 0x00}, ++ {0x040c, 0x23}, ++ {0x040d, 0xc0}, ++ {0x040e, 0x1b}, ++ {0x040f, 0x20}, ++ {0x034c, 0x23}, ++ {0x034d, 0xc0}, ++ {0x034e, 0x1b}, ++ {0x034f, 0x20}, ++ {0x30d9, 0x01}, ++ {0x32d5, 0x01}, ++ {0x32d6, 0x00}, ++ {0x401e, 0x00}, ++ {0x40b8, 0x04}, ++ {0x40b9, 0x20}, ++ {0x40bc, 0x02}, ++ {0x40bd, 0x58}, ++ {0x40be, 0x02}, ++ {0x40bf, 0x58}, ++ {0x41a4, 0x00}, ++ {0x5a09, 0x01}, ++ {0x5a17, 0x01}, ++ {0x5a25, 0x01}, ++ {0x5a33, 0x01}, ++ {0x98d7, 0x14}, ++ {0x98d8, 0x14}, ++ {0x98d9, 0x00}, ++ {0x99c4, 0x00}, ++ {0x0202, 0x03}, ++ {0x0203, 0xe8}, ++ {0x0204, 0x00}, ++ {0x0205, 0x00}, ++ {0x020e, 0x01}, ++ {0x020f, 0x00}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x02}, ++ {0x341f, 0x3c}, ++ {0x3420, 0x02}, ++ {0x3421, 0x42}, ++}; ++ ++/* 48 mpix 3.0fps */ ++static const struct arducam_64mp_reg mode_8000x6000_regs = { ++ {0x0342, 0xb6}, ++ {0x0343, 0xb2}, ++ {0x0340, 0x19}, ++ {0x0341, 0x0e}, ++ {0x0344, 0x02}, ++ {0x0345, 0x70}, ++ {0x0346, 0x01}, ++ {0x0347, 0xd8}, ++ {0x0348, 0x21}, ++ {0x0349, 0xaf}, ++ {0x034a, 0x19}, ++ {0x034b, 0x47}, ++ {0x0900, 0x00}, ++ {0x0901, 0x11}, ++ {0x0902, 0x0a}, ++ {0x30d8, 0x00}, ++ {0x3200, 0x01}, ++ {0x3201, 0x01}, ++ {0x0408, 0x00}, ++ {0x0409, 0x00}, ++ {0x040a, 0x00}, ++ {0x040b, 0x00}, ++ {0x040c, 0x1f}, ++ {0x040d, 0x40}, ++ {0x040e, 0x17}, ++ {0x040f, 0x70}, ++ {0x034c, 0x1f}, ++ {0x034d, 0x40}, ++ {0x034e, 0x17}, ++ {0x034f, 0x70}, ++ {0x30d9, 0x01}, ++ {0x32d5, 0x01}, ++ {0x32d6, 0x00}, ++ {0x401e, 0x00}, ++ {0x40b8, 0x04}, ++ {0x40b9, 0x20}, ++ {0x40bc, 0x02}, ++ {0x40bd, 0x58}, ++ {0x40be, 0x02}, ++ {0x40bf, 0x58}, ++ {0x41a4, 0x00}, ++ {0x5a09, 0x01}, ++ {0x5a17, 0x01}, ++ {0x5a25, 0x01}, ++ {0x5a33, 0x01}, ++ {0x98d7, 0x14}, ++ {0x98d8, 0x14}, ++ {0x98d9, 0x00}, ++ {0x99c4, 0x00}, ++ {0x0202, 0x03}, ++ {0x0203, 0xe8}, ++ {0x0204, 0x00}, ++ {0x0205, 0x00}, ++ {0x020e, 0x01}, ++ {0x020f, 0x00}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x01}, ++ {0x341f, 0xf4}, ++ {0x3420, 0x01}, ++ {0x3421, 0xf4}, ++}; ++ ++/* 16 mpix 10fps */ ++static const struct arducam_64mp_reg mode_4624x3472_regs = { ++ {0x0342, 0x63}, ++ {0x0343, 0x97}, ++ {0x0340, 0x0d}, ++ {0x0341, 0xca}, ++ {0x0344, 0x00}, ++ {0x0345, 0x00}, ++ {0x0346, 0x00}, ++ {0x0347, 0x00}, ++ {0x0348, 0x24}, ++ {0x0349, 0x1f}, ++ {0x034a, 0x1b}, ++ {0x034b, 0x1f}, ++ {0x0900, 0x01}, ++ {0x0901, 0x22}, ++ {0x0902, 0x08}, ++ {0x30d8, 0x04}, ++ {0x3200, 0x41}, ++ {0x3201, 0x41}, ++ {0x0408, 0x00}, ++ {0x0409, 0x00}, ++ {0x040a, 0x00}, ++ {0x040b, 0x00}, ++ {0x040c, 0x12}, ++ {0x040d, 0x10}, ++ {0x040e, 0x0d}, ++ {0x040f, 0x90}, ++ {0x034c, 0x12}, ++ {0x034d, 0x10}, ++ {0x034e, 0x0d}, ++ {0x034f, 0x90}, ++ {0x30d9, 0x00}, ++ {0x32d5, 0x00}, ++ {0x32d6, 0x00}, ++ {0x401e, 0x00}, ++ {0x40b8, 0x01}, ++ {0x40b9, 0x2c}, ++ {0x40bc, 0x01}, ++ {0x40bd, 0x18}, ++ {0x40be, 0x00}, ++ {0x40bf, 0x00}, ++ {0x41a4, 0x00}, ++ {0x5a09, 0x01}, ++ {0x5a17, 0x01}, ++ {0x5a25, 0x01}, ++ {0x5a33, 0x01}, ++ {0x98d7, 0xb4}, ++ {0x98d8, 0x8c}, ++ {0x98d9, 0x0a}, ++ {0x99c4, 0x16}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x01}, ++ {0x341f, 0x21}, ++ {0x3420, 0x01}, ++ {0x3421, 0x21}, ++}; ++ ++/* 4k 20fps mode */ ++static const struct arducam_64mp_reg mode_3840x2160_regs = { ++ {0x0342, 0x4e}, ++ {0x0343, 0xb7}, ++ {0x0340, 0x08}, ++ {0x0341, 0xb9}, ++ {0x0344, 0x03}, ++ {0x0345, 0x10}, ++ {0x0346, 0x05}, ++ {0x0347, 0x20}, ++ {0x0348, 0x21}, ++ {0x0349, 0x0f}, ++ {0x034a, 0x15}, ++ {0x034b, 0xff}, ++ {0x0900, 0x01}, ++ {0x0901, 0x22}, ++ {0x0902, 0x08}, ++ {0x30d8, 0x04}, ++ {0x3200, 0x41}, ++ {0x3201, 0x41}, ++ {0x0408, 0x00}, ++ {0x0409, 0x00}, ++ {0x040a, 0x00}, ++ {0x040b, 0x00}, ++ {0x040c, 0x0f}, ++ {0x040d, 0x00}, ++ {0x040e, 0x08}, ++ {0x040f, 0x70}, ++ {0x034c, 0x0f}, ++ {0x034d, 0x00}, ++ {0x034e, 0x08}, ++ {0x034f, 0x70}, ++ {0x30d9, 0x00}, ++ {0x32d5, 0x00}, ++ {0x32d6, 0x00}, ++ {0x401e, 0x00}, ++ {0x40b8, 0x01}, ++ {0x40b9, 0x2c}, ++ {0x40bc, 0x01}, ++ {0x40bd, 0x18}, ++ {0x40be, 0x00}, ++ {0x40bf, 0x00}, ++ {0x41a4, 0x00}, ++ {0x5a09, 0x01}, ++ {0x5a17, 0x01}, ++ {0x5a25, 0x01}, ++ {0x5a33, 0x01}, ++ {0x98d7, 0xb4}, ++ {0x98d8, 0x8c}, ++ {0x98d9, 0x0a}, ++ {0x99c4, 0x16}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x00}, ++ {0x341f, 0xf0}, ++ {0x3420, 0x00}, ++ {0x3421, 0xb4}, ++}; ++ ++/* 4x4 binned 30fps mode */ ++static const struct arducam_64mp_reg mode_2312x1736_regs = { ++ {0x0342, 0x33}, ++ {0x0343, 0x60}, ++ {0x0340, 0x08}, ++ {0x0341, 0xe9}, ++ {0x0344, 0x00}, ++ {0x0345, 0x00}, ++ {0x0346, 0x00}, ++ {0x0347, 0x00}, ++ {0x0348, 0x24}, ++ {0x0349, 0x1f}, ++ {0x034a, 0x1b}, ++ {0x034b, 0x1f}, ++ {0x0900, 0x01}, ++ {0x0901, 0x44}, ++ {0x0902, 0x08}, ++ {0x30d8, 0x04}, ++ {0x3200, 0x43}, ++ {0x3201, 0x43}, ++ {0x0408, 0x00}, ++ {0x0409, 0x00}, ++ {0x040a, 0x00}, ++ {0x040b, 0x00}, ++ {0x040c, 0x09}, ++ {0x040d, 0x08}, ++ {0x040e, 0x06}, ++ {0x040f, 0xc8}, ++ {0x034c, 0x09}, ++ {0x034d, 0x08}, ++ {0x034e, 0x06}, ++ {0x034f, 0xc8}, ++ {0x30d9, 0x00}, ++ {0x32d5, 0x00}, ++ {0x32d6, 0x00}, ++ {0x401e, 0x00}, ++ {0x40b8, 0x01}, ++ {0x40b9, 0x2c}, ++ {0x40bc, 0x01}, ++ {0x40bd, 0x18}, ++ {0x40be, 0x00}, ++ {0x40bf, 0x00}, ++ {0x41a4, 0x00}, ++ {0x5a09, 0x01}, ++ {0x5a17, 0x01}, ++ {0x5a25, 0x01}, ++ {0x5a33, 0x01}, ++ {0x98d7, 0xb4}, ++ {0x98d8, 0x8c}, ++ {0x98d9, 0x0a}, ++ {0x99c4, 0x16}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x00}, ++ {0x341f, 0x90}, ++ {0x3420, 0x00}, ++ {0x3421, 0x90}, ++}; ++ ++/* 1080p 60fps mode */ ++static const struct arducam_64mp_reg mode_1920x1080_regs = { ++ {0x0342, 0x29}, ++ {0x0343, 0xe3}, ++ {0x0340, 0x05}, ++ {0x0341, 0x76}, ++ {0x0344, 0x03}, ++ {0x0345, 0x10}, ++ {0x0346, 0x05}, ++ {0x0347, 0x20}, ++ {0x0348, 0x21}, ++ {0x0349, 0x0f}, ++ {0x034a, 0x16}, ++ {0x034b, 0x0f}, ++ {0x0900, 0x01}, ++ {0x0901, 0x44}, ++ {0x0902, 0x08}, ++ {0x30d8, 0x04}, ++ {0x3200, 0x43}, ++ {0x3201, 0x43}, ++ {0x0408, 0x00}, ++ {0x0409, 0x00}, ++ {0x040a, 0x00}, ++ {0x040b, 0x00}, ++ {0x040c, 0x07}, ++ {0x040d, 0x80}, ++ {0x040e, 0x04}, ++ {0x040f, 0x38}, ++ {0x034c, 0x07}, ++ {0x034d, 0x80}, ++ {0x034e, 0x04}, ++ {0x034f, 0x38}, ++ {0x30d9, 0x00}, ++ {0x32d5, 0x00}, ++ {0x32d6, 0x00}, ++ {0x401e, 0x00}, ++ {0x40b8, 0x01}, ++ {0x40b9, 0x2c}, ++ {0x40bc, 0x01}, ++ {0x40bd, 0x18}, ++ {0x40be, 0x00}, ++ {0x40bf, 0x00}, ++ {0x41a4, 0x00}, ++ {0x5a09, 0x01}, ++ {0x5a17, 0x01}, ++ {0x5a25, 0x01}, ++ {0x5a33, 0x01}, ++ {0x98d7, 0xb4}, ++ {0x98d8, 0x8c}, ++ {0x98d9, 0x0a}, ++ {0x99c4, 0x16}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x00}, ++ {0x341f, 0x78}, ++ {0x3420, 0x00}, ++ {0x3421, 0x5a}, ++}; ++ ++/* 720p 120fps mode */ ++static const struct arducam_64mp_reg mode_1280x720_regs = { ++ {0x0342, 0x1b}, ++ {0x0343, 0x08}, ++ {0x0340, 0x04}, ++ {0x0341, 0x3b}, ++ {0x0344, 0x08}, ++ {0x0345, 0x10}, ++ {0x0346, 0x07}, ++ {0x0347, 0xf0}, ++ {0x0348, 0x1c}, ++ {0x0349, 0x0f}, ++ {0x034a, 0x13}, ++ {0x034b, 0x3f}, ++ {0x0900, 0x01}, ++ {0x0901, 0x44}, ++ {0x0902, 0x08}, ++ {0x30d8, 0x04}, ++ {0x3200, 0x43}, ++ {0x3201, 0x43}, ++ {0x0408, 0x00}, ++ {0x0409, 0x00}, ++ {0x040a, 0x00}, ++ {0x040b, 0x00}, ++ {0x040c, 0x05}, ++ {0x040d, 0x00}, ++ {0x040e, 0x02}, ++ {0x040f, 0xd0}, ++ {0x034c, 0x05}, ++ {0x034d, 0x00}, ++ {0x034e, 0x02}, ++ {0x034f, 0xd0}, ++ {0x30d9, 0x00}, ++ {0x32d5, 0x00}, ++ {0x32d6, 0x00}, ++ {0x401e, 0x00}, ++ {0x40b8, 0x01}, ++ {0x40b9, 0x2c}, ++ {0x40bc, 0x01}, ++ {0x40bd, 0x18}, ++ {0x40be, 0x00}, ++ {0x40bf, 0x00}, ++ {0x41a4, 0x00}, ++ {0x5a09, 0x01}, ++ {0x5a17, 0x01}, ++ {0x5a25, 0x01}, ++ {0x5a33, 0x01}, ++ {0x98d7, 0xb4}, ++ {0x98d8, 0x8c}, ++ {0x98d9, 0x0a}, ++ {0x99c4, 0x16}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x00}, ++ {0x341f, 0x50}, ++ {0x3420, 0x00}, ++ {0x3421, 0x3c}, ++}; ++ ++/* Mode configs */ ++static const struct arducam_64mp_mode supported_modes = { ++ { ++ .width = 9152, ++ .height = 6944, ++ .line_length_pix = 0xb6b2, ++ .crop = { ++ .left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT, ++ .top = ARDUCAM_64MP_PIXEL_ARRAY_TOP, ++ .width = 9248, ++ .height = 6944, ++ }, ++ .timeperframe_default = { ++ .numerator = 100, ++ .denominator = 270 ++ }, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_9152x6944_regs), ++ .regs = mode_9152x6944_regs, ++ } ++ }, { ++ .width = 8000, ++ .height = 6000, ++ .line_length_pix = 0xb6b2, ++ .crop = { ++ .left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT + 624, ++ .top = ARDUCAM_64MP_PIXEL_ARRAY_TOP + 472, ++ .width = 9248, ++ .height = 6944, ++ }, ++ .timeperframe_default = { ++ .numerator = 100, ++ .denominator = 300 ++ }, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_8000x6000_regs), ++ .regs = mode_8000x6000_regs, ++ } ++ }, { ++ .width = 4624, ++ .height = 3472, ++ .line_length_pix = 0x6397, ++ .crop = { ++ .left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT, ++ .top = ARDUCAM_64MP_PIXEL_ARRAY_TOP, ++ .width = 9248, ++ .height = 6944, ++ }, ++ .timeperframe_default = { ++ .numerator = 100, ++ .denominator = 1000 ++ }, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_4624x3472_regs), ++ .regs = mode_4624x3472_regs, ++ } ++ }, { ++ .width = 3840, ++ .height = 2160, ++ .line_length_pix = 0x4eb7, ++ .crop = { ++ .left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT + 784, ++ .top = ARDUCAM_64MP_PIXEL_ARRAY_TOP + 1312, ++ .width = 7680, ++ .height = 4320, ++ }, ++ .timeperframe_default = { ++ .numerator = 100, ++ .denominator = 2000 ++ }, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_3840x2160_regs), ++ .regs = mode_3840x2160_regs, ++ } ++ }, { ++ .width = 2312, ++ .height = 1736, ++ .line_length_pix = 0x3360, ++ .crop = { ++ .left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT, ++ .top = ARDUCAM_64MP_PIXEL_ARRAY_TOP, ++ .width = 9248, ++ .height = 6944, ++ }, ++ .timeperframe_default = { ++ .numerator = 100, ++ .denominator = 3000 ++ }, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_2312x1736_regs), ++ .regs = mode_2312x1736_regs, ++ } ++ }, { ++ .width = 1920, ++ .height = 1080, ++ .line_length_pix = 0x29e3, ++ .crop = { ++ .left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT + 784, ++ .top = ARDUCAM_64MP_PIXEL_ARRAY_TOP + 1312, ++ .width = 7680, ++ .height = 4320, ++ }, ++ .timeperframe_default = { ++ .numerator = 100, ++ .denominator = 6000 ++ }, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_1920x1080_regs), ++ .regs = mode_1920x1080_regs, ++ } ++ }, { ++ .width = 1280, ++ .height = 720, ++ .line_length_pix = 0x1b08, ++ .crop = { ++ .left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT + 2064, ++ .top = ARDUCAM_64MP_PIXEL_ARRAY_TOP + 2032, ++ .width = 5120, ++ .height = 2880, ++ }, ++ .timeperframe_default = { ++ .numerator = 100, ++ .denominator = 12000 ++ }, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_1280x720_regs), ++ .regs = mode_1280x720_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 = { ++ /* 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 arducam_64mp_test_pattern_menu = { ++ "Disabled", ++ "Color Bars", ++ "Solid Color", ++ "Grey Color Bars", ++ "PN9" ++}; ++ ++static const int arducam_64mp_test_pattern_val = { ++ ARDUCAM_64MP_TEST_PATTERN_DISABLE, ++ ARDUCAM_64MP_TEST_PATTERN_COLOR_BARS, ++ ARDUCAM_64MP_TEST_PATTERN_SOLID_COLOR, ++ ARDUCAM_64MP_TEST_PATTERN_GREY_COLOR, ++ ARDUCAM_64MP_TEST_PATTERN_PN9, ++}; ++ ++/* regulator supplies */ ++static const char * const arducam_64mp_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 ARDUCAM_64MP_NUM_SUPPLIES ARRAY_SIZE(arducam_64mp_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 7.7ms. 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 - 1ms. ++ */ ++#define ARDUCAM_64MP_XCLR_MIN_DELAY_US 8000 ++#define ARDUCAM_64MP_XCLR_DELAY_RANGE_US 1000 ++ ++struct arducam_64mp { ++ struct v4l2_subdev sd; ++ struct media_pad padNUM_PADS; ++ ++ unsigned int fmt_code; ++ ++ struct clk *xclk; ++ ++ struct gpio_desc *reset_gpio; ++ struct regulator_bulk_data suppliesARDUCAM_64MP_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 arducam_64mp_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; ++}; ++ ++static inline struct arducam_64mp *to_arducam_64mp(struct v4l2_subdev *_sd) ++{ ++ return container_of(_sd, struct arducam_64mp, sd); ++} ++ ++/* Read registers up to 2 at a time */ ++static int arducam_64mp_read_reg(struct i2c_client *client, ++ u16 reg, u32 len, u32 *val) ++{ ++ struct i2c_msg msgs2; ++ u8 addr_buf2 = { reg >> 8, reg & 0xff }; ++ u8 data_buf4 = { 0, }; ++ int ret; ++ ++ if (len > 4) ++ return -EINVAL; ++ ++ /* Write register address */ ++ msgs0.addr = client->addr; ++ msgs0.flags = 0; ++ msgs0.len = ARRAY_SIZE(addr_buf); ++ msgs0.buf = addr_buf; ++ ++ /* Read data from register */ ++ msgs1.addr = client->addr; ++ msgs1.flags = I2C_M_RD; ++ msgs1.len = len; ++ msgs1.buf = &data_buf4 - 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 arducam_64mp_write_reg(struct arducam_64mp *arducam_64mp, ++ u16 reg, u32 len, u32 val) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&arducam_64mp->sd); ++ u8 buf6; ++ ++ 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 arducam_64mp_write_regs(struct arducam_64mp *arducam_64mp, ++ const struct arducam_64mp_reg *regs, u32 len) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&arducam_64mp->sd); ++ unsigned int i; ++ int ret; ++ ++ for (i = 0; i < len; i++) { ++ ret = arducam_64mp_write_reg(arducam_64mp, regsi.address, 1, ++ regsi.val); ++ if (ret) { ++ dev_err_ratelimited(&client->dev, ++ "Failed to write reg 0x%4.4x. error = %d\n", ++ regsi.address, ret); ++ ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++/* Get bayer order based on flip setting. */ ++static u32 arducam_64mp_get_format_code(struct arducam_64mp *arducam_64mp) ++{ ++ unsigned int i; ++ ++ lockdep_assert_held(&arducam_64mp->mutex); ++ ++ i = (arducam_64mp->vflip->val ? 2 : 0) | ++ (arducam_64mp->hflip->val ? 1 : 0); ++ ++ return codesi; ++} ++ ++static int arducam_64mp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) ++{ ++ struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd); ++ struct v4l2_mbus_framefmt *try_fmt_img = ++ v4l2_subdev_get_try_format(sd, fh->state, IMAGE_PAD); ++ struct v4l2_mbus_framefmt *try_fmt_meta = ++ v4l2_subdev_get_try_format(sd, fh->state, METADATA_PAD); ++ struct v4l2_rect *try_crop; ++ ++ mutex_lock(&arducam_64mp->mutex); ++ ++ /* Initialize try_fmt for the image pad */ ++ try_fmt_img->width = supported_modes0.width; ++ try_fmt_img->height = supported_modes0.height; ++ try_fmt_img->code = arducam_64mp_get_format_code(arducam_64mp); ++ try_fmt_img->field = V4L2_FIELD_NONE; ++ ++ /* Initialize try_fmt for the embedded metadata pad */ ++ try_fmt_meta->width = ARDUCAM_64MP_EMBEDDED_LINE_WIDTH; ++ try_fmt_meta->height = ARDUCAM_64MP_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->state, IMAGE_PAD); ++ try_crop->left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT; ++ try_crop->top = ARDUCAM_64MP_PIXEL_ARRAY_TOP; ++ try_crop->width = ARDUCAM_64MP_PIXEL_ARRAY_WIDTH; ++ try_crop->height = ARDUCAM_64MP_PIXEL_ARRAY_HEIGHT; ++ ++ mutex_unlock(&arducam_64mp->mutex); ++ ++ return 0; ++} ++ ++static void ++arducam_64mp_adjust_exposure_range(struct arducam_64mp *arducam_64mp) ++{ ++ int exposure_max, exposure_def; ++ ++ /* Honour the VBLANK limits when setting exposure. */ ++ exposure_max = arducam_64mp->mode->height + arducam_64mp->vblank->val - ++ ARDUCAM_64MP_EXPOSURE_OFFSET; ++ exposure_def = min(exposure_max, arducam_64mp->exposure->val); ++ __v4l2_ctrl_modify_range(arducam_64mp->exposure, ++ arducam_64mp->exposure->minimum, ++ exposure_max, arducam_64mp->exposure->step, ++ exposure_def); ++} ++ ++static int arducam_64mp_set_frame_length(struct arducam_64mp *arducam_64mp, ++ unsigned int vblank) ++{ ++ unsigned int val = vblank + arducam_64mp->mode->height; ++ int ret = 0; ++ ++ arducam_64mp->long_exp_shift = 0; ++ ++ while (val > ARDUCAM_64MP_FRAME_LENGTH_MAX) { ++ arducam_64mp->long_exp_shift++; ++ val >>= 1; ++ } ++ ++ ret = arducam_64mp_write_reg(arducam_64mp, ++ ARDUCAM_64MP_REG_FRAME_LENGTH, ++ ARDUCAM_64MP_REG_VALUE_16BIT, val); ++ if (ret) ++ return ret; ++ ++ return arducam_64mp_write_reg(arducam_64mp, ++ ARDUCAM_64MP_LONG_EXP_SHIFT_REG, ++ ARDUCAM_64MP_REG_VALUE_08BIT, ++ arducam_64mp->long_exp_shift); ++} ++ ++static int arducam_64mp_set_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct arducam_64mp *arducam_64mp = ++ container_of(ctrl->handler, struct arducam_64mp, ctrl_handler); ++ struct i2c_client *client = v4l2_get_subdevdata(&arducam_64mp->sd); ++ int ret; ++ u32 val; ++ /* ++ * The VBLANK control may change the limits of usable exposure, so check ++ * and adjust if necessary. ++ */ ++ if (ctrl->id == V4L2_CID_VBLANK) ++ arducam_64mp_adjust_exposure_range(arducam_64mp); ++ ++ /* ++ * 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 = arducam_64mp_write_reg(arducam_64mp, ++ ARDUCAM_64MP_REG_ANALOG_GAIN, ++ ARDUCAM_64MP_REG_VALUE_16BIT, ++ ctrl->val); ++ break; ++ case V4L2_CID_EXPOSURE: ++ val = ctrl->val >> arducam_64mp->long_exp_shift; ++ ret = arducam_64mp_write_reg(arducam_64mp, ++ ARDUCAM_64MP_REG_EXPOSURE, ++ ARDUCAM_64MP_REG_VALUE_16BIT, ++ val); ++ break; ++ case V4L2_CID_DIGITAL_GAIN: ++ ret = arducam_64mp_write_reg(arducam_64mp, ++ ARDUCAM_64MP_REG_DIGITAL_GAIN, ++ ARDUCAM_64MP_REG_VALUE_16BIT, ++ ctrl->val); ++ break; ++ case V4L2_CID_TEST_PATTERN: ++ val = arducam_64mp_test_pattern_valctrl->val; ++ ret = arducam_64mp_write_reg(arducam_64mp, ++ ARDUCAM_64MP_REG_TEST_PATTERN, ++ ARDUCAM_64MP_REG_VALUE_16BIT, ++ val); ++ break; ++ case V4L2_CID_TEST_PATTERN_RED: ++ ret = arducam_64mp_write_reg(arducam_64mp, ++ ARDUCAM_64MP_REG_TEST_PATTERN_R, ++ ARDUCAM_64MP_REG_VALUE_16BIT, ++ ctrl->val); ++ break; ++ case V4L2_CID_TEST_PATTERN_GREENR: ++ ret = arducam_64mp_write_reg(arducam_64mp, ++ ARDUCAM_64MP_REG_TEST_PATTERN_GR, ++ ARDUCAM_64MP_REG_VALUE_16BIT, ++ ctrl->val); ++ break; ++ case V4L2_CID_TEST_PATTERN_BLUE: ++ ret = arducam_64mp_write_reg(arducam_64mp, ++ ARDUCAM_64MP_REG_TEST_PATTERN_B, ++ ARDUCAM_64MP_REG_VALUE_16BIT, ++ ctrl->val); ++ break; ++ case V4L2_CID_TEST_PATTERN_GREENB: ++ ret = arducam_64mp_write_reg(arducam_64mp, ++ ARDUCAM_64MP_REG_TEST_PATTERN_GB, ++ ARDUCAM_64MP_REG_VALUE_16BIT, ++ ctrl->val); ++ break; ++ case V4L2_CID_HFLIP: ++ case V4L2_CID_VFLIP: ++ ret = arducam_64mp_write_reg(arducam_64mp, ++ ARDUCAM_64MP_REG_ORIENTATION, 1, ++ arducam_64mp->hflip->val | ++ arducam_64mp->vflip->val << 1); ++ break; ++ case V4L2_CID_VBLANK: ++ ret = arducam_64mp_set_frame_length(arducam_64mp, 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 arducam_64mp_ctrl_ops = { ++ .s_ctrl = arducam_64mp_set_ctrl, ++}; ++ ++static int arducam_64mp_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd); ++ ++ if (code->pad >= NUM_PADS) ++ return -EINVAL; ++ ++ if (code->pad == IMAGE_PAD) { ++ if (code->index > 0) ++ return -EINVAL; ++ ++ code->code = arducam_64mp_get_format_code(arducam_64mp); ++ } else { ++ if (code->index > 0) ++ return -EINVAL; ++ ++ code->code = MEDIA_BUS_FMT_SENSOR_DATA; ++ } ++ ++ return 0; ++} ++ ++static int arducam_64mp_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd); ++ ++ if (fse->pad >= NUM_PADS) ++ return -EINVAL; ++ ++ if (fse->pad == IMAGE_PAD) { ++ if (fse->index >= ARRAY_SIZE(supported_modes)) ++ return -EINVAL; ++ ++ if (fse->code != arducam_64mp_get_format_code(arducam_64mp)) ++ return -EINVAL; ++ ++ fse->min_width = supported_modesfse->index.width; ++ fse->max_width = fse->min_width; ++ fse->min_height = supported_modesfse->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 = ARDUCAM_64MP_EMBEDDED_LINE_WIDTH; ++ fse->max_width = fse->min_width; ++ fse->min_height = ARDUCAM_64MP_NUM_EMBEDDED_LINES; ++ fse->max_height = fse->min_height; ++ } ++ ++ return 0; ++} ++ ++static void arducam_64mp_reset_colorspace(struct v4l2_mbus_framefmt *fmt) ++{ ++ fmt->colorspace = V4L2_COLORSPACE_RAW; ++ 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 ++arducam_64mp_update_image_pad_format(struct arducam_64mp *arducam_64mp, ++ const struct arducam_64mp_mode *mode, ++ struct v4l2_subdev_format *fmt) ++{ ++ fmt->format.width = mode->width; ++ fmt->format.height = mode->height; ++ fmt->format.field = V4L2_FIELD_NONE; ++ arducam_64mp_reset_colorspace(&fmt->format); ++} ++ ++static void ++arducam_64mp_update_metadata_pad_format(struct v4l2_subdev_format *fmt) ++{ ++ fmt->format.width = ARDUCAM_64MP_EMBEDDED_LINE_WIDTH; ++ fmt->format.height = ARDUCAM_64MP_NUM_EMBEDDED_LINES; ++ fmt->format.code = MEDIA_BUS_FMT_SENSOR_DATA; ++ fmt->format.field = V4L2_FIELD_NONE; ++} ++ ++static int arducam_64mp_get_pad_format(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd); ++ ++ if (fmt->pad >= NUM_PADS) ++ return -EINVAL; ++ ++ mutex_lock(&arducam_64mp->mutex); ++ ++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { ++ struct v4l2_mbus_framefmt *try_fmt = ++ v4l2_subdev_get_try_format(&arducam_64mp->sd, sd_state, ++ fmt->pad); ++ /* update the code which could change due to vflip or hflip: */ ++ try_fmt->code = fmt->pad == IMAGE_PAD ? ++ arducam_64mp_get_format_code(arducam_64mp) : ++ MEDIA_BUS_FMT_SENSOR_DATA; ++ fmt->format = *try_fmt; ++ } else { ++ if (fmt->pad == IMAGE_PAD) { ++ arducam_64mp_update_image_pad_format(arducam_64mp, ++ arducam_64mp->mode, ++ fmt); ++ fmt->format.code = ++ arducam_64mp_get_format_code(arducam_64mp); ++ } else { ++ arducam_64mp_update_metadata_pad_format(fmt); ++ } ++ } ++ ++ mutex_unlock(&arducam_64mp->mutex); ++ return 0; ++} ++ ++static unsigned int ++arducam_64mp_get_frame_length(const struct arducam_64mp_mode *mode, ++ const struct v4l2_fract *timeperframe) ++{ ++ u64 frame_length; ++ ++ frame_length = (u64)timeperframe->numerator * ARDUCAM_64MP_PIXEL_RATE; ++ do_div(frame_length, ++ (u64)timeperframe->denominator * mode->line_length_pix); ++ ++ if (WARN_ON(frame_length > ARDUCAM_64MP_FRAME_LENGTH_MAX)) ++ frame_length = ARDUCAM_64MP_FRAME_LENGTH_MAX; ++ ++ return max_t(unsigned int, frame_length, mode->height); ++} ++ ++static void arducam_64mp_set_framing_limits(struct arducam_64mp *arducam_64mp) ++{ ++ unsigned int frm_length_min, frm_length_default, hblank; ++ const struct arducam_64mp_mode *mode = arducam_64mp->mode; ++ ++ /* The default framerate is highest possible framerate. */ ++ frm_length_min = ++ arducam_64mp_get_frame_length(mode, ++ &mode->timeperframe_default); ++ frm_length_default = ++ arducam_64mp_get_frame_length(mode, ++ &mode->timeperframe_default); ++ ++ /* Default to no long exposure multiplier. */ ++ arducam_64mp->long_exp_shift = 0; ++ ++ /* Update limits and set FPS to default */ ++ __v4l2_ctrl_modify_range(arducam_64mp->vblank, ++ frm_length_min - mode->height, ++ ((1 << ARDUCAM_64MP_LONG_EXP_SHIFT_MAX) * ++ ARDUCAM_64MP_FRAME_LENGTH_MAX) - mode->height, ++ 1, frm_length_default - mode->height); ++ ++ /* Setting this will adjust the exposure limits as well. */ ++ __v4l2_ctrl_s_ctrl(arducam_64mp->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(arducam_64mp->hblank, hblank, hblank, 1, ++ hblank); ++} ++ ++static int arducam_64mp_set_pad_format(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct v4l2_mbus_framefmt *framefmt; ++ const struct arducam_64mp_mode *mode; ++ struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd); ++ ++ if (fmt->pad >= NUM_PADS) ++ return -EINVAL; ++ ++ mutex_lock(&arducam_64mp->mutex); ++ ++ if (fmt->pad == IMAGE_PAD) { ++ /* Bayer order varies with flips */ ++ fmt->format.code = arducam_64mp_get_format_code(arducam_64mp); ++ ++ mode = v4l2_find_nearest_size(supported_modes, ++ ARRAY_SIZE(supported_modes), ++ width, height, ++ fmt->format.width, ++ fmt->format.height); ++ arducam_64mp_update_image_pad_format(arducam_64mp, mode, fmt); ++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { ++ framefmt = v4l2_subdev_get_try_format(sd, sd_state, ++ fmt->pad); ++ *framefmt = fmt->format; ++ } else { ++ arducam_64mp->mode = mode; ++ arducam_64mp->fmt_code = fmt->format.code; ++ arducam_64mp_set_framing_limits(arducam_64mp); ++ } ++ } else { ++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { ++ framefmt = v4l2_subdev_get_try_format(sd, sd_state, ++ fmt->pad); ++ *framefmt = fmt->format; ++ } else { ++ /* Only one embedded data mode is supported */ ++ arducam_64mp_update_metadata_pad_format(fmt); ++ } ++ } ++ ++ mutex_unlock(&arducam_64mp->mutex); ++ ++ return 0; ++} ++ ++static const struct v4l2_rect * ++__arducam_64mp_get_pad_crop(struct arducam_64mp *arducam_64mp, ++ struct v4l2_subdev_state *sd_state, ++ unsigned int pad, ++ enum v4l2_subdev_format_whence which) ++{ ++ switch (which) { ++ case V4L2_SUBDEV_FORMAT_TRY: ++ return v4l2_subdev_get_try_crop(&arducam_64mp->sd, sd_state, ++ pad); ++ case V4L2_SUBDEV_FORMAT_ACTIVE: ++ return &arducam_64mp->mode->crop; ++ } ++ ++ return NULL; ++} ++ ++static int arducam_64mp_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_selection *sel) ++{ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP: { ++ struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd); ++ ++ mutex_lock(&arducam_64mp->mutex); ++ sel->r = *__arducam_64mp_get_pad_crop(arducam_64mp, sd_state, ++ sel->pad, sel->which); ++ mutex_unlock(&arducam_64mp->mutex); ++ ++ return 0; ++ } ++ ++ case V4L2_SEL_TGT_NATIVE_SIZE: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = ARDUCAM_64MP_NATIVE_WIDTH; ++ sel->r.height = ARDUCAM_64MP_NATIVE_HEIGHT; ++ ++ return 0; ++ ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT; ++ sel->r.top = ARDUCAM_64MP_PIXEL_ARRAY_TOP; ++ sel->r.width = ARDUCAM_64MP_PIXEL_ARRAY_WIDTH; ++ sel->r.height = ARDUCAM_64MP_PIXEL_ARRAY_HEIGHT; ++ ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++/* Start streaming */ ++static int arducam_64mp_start_streaming(struct arducam_64mp *arducam_64mp) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&arducam_64mp->sd); ++ const struct arducam_64mp_reg_list *reg_list; ++ int ret; ++ ++ if (!arducam_64mp->common_regs_written) { ++ ret = arducam_64mp_write_regs(arducam_64mp, mode_common_regs, ++ ARRAY_SIZE(mode_common_regs)); ++ ++ if (ret) { ++ dev_err(&client->dev, "%s failed to set common settings\n", ++ __func__); ++ return ret; ++ } ++ arducam_64mp->common_regs_written = true; ++ } ++ ++ /* Apply default values of current mode */ ++ reg_list = &arducam_64mp->mode->reg_list; ++ ret = arducam_64mp_write_regs(arducam_64mp, 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(arducam_64mp->sd.ctrl_handler); ++ if (ret) ++ return ret; ++ ++ /* set stream on register */ ++ return arducam_64mp_write_reg(arducam_64mp, ++ ARDUCAM_64MP_REG_MODE_SELECT, ++ ARDUCAM_64MP_REG_VALUE_08BIT, ++ ARDUCAM_64MP_MODE_STREAMING); ++} ++ ++/* Stop streaming */ ++static void arducam_64mp_stop_streaming(struct arducam_64mp *arducam_64mp) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&arducam_64mp->sd); ++ int ret; ++ ++ /* set stream off register */ ++ ret = arducam_64mp_write_reg(arducam_64mp, ARDUCAM_64MP_REG_MODE_SELECT, ++ ARDUCAM_64MP_REG_VALUE_08BIT, ++ ARDUCAM_64MP_MODE_STANDBY); ++ if (ret) ++ dev_err(&client->dev, "%s failed to set stream\n", __func__); ++} ++ ++static int arducam_64mp_set_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret = 0; ++ ++ mutex_lock(&arducam_64mp->mutex); ++ if (arducam_64mp->streaming == enable) { ++ mutex_unlock(&arducam_64mp->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 = arducam_64mp_start_streaming(arducam_64mp); ++ if (ret) ++ goto err_rpm_put; ++ } else { ++ arducam_64mp_stop_streaming(arducam_64mp); ++ pm_runtime_put(&client->dev); ++ } ++ ++ arducam_64mp->streaming = enable; ++ ++ /* vflip and hflip cannot change during streaming */ ++ __v4l2_ctrl_grab(arducam_64mp->vflip, enable); ++ __v4l2_ctrl_grab(arducam_64mp->hflip, enable); ++ ++ mutex_unlock(&arducam_64mp->mutex); ++ ++ return ret; ++ ++err_rpm_put: ++ pm_runtime_put(&client->dev); ++err_unlock: ++ mutex_unlock(&arducam_64mp->mutex); ++ ++ return ret; ++} ++ ++/* Power/clock management functions */ ++static int arducam_64mp_power_on(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd); ++ int ret; ++ ++ ret = regulator_bulk_enable(ARDUCAM_64MP_NUM_SUPPLIES, ++ arducam_64mp->supplies); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to enable regulators\n", ++ __func__); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(arducam_64mp->xclk); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to enable clock\n", ++ __func__); ++ goto reg_off; ++ } ++ ++ gpiod_set_value_cansleep(arducam_64mp->reset_gpio, 1); ++ usleep_range(ARDUCAM_64MP_XCLR_MIN_DELAY_US, ++ ARDUCAM_64MP_XCLR_MIN_DELAY_US + ++ ARDUCAM_64MP_XCLR_DELAY_RANGE_US); ++ ++ return 0; ++ ++reg_off: ++ regulator_bulk_disable(ARDUCAM_64MP_NUM_SUPPLIES, ++ arducam_64mp->supplies); ++ return ret; ++} ++ ++static int arducam_64mp_power_off(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd); ++ ++ gpiod_set_value_cansleep(arducam_64mp->reset_gpio, 0); ++ regulator_bulk_disable(ARDUCAM_64MP_NUM_SUPPLIES, ++ arducam_64mp->supplies); ++ clk_disable_unprepare(arducam_64mp->xclk); ++ ++ /* Force reprogramming of the common registers when powered up again. */ ++ arducam_64mp->common_regs_written = false; ++ ++ return 0; ++} ++ ++static int __maybe_unused arducam_64mp_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd); ++ ++ if (arducam_64mp->streaming) ++ arducam_64mp_stop_streaming(arducam_64mp); ++ ++ return 0; ++} ++ ++static int __maybe_unused arducam_64mp_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd); ++ int ret; ++ ++ if (arducam_64mp->streaming) { ++ ret = arducam_64mp_start_streaming(arducam_64mp); ++ if (ret) ++ goto error; ++ } ++ ++ return 0; ++ ++error: ++ arducam_64mp_stop_streaming(arducam_64mp); ++ arducam_64mp->streaming = 0; ++ return ret; ++} ++ ++static int arducam_64mp_get_regulators(struct arducam_64mp *arducam_64mp) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&arducam_64mp->sd); ++ unsigned int i; ++ ++ for (i = 0; i < ARDUCAM_64MP_NUM_SUPPLIES; i++) ++ arducam_64mp->suppliesi.supply = arducam_64mp_supply_namei; ++ ++ return devm_regulator_bulk_get(&client->dev, ++ ARDUCAM_64MP_NUM_SUPPLIES, ++ arducam_64mp->supplies); ++} ++ ++/* Verify chip ID */ ++static int arducam_64mp_identify_module(struct arducam_64mp *arducam_64mp) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&arducam_64mp->sd); ++ struct i2c_client *arducam_identifier; ++ int ret; ++ u32 val; ++ ++ arducam_identifier = i2c_new_dummy_device(client->adapter, 0x50); ++ if (IS_ERR(arducam_identifier)) { ++ dev_err(&client->dev, "failed to create arducam_identifier\n"); ++ return PTR_ERR(arducam_identifier); ++ } ++ ++ ret = arducam_64mp_read_reg(arducam_identifier, ++ ARDUCAM_64MP_REG_CHIP_ID, ++ ARDUCAM_64MP_REG_VALUE_16BIT, &val); ++ if (ret) { ++ dev_err(&client->dev, "failed to read chip id %x, with error %d\n", ++ ARDUCAM_64MP_CHIP_ID, ret); ++ goto error; ++ } ++ ++ if (val != ARDUCAM_64MP_CHIP_ID) { ++ dev_err(&client->dev, "chip id mismatch: %x!=%x\n", ++ ARDUCAM_64MP_CHIP_ID, val); ++ ret = -EIO; ++ goto error; ++ } ++ ++ dev_info(&client->dev, "Device found Arducam 64MP.\n"); ++ ++error: ++ i2c_unregister_device(arducam_identifier); ++ ++ return ret; ++} ++ ++static const struct v4l2_subdev_core_ops arducam_64mp_core_ops = { ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++}; ++ ++static const struct v4l2_subdev_video_ops arducam_64mp_video_ops = { ++ .s_stream = arducam_64mp_set_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops arducam_64mp_pad_ops = { ++ .enum_mbus_code = arducam_64mp_enum_mbus_code, ++ .get_fmt = arducam_64mp_get_pad_format, ++ .set_fmt = arducam_64mp_set_pad_format, ++ .get_selection = arducam_64mp_get_selection, ++ .enum_frame_size = arducam_64mp_enum_frame_size, ++}; ++ ++static const struct v4l2_subdev_ops arducam_64mp_subdev_ops = { ++ .core = &arducam_64mp_core_ops, ++ .video = &arducam_64mp_video_ops, ++ .pad = &arducam_64mp_pad_ops, ++}; ++ ++static const struct v4l2_subdev_internal_ops arducam_64mp_internal_ops = { ++ .open = arducam_64mp_open, ++}; ++ ++/* Initialize control handlers */ ++static int arducam_64mp_init_controls(struct arducam_64mp *arducam_64mp) ++{ ++ struct v4l2_ctrl_handler *ctrl_hdlr; ++ struct i2c_client *client = v4l2_get_subdevdata(&arducam_64mp->sd); ++ struct v4l2_fwnode_device_properties props; ++ struct v4l2_ctrl *link_freq; ++ unsigned int i; ++ int ret; ++ u8 test_pattern_max; ++ u8 link_freq_max; ++ ++ ctrl_hdlr = &arducam_64mp->ctrl_handler; ++ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 16); ++ if (ret) ++ return ret; ++ ++ mutex_init(&arducam_64mp->mutex); ++ ctrl_hdlr->lock = &arducam_64mp->mutex; ++ ++ /* By default, PIXEL_RATE is read only */ ++ arducam_64mp->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, ++ &arducam_64mp_ctrl_ops, ++ V4L2_CID_PIXEL_RATE, ++ ARDUCAM_64MP_PIXEL_RATE, ++ ARDUCAM_64MP_PIXEL_RATE, 1, ++ ARDUCAM_64MP_PIXEL_RATE); ++ ++ /* LINK_FREQ is also read only */ ++ link_freq_max = ARRAY_SIZE(arducam_64mp_link_freq_menu) - 1; ++ link_freq = ++ v4l2_ctrl_new_int_menu(ctrl_hdlr, &arducam_64mp_ctrl_ops, ++ V4L2_CID_LINK_FREQ, ++ link_freq_max, 0, ++ arducam_64mp_link_freq_menu); ++ if (link_freq) ++ link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ ++ /* ++ * Create the controls here, but mode specific limits are setup ++ * in the arducam_64mp_set_framing_limits() call below. ++ */ ++ arducam_64mp->vblank = v4l2_ctrl_new_std(ctrl_hdlr, ++ &arducam_64mp_ctrl_ops, ++ V4L2_CID_VBLANK, ++ 0, 0xffff, 1, 0); ++ arducam_64mp->hblank = v4l2_ctrl_new_std(ctrl_hdlr, ++ &arducam_64mp_ctrl_ops, ++ V4L2_CID_HBLANK, ++ 0, 0xffff, 1, 0); ++ ++ /* HBLANK is read-only, but does change with mode. */ ++ if (arducam_64mp->hblank) ++ arducam_64mp->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ ++ arducam_64mp->exposure = ++ v4l2_ctrl_new_std(ctrl_hdlr, ++ &arducam_64mp_ctrl_ops, ++ V4L2_CID_EXPOSURE, ++ ARDUCAM_64MP_EXPOSURE_MIN, ++ ARDUCAM_64MP_EXPOSURE_MAX, ++ ARDUCAM_64MP_EXPOSURE_STEP, ++ ARDUCAM_64MP_EXPOSURE_DEFAULT); ++ ++ v4l2_ctrl_new_std(ctrl_hdlr, &arducam_64mp_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, ARDUCAM_64MP_ANA_GAIN_MIN, ++ ARDUCAM_64MP_ANA_GAIN_MAX, ARDUCAM_64MP_ANA_GAIN_STEP, ++ ARDUCAM_64MP_ANA_GAIN_DEFAULT); ++ ++ v4l2_ctrl_new_std(ctrl_hdlr, &arducam_64mp_ctrl_ops, ++ V4L2_CID_DIGITAL_GAIN, ARDUCAM_64MP_DGTL_GAIN_MIN, ++ ARDUCAM_64MP_DGTL_GAIN_MAX, ++ ARDUCAM_64MP_DGTL_GAIN_STEP, ++ ARDUCAM_64MP_DGTL_GAIN_DEFAULT); ++ ++ arducam_64mp->hflip = v4l2_ctrl_new_std(ctrl_hdlr, ++ &arducam_64mp_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ if (arducam_64mp->hflip) ++ arducam_64mp->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ arducam_64mp->vflip = v4l2_ctrl_new_std(ctrl_hdlr, ++ &arducam_64mp_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ if (arducam_64mp->vflip) ++ arducam_64mp->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ test_pattern_max = ARRAY_SIZE(arducam_64mp_test_pattern_menu) - 1; ++ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &arducam_64mp_ctrl_ops, ++ V4L2_CID_TEST_PATTERN, ++ test_pattern_max, ++ 0, 0, arducam_64mp_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, &arducam_64mp_ctrl_ops, ++ V4L2_CID_TEST_PATTERN_RED + i, ++ ARDUCAM_64MP_TEST_PATTERN_COLOUR_MIN, ++ ARDUCAM_64MP_TEST_PATTERN_COLOUR_MAX, ++ ARDUCAM_64MP_TEST_PATTERN_COLOUR_STEP, ++ ARDUCAM_64MP_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, &arducam_64mp_ctrl_ops, ++ &props); ++ if (ret) ++ goto error; ++ ++ arducam_64mp->sd.ctrl_handler = ctrl_hdlr; ++ ++ /* Setup exposure and frame/line length limits. */ ++ arducam_64mp_set_framing_limits(arducam_64mp); ++ ++ return 0; ++ ++error: ++ v4l2_ctrl_handler_free(ctrl_hdlr); ++ mutex_destroy(&arducam_64mp->mutex); ++ ++ return ret; +} + - static void armctrl_mask_irq(struct irq_data *d) - { -- writel_relaxed(HWIRQ_BIT(d->hwirq), intc.disableHWIRQ_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.disableHWIRQ_BANK(d->hwirq)); - } - - static void armctrl_unmask_irq(struct irq_data *d) - { -- writel_relaxed(HWIRQ_BIT(d->hwirq), intc.enableHWIRQ_BANK(d->hwirq)); -+ if (d->hwirq >= NUMBER_IRQS) { -+ if (num_online_cpus() > 1) { -+ unsigned int data; ++static void arducam_64mp_free_controls(struct arducam_64mp *arducam_64mp) ++{ ++ v4l2_ctrl_handler_free(arducam_64mp->sd.ctrl_handler); ++ mutex_destroy(&arducam_64mp->mutex); ++} + -+ if (!intc.local_base) { -+ pr_err("FIQ is disabled due to missing arm_local_intc\n"); -+ return; -+ } ++static int arducam_64mp_check_hwcfg(struct device *dev) ++{ ++ struct fwnode_handle *endpoint; ++ struct v4l2_fwnode_endpoint ep_cfg = { ++ .bus_type = V4L2_MBUS_CSI2_DPHY ++ }; ++ int ret = -EINVAL; + -+ data = readl_relaxed(intc.local_base + -+ ARM_LOCAL_GPU_INT_ROUTING); ++ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); ++ if (!endpoint) { ++ dev_err(dev, "endpoint node not found\n"); ++ return -EINVAL; ++ } + -+ data &= ~0xc; -+ data |= (1 << 2); -+ writel_relaxed(data, -+ intc.local_base + -+ ARM_LOCAL_GPU_INT_ROUTING); -+ } ++ if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) { ++ dev_err(dev, "could not parse endpoint\n"); ++ goto error_out; ++ } + -+ writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq), -+ intc.base + REG_FIQ_CONTROL); -+ } else { -+ writel_relaxed(HWIRQ_BIT(d->hwirq), -+ intc.enableHWIRQ_BANK(d->hwirq)); ++ /* 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_frequencies0 != ARDUCAM_64MP_DEFAULT_LINK_FREQ) { ++ dev_err(dev, "Link frequency not supported: %lld\n", ++ ep_cfg.link_frequencies0); ++ goto error_out; + } ++ ++ ret = 0; ++ ++error_out: ++ v4l2_fwnode_endpoint_free(&ep_cfg); ++ fwnode_handle_put(endpoint); ++ ++ return ret; +} + -+#ifdef CONFIG_ARM64 -+void bcm2836_arm_irqchip_spin_gpu_irq(void); ++static const struct of_device_id arducam_64mp_dt_ids = { ++ { .compatible = "arducam,64mp"}, ++ { /* sentinel */ } ++}; + -+static void armctrl_ack_irq(struct irq_data *d) ++static int arducam_64mp_probe(struct i2c_client *client) +{ -+ bcm2836_arm_irqchip_spin_gpu_irq(); - } - -+#endif ++ struct device *dev = &client->dev; ++ struct arducam_64mp *arducam_64mp; ++ const struct of_device_id *match; ++ u32 xclk_freq; ++ int ret; + - 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, -@@ -135,15 +201,16 @@ static int __init armctrl_of_init(struct device_node *node, - 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); - -@@ -174,6 +241,8 @@ static int __init armctrl_of_init(struct device_node *node, - pr_err(FW_BUG "Bootloader left fiq enabled\n"); - } - -+ last_irq = irq; ++ arducam_64mp = devm_kzalloc(&client->dev, sizeof(*arducam_64mp), ++ GFP_KERNEL); ++ if (!arducam_64mp) ++ return -ENOMEM; + - if (is_2836) { - int parent_irq = irq_of_parse_and_map(node, 0); - -@@ -186,6 +255,27 @@ static int __init armctrl_of_init(struct device_node *node, - 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"); ++ v4l2_i2c_subdev_init(&arducam_64mp->sd, client, ++ &arducam_64mp_subdev_ops); ++ ++ match = of_match_device(arducam_64mp_dt_ids, dev); ++ if (!match) ++ return -ENODEV; ++ ++ /* Check the hardware configuration in device tree */ ++ if (arducam_64mp_check_hwcfg(dev)) ++ return -EINVAL; ++ ++ /* Get system clock (xclk) */ ++ arducam_64mp->xclk = devm_clk_get(dev, NULL); ++ if (IS_ERR(arducam_64mp->xclk)) { ++ dev_err(dev, "failed to get xclk\n"); ++ return PTR_ERR(arducam_64mp->xclk); + } + -+ /* Make a duplicate irq range which is used to enable FIQ */ -+ for (b = 0; b < NR_BANKS; b++) { -+ for (i = 0; i < bank_irqsb; 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); -+ } ++ xclk_freq = clk_get_rate(arducam_64mp->xclk); ++ if (xclk_freq != ARDUCAM_64MP_XCLK_FREQ) { ++ dev_err(dev, "xclk frequency not supported: %d Hz\n", ++ xclk_freq); ++ return -EINVAL; + } -+#ifndef CONFIG_ARM64 -+ init_FIQ(irq - last_irq); -+#endif + - return 0; - } - -diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c -index cbc7c740e4dc..0b2af88b69a0 100644 ---- a/drivers/irqchip/irq-bcm2836.c -+++ b/drivers/irqchip/irq-bcm2836.c -@@ -22,6 +22,9 @@ struct bcm2836_arm_irqchip_intc { - - static struct bcm2836_arm_irqchip_intc intc __read_mostly; - -+void __iomem *arm_local_intc; -+EXPORT_SYMBOL_GPL(arm_local_intc); ++ ret = arducam_64mp_get_regulators(arducam_64mp); ++ if (ret) { ++ dev_err(dev, "failed to get regulators\n"); ++ return ret; ++ } + - static void bcm2836_arm_irqchip_mask_per_cpu_irq(unsigned int reg_offset, - unsigned int bit, - int cpu) -@@ -84,6 +87,27 @@ static void bcm2836_arm_irqchip_unmask_gpu_irq(struct irq_data *d) - { - } - -+#ifdef CONFIG_ARM64 ++ /* Request optional enable pin */ ++ arducam_64mp->reset_gpio = devm_gpiod_get_optional(dev, "reset", ++ GPIOD_OUT_HIGH); + -+void bcm2836_arm_irqchip_spin_gpu_irq(void) -+{ -+ u32 i; -+ void __iomem *gpurouting = (intc.base + LOCAL_GPU_ROUTING); -+ u32 routing_val = readl(gpurouting); ++ /* ++ * The sensor must be powered for arducam_64mp_identify_module() ++ * to be able to read the CHIP_ID from arducam_identifier. ++ */ ++ ret = arducam_64mp_power_on(dev); ++ if (ret) ++ return ret; + -+ for (i = 1; i <= 3; i++) { -+ u32 new_routing_val = (routing_val + i) & 3; ++ ret = arducam_64mp_identify_module(arducam_64mp); ++ if (ret) ++ goto error_power_off; + -+ if (cpu_active(new_routing_val)) { -+ writel(new_routing_val, gpurouting); -+ return; -+ } ++ /* Set default mode to max resolution */ ++ arducam_64mp->mode = &supported_modes0; ++ arducam_64mp->fmt_code = MEDIA_BUS_FMT_SRGGB10_1X10; ++ ++ /* 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 = arducam_64mp_init_controls(arducam_64mp); ++ if (ret) ++ goto error_power_off; ++ ++ /* Initialize subdev */ ++ arducam_64mp->sd.internal_ops = &arducam_64mp_internal_ops; ++ arducam_64mp->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | ++ V4L2_SUBDEV_FL_HAS_EVENTS; ++ arducam_64mp->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ++ /* Initialize source pads */ ++ arducam_64mp->padIMAGE_PAD.flags = MEDIA_PAD_FL_SOURCE; ++ arducam_64mp->padMETADATA_PAD.flags = MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&arducam_64mp->sd.entity, NUM_PADS, ++ arducam_64mp->pad); ++ if (ret) { ++ dev_err(dev, "failed to init entity pads: %d\n", ret); ++ goto error_handler_free; + } -+} -+EXPORT_SYMBOL(bcm2836_arm_irqchip_spin_gpu_irq); + -+#endif ++ ret = v4l2_async_register_subdev_sensor(&arducam_64mp->sd); ++ if (ret < 0) { ++ dev_err(dev, "failed to register sensor sub-device: %d\n", ret); ++ goto error_media_entity; ++ } + - static struct irq_chip bcm2836_arm_irqchip_gpu = { - .name = "bcm2836-gpu", - .irq_mask = bcm2836_arm_irqchip_mask_gpu_irq, -@@ -128,7 +152,7 @@ static int bcm2836_map(struct irq_domain *d, unsigned int irq, - 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; - } -@@ -323,6 +347,8 @@ static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node, - panic("%pOF: unable to map local interrupt registers\n", node); - } - -+ arm_local_intc = intc.base; ++ return 0; + - bcm2835_init_local_timer_frequency(); - - intc.domain = irq_domain_add_linear(node, LAST_IRQ + 1, -diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c -index 93f5b1b60fde..d0d05d663eea 100644 ---- a/drivers/leds/leds-gpio.c -+++ b/drivers/leds/leds-gpio.c -@@ -46,8 +46,15 @@ static void gpio_led_set(struct led_classdev *led_cdev, - 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); -@@ -61,6 +68,13 @@ static int gpio_led_set_blocking(struct led_classdev *led_cdev, - return 0; - } - -+static enum led_brightness gpio_led_get(struct led_classdev *led_cdev) ++error_media_entity: ++ media_entity_cleanup(&arducam_64mp->sd.entity); ++ ++error_handler_free: ++ arducam_64mp_free_controls(arducam_64mp); ++ ++error_power_off: ++ pm_runtime_disable(&client->dev); ++ pm_runtime_set_suspended(&client->dev); ++ arducam_64mp_power_off(&client->dev); ++ ++ return ret; ++} ++ ++static void arducam_64mp_remove(struct i2c_client *client) +{ -+ 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; ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd); ++ ++ v4l2_async_unregister_subdev(sd); ++ media_entity_cleanup(&sd->entity); ++ arducam_64mp_free_controls(arducam_64mp); ++ ++ pm_runtime_disable(&client->dev); ++ if (!pm_runtime_status_suspended(&client->dev)) ++ arducam_64mp_power_off(&client->dev); ++ pm_runtime_set_suspended(&client->dev); +} + - static int gpio_blink_set(struct led_classdev *led_cdev, - unsigned long *delay_on, unsigned long *delay_off) - { -@@ -89,6 +103,7 @@ static int create_gpio_led(const struct gpio_led *template, - 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 --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig -index ce9429ca6dde..d45aba3e1d13 100644 ---- a/drivers/leds/trigger/Kconfig -+++ b/drivers/leds/trigger/Kconfig -@@ -114,6 +114,13 @@ config LEDS_TRIGGER_CAMERA - 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. ++MODULE_DEVICE_TABLE(of, arducam_64mp_dt_ids); + - config LEDS_TRIGGER_PANIC - bool "LED Panic Trigger" - help -@@ -144,4 +151,15 @@ config LEDS_TRIGGER_AUDIO - 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. ++static const struct dev_pm_ops arducam_64mp_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(arducam_64mp_suspend, arducam_64mp_resume) ++ SET_RUNTIME_PM_OPS(arducam_64mp_power_off, arducam_64mp_power_on, NULL) ++}; + - endif # LEDS_TRIGGERS -diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile -index 733a83e2a718..1083b35cbe8b 100644 ---- a/drivers/leds/trigger/Makefile -+++ b/drivers/leds/trigger/Makefile -@@ -11,7 +11,9 @@ obj-$(CONFIG_LEDS_TRIGGER_ACTIVITY) += ledtrig-activity.o - 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 --git a/drivers/leds/trigger/ledtrig-actpwr.c b/drivers/leds/trigger/ledtrig-actpwr.c ++static struct i2c_driver arducam_64mp_i2c_driver = { ++ .driver = { ++ .name = "arducam_64mp", ++ .of_match_table = arducam_64mp_dt_ids, ++ .pm = &arducam_64mp_pm_ops, ++ }, ++ .probe = arducam_64mp_probe, ++ .remove = arducam_64mp_remove, ++}; ++ ++module_i2c_driver(arducam_64mp_i2c_driver); ++ ++MODULE_AUTHOR("Lee Jackson <info@arducam.com>"); ++MODULE_DESCRIPTION("Arducam 64MP sensor driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/media/i2c/bu64754.c b/drivers/media/i2c/bu64754.c new file mode 100644 -index 000000000000..1a52107ceb03 +index 000000000000..530b31e9876a --- /dev/null -+++ b/drivers/leds/trigger/ledtrig-actpwr.c -@@ -0,0 +1,190 @@ ++++ b/drivers/media/i2c/bu64754.c +@@ -0,0 +1,315 @@ +// 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. ++ * The BU64754GWZ is an actuator driver IC which can control the ++ * actuator position precisely using an internal Hall Sensor. + */ + ++#include <linux/delay.h> ++#include <linux/i2c.h> +#include <linux/module.h> -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/timer.h> -+#include <linux/leds.h> -+#include "../leds.h" ++#include <linux/pm_runtime.h> ++#include <linux/regulator/consumer.h> + -+enum { -+ TRIG_ACT, -+ TRIG_PWR, ++#include <media/v4l2-cci.h> ++#include <media/v4l2-ctrls.h> ++#include <media/v4l2-device.h> + -+ TRIG_COUNT -+}; ++#define BU64754_REG_ACTIVE CCI_REG16(0x07) ++#define BU64754_ACTIVE_MODE 0x8080 + -+struct actpwr_trig_src { -+ const char *name; -+ int interval; -+ bool invert; -+}; ++#define BU64754_REG_SERVE CCI_REG16(0xd9) ++#define BU64754_SERVE_ON 0x0404 + -+struct actpwr_vled { -+ struct led_classdev cdev; -+ struct actpwr_trig_data *parent; -+ enum led_brightness value; -+ unsigned int interval; -+ bool invert; -+}; ++#define BU64754_REG_POSITION CCI_REG16(0x45) ++#define BU64753_POSITION_MAX 1023 /* 0x3ff */ ++#define BU64753_POSITION_STEPS 1 + -+struct actpwr_trig_data { -+ struct led_trigger trig; -+ struct actpwr_vled virt_ledsTRIG_COUNT; -+ struct actpwr_vled *active; -+ struct timer_list timer; -+ int next_active; -+}; ++#define BU64754_POWER_ON_DELAY 800 /* uS : t1, t3 */ + -+static int actpwr_trig_activate(struct led_classdev *led_cdev); -+static void actpwr_trig_deactivate(struct led_classdev *led_cdev); ++struct bu64754 { ++ struct device *dev; + -+static const struct actpwr_trig_src actpwr_trig_sourcesTRIG_COUNT = { -+ TRIG_ACT = { "mmc0", 500, true }, -+ TRIG_PWR = { "default-on", 500, false }, -+}; ++ struct v4l2_ctrl_handler ctrls_vcm; ++ struct v4l2_subdev sd; ++ struct regmap *cci; + -+static struct actpwr_trig_data actpwr_data = { -+ { -+ .name = "actpwr", -+ .activate = actpwr_trig_activate, -+ .deactivate = actpwr_trig_deactivate, -+ } ++ u16 current_val; ++ struct regulator *vdd; ++ struct notifier_block notifier; +}; + -+static void actpwr_brightness_set(struct led_classdev *led_cdev, -+ enum led_brightness value) ++static inline struct bu64754 *sd_to_bu64754(struct v4l2_subdev *subdev) +{ -+ struct actpwr_vled *vled = container_of(led_cdev, struct actpwr_vled, -+ cdev); -+ struct actpwr_trig_data *trig = vled->parent; ++ return container_of(subdev, struct bu64754, sd); ++} + -+ if (vled->invert) -+ value = !value; -+ vled->value = value; ++static int bu64754_set(struct bu64754 *bu64754, u16 position) ++{ ++ int ret; + -+ if (vled == trig->active) -+ led_trigger_event(&trig->trig, value); ++ position &= 0x3ff; /* BU64753_POSITION_MAX */ ++ ret = cci_write(bu64754->cci, BU64754_REG_POSITION, position, NULL); ++ if (ret) { ++ dev_err(bu64754->dev, "Set position failed ret=%d\n", ret); ++ return ret; ++ } ++ ++ return 0; +} + -+static int actpwr_brightness_set_blocking(struct led_classdev *led_cdev, -+ enum led_brightness value) ++static int bu64754_active(struct bu64754 *bu64754) +{ -+ actpwr_brightness_set(led_cdev, value); -+ return 0; ++ int ret; ++ ++ /* Power on */ ++ ret = cci_write(bu64754->cci, BU64754_REG_ACTIVE, BU64754_ACTIVE_MODE, NULL); ++ if (ret < 0) { ++ dev_err(bu64754->dev, "Failed to set active mode ret = %d\n", ++ ret); ++ return ret; ++ } ++ ++ /* Serve on */ ++ ret = cci_write(bu64754->cci, BU64754_REG_SERVE, BU64754_SERVE_ON, NULL); ++ if (ret < 0) { ++ dev_err(bu64754->dev, "Failed to enable serve ret = %d\n", ++ ret); ++ return ret; ++ } ++ ++ return bu64754_set(bu64754, bu64754->current_val); +} + -+static enum led_brightness actpwr_brightness_get(struct led_classdev *led_cdev) ++static int bu64754_standby(struct bu64754 *bu64754) +{ -+ struct actpwr_vled *vled = container_of(led_cdev, struct actpwr_vled, -+ cdev); ++ int ret; + -+ return vled->value; ++ ret = cci_write(bu64754->cci, BU64754_REG_ACTIVE, 0, NULL); ++ if (ret < 0) ++ dev_err(bu64754->dev, "Failed to enter standby mode ret = %d\n", ++ ret); ++ ++ return ret; +} + -+static void actpwr_trig_cycle(struct timer_list *t) ++static int bu64754_regulator_event(struct notifier_block *nb, ++ unsigned long action, void *data) +{ -+ struct actpwr_trig_data *trig = &actpwr_data; -+ struct actpwr_vled *active; ++ struct bu64754 *bu64754 = container_of(nb, struct bu64754, notifier); + -+ active = &trig->virt_ledstrig->next_active; -+ trig->active = active; -+ trig->next_active = (trig->next_active + 1) % TRIG_COUNT; ++ if (action & REGULATOR_EVENT_ENABLE) { ++ /* ++ * Initialisation delay between VDD low->high and availability ++ * i2c operation. ++ */ ++ usleep_range(BU64754_POWER_ON_DELAY, ++ BU64754_POWER_ON_DELAY + 100); + -+ led_trigger_event(&trig->trig, active->value); ++ bu64754_active(bu64754); ++ } else if (action & REGULATOR_EVENT_PRE_DISABLE) { ++ bu64754_standby(bu64754); ++ } + -+ mod_timer(&trig->timer, jiffies + msecs_to_jiffies(active->interval)); ++ return 0; +} + -+static int actpwr_trig_activate(struct led_classdev *led_cdev) ++static int bu64754_set_ctrl(struct v4l2_ctrl *ctrl) +{ -+ struct actpwr_trig_data *trig = &actpwr_data; ++ struct bu64754 *bu64754 = container_of(ctrl->handler, ++ struct bu64754, ctrls_vcm); + -+ /* 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); ++ if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) { ++ bu64754->current_val = ctrl->val; ++ return bu64754_set(bu64754, ctrl->val); ++ } ++ ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops bu64754_vcm_ctrl_ops = { ++ .s_ctrl = bu64754_set_ctrl, ++}; + ++static int bu64754_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) ++{ ++ return pm_runtime_resume_and_get(sd->dev); ++} ++ ++static int bu64754_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) ++{ ++ pm_runtime_put(sd->dev); + return 0; +} + -+static void actpwr_trig_deactivate(struct led_classdev *led_cdev) ++static const struct v4l2_subdev_internal_ops bu64754_int_ops = { ++ .open = bu64754_open, ++ .close = bu64754_close, ++}; ++ ++static const struct v4l2_subdev_ops bu64754_ops = { }; ++ ++static void bu64754_subdev_cleanup(struct bu64754 *bu64754) +{ -+ struct actpwr_trig_data *trig = &actpwr_data; ++ v4l2_async_unregister_subdev(&bu64754->sd); ++ v4l2_ctrl_handler_free(&bu64754->ctrls_vcm); ++ media_entity_cleanup(&bu64754->sd.entity); ++} + -+ if (list_empty(&trig->trig.led_cdevs)) { -+ del_timer_sync(&trig->timer); -+ trig->active = NULL; ++static int bu64754_init_controls(struct bu64754 *bu64754) ++{ ++ struct v4l2_ctrl_handler *hdl = &bu64754->ctrls_vcm; ++ const struct v4l2_ctrl_ops *ops = &bu64754_vcm_ctrl_ops; ++ ++ v4l2_ctrl_handler_init(hdl, 1); ++ ++ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_ABSOLUTE, ++ 0, BU64753_POSITION_MAX, BU64753_POSITION_STEPS, ++ 0); ++ ++ bu64754->current_val = 0; ++ ++ bu64754->sd.ctrl_handler = hdl; ++ if (hdl->error) { ++ dev_err(bu64754->dev, "%s fail error: 0x%x\n", ++ __func__, hdl->error); ++ return hdl->error; + } ++ ++ return 0; +} + -+static int __init actpwr_trig_init(void) ++static int bu64754_probe(struct i2c_client *client) +{ -+ struct actpwr_trig_data *trig = &actpwr_data; -+ int ret = 0; -+ int i; ++ struct bu64754 *bu64754; ++ int ret; + -+ timer_setup(&trig->timer, actpwr_trig_cycle, 0); ++ bu64754 = devm_kzalloc(&client->dev, sizeof(*bu64754), GFP_KERNEL); ++ if (!bu64754) ++ return -ENOMEM; + -+ /* Register one "LED" for each source trigger */ -+ for (i = 0; i < TRIG_COUNT; i++) -+ { -+ struct actpwr_vled *vled = &trig->virt_ledsi; -+ struct led_classdev *cdev = &vled->cdev; -+ const struct actpwr_trig_src *src = &actpwr_trig_sourcesi; ++ bu64754->dev = &client->dev; + -+ 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; ++ bu64754->cci = devm_cci_regmap_init_i2c(client, 8); ++ if (IS_ERR(bu64754->cci)) { ++ dev_err(bu64754->dev, "Failed to initialize CCI\n"); ++ return PTR_ERR(bu64754->cci); + } + -+ ret = led_trigger_register(&trig->trig); ++ bu64754->vdd = devm_regulator_get_optional(&client->dev, "vdd"); ++ if (IS_ERR(bu64754->vdd)) { ++ if (PTR_ERR(bu64754->vdd) != -ENODEV) ++ return PTR_ERR(bu64754->vdd); ++ ++ bu64754->vdd = NULL; ++ } else { ++ bu64754->notifier.notifier_call = bu64754_regulator_event; ++ ++ ret = regulator_register_notifier(bu64754->vdd, ++ &bu64754->notifier); ++ if (ret) { ++ dev_err(bu64754->dev, ++ "could not register regulator notifier\n"); ++ return ret; ++ } ++ } ++ ++ v4l2_i2c_subdev_init(&bu64754->sd, client, &bu64754_ops); ++ bu64754->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ bu64754->sd.internal_ops = &bu64754_int_ops; ++ bu64754->sd.entity.function = MEDIA_ENT_F_LENS; ++ ++ ret = bu64754_init_controls(bu64754); + if (ret) -+ goto error_classdev; ++ goto err_cleanup; ++ ++ ret = media_entity_pads_init(&bu64754->sd.entity, 0, NULL); ++ if (ret < 0) ++ goto err_cleanup; ++ ++ bu64754->sd.entity.function = MEDIA_ENT_F_LENS; ++ ++ ret = v4l2_async_register_subdev(&bu64754->sd); ++ if (ret < 0) ++ goto err_cleanup; ++ ++ if (!bu64754->vdd) ++ pm_runtime_set_active(&client->dev); ++ ++ pm_runtime_enable(&client->dev); ++ pm_runtime_idle(&client->dev); + + return 0; + -+error_classdev: -+ while (i > 0) -+ { -+ i--; -+ led_classdev_unregister(&trig->virt_ledsi.cdev); -+ } ++err_cleanup: ++ v4l2_ctrl_handler_free(&bu64754->ctrls_vcm); ++ media_entity_cleanup(&bu64754->sd.entity); + + return ret; +} + -+static void __exit actpwr_trig_exit(void) ++static void bu64754_remove(struct i2c_client *client) +{ -+ int i; -+ -+ led_trigger_unregister(&actpwr_data.trig); -+ for (i = 0; i < TRIG_COUNT; i++) -+ { -+ led_classdev_unregister(&actpwr_data.virt_ledsi.cdev); -+ } -+} ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct bu64754 *bu64754 = sd_to_bu64754(sd); + -+module_init(actpwr_trig_init); -+module_exit(actpwr_trig_exit); ++ if (bu64754->vdd) ++ regulator_unregister_notifier(bu64754->vdd, ++ &bu64754->notifier); + -+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.com>"); -+MODULE_DESCRIPTION("ACT/PWR LED trigger"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/leds/trigger/ledtrig-input.c b/drivers/leds/trigger/ledtrig-input.c -new file mode 100644 -index 000000000000..8a974a355656 ---- /dev/null -+++ b/drivers/leds/trigger/ledtrig-input.c -@@ -0,0 +1,55 @@ -+/* -+ * 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. -+ * -+ */ ++ pm_runtime_disable(&client->dev); + -+#include <linux/module.h> -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/leds.h> -+#include <linux/gpio.h> -+#include "../leds.h" ++ bu64754_subdev_cleanup(bu64754); ++} + -+static int input_trig_activate(struct led_classdev *led_cdev) ++static int __maybe_unused bu64754_vcm_suspend(struct device *dev) +{ -+ led_cdev->flags |= SET_GPIO_INPUT; -+ led_set_brightness(led_cdev, 0); -+ return 0; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct bu64754 *bu64754 = sd_to_bu64754(sd); ++ ++ if (bu64754->vdd) ++ return regulator_disable(bu64754->vdd); ++ ++ return bu64754_standby(bu64754); +} + -+static void input_trig_deactivate(struct led_classdev *led_cdev) ++static int __maybe_unused bu64754_vcm_resume(struct device *dev) +{ -+ led_cdev->flags |= SET_GPIO_OUTPUT; -+ led_set_brightness(led_cdev, 0); ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct bu64754 *bu64754 = sd_to_bu64754(sd); ++ ++ if (bu64754->vdd) ++ return regulator_enable(bu64754->vdd); ++ ++ return bu64754_active(bu64754); +} + -+static struct led_trigger input_led_trigger = { -+ .name = "input", -+ .activate = input_trig_activate, -+ .deactivate = input_trig_deactivate, ++static const struct of_device_id bu64754_of_table = { ++ { .compatible = "rohm,bu64754", }, ++ { /* sentinel */ } +}; + -+static int __init input_trig_init(void) -+{ -+ return led_trigger_register(&input_led_trigger); -+} ++MODULE_DEVICE_TABLE(of, bu64754_of_table); + -+static void __exit input_trig_exit(void) -+{ -+ led_trigger_unregister(&input_led_trigger); -+} ++static const struct dev_pm_ops bu64754_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(bu64754_vcm_suspend, bu64754_vcm_resume) ++ SET_RUNTIME_PM_OPS(bu64754_vcm_suspend, bu64754_vcm_resume, NULL) ++}; + -+module_init(input_trig_init); -+module_exit(input_trig_exit); ++static struct i2c_driver bu64754_i2c_driver = { ++ .driver = { ++ .name = "bu64754", ++ .pm = &bu64754_pm_ops, ++ .of_match_table = bu64754_of_table, ++ }, ++ .probe = bu64754_probe, ++ .remove = bu64754_remove, ++}; + -+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.org>"); -+MODULE_DESCRIPTION("Set LED GPIO to Input \"trigger\""); ++module_i2c_driver(bu64754_i2c_driver); ++ ++MODULE_AUTHOR("Kieran Bingham"); ++MODULE_DESCRIPTION("BU64754 VCM driver"); +MODULE_LICENSE("GPL"); -diff --git a/drivers/mailbox/bcm2835-mailbox.c b/drivers/mailbox/bcm2835-mailbox.c -index 39761d190545..9766d8b50778 100644 ---- a/drivers/mailbox/bcm2835-mailbox.c -+++ b/drivers/mailbox/bcm2835-mailbox.c -@@ -45,12 +45,15 @@ - #define MAIL1_WRT (ARM_0_MAIL1 + 0x00) - #define MAIL1_STA (ARM_0_MAIL1 + 0x18) ++ +diff --git a/drivers/media/i2c/dw9807-vcm.c b/drivers/media/i2c/dw9807-vcm.c +index 4148009e0e01..2362c4813f5e 100644 +--- a/drivers/media/i2c/dw9807-vcm.c ++++ b/drivers/media/i2c/dw9807-vcm.c +@@ -1,12 +1,21 @@ + // SPDX-License-Identifier: GPL-2.0 + // Copyright (C) 2018 Intel Corporation -+/* 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) ++/* ++ * DW9807 is a 10-bit DAC driver, capable of sinking up to 100mA. ++ * ++ * DW9817 is a bidirectional 10-bit driver, driving up to +/- 100mA. ++ * Operationally it is identical to DW9807, except that the idle position is ++ * the mid-point, not 0. ++ */ ++ + #include <linux/acpi.h> + #include <linux/delay.h> + #include <linux/i2c.h> + #include <linux/iopoll.h> + #include <linux/module.h> + #include <linux/pm_runtime.h> ++#include <linux/regulator/consumer.h> + #include <media/v4l2-ctrls.h> + #include <media/v4l2-device.h> - /* Configuration register: Enable interrupts. */ - #define ARM_MC_IHAVEDATAIRQEN BIT(0) -+#endif +@@ -38,10 +47,22 @@ - struct bcm2835_mbox { - void __iomem *regs; -@@ -145,7 +148,7 @@ static int bcm2835_mbox_probe(struct platform_device *pdev) - return -ENOMEM; - spin_lock_init(&mbox->lock); + #define MAX_RETRY 10 -- 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", -@@ -195,7 +198,18 @@ static struct platform_driver bcm2835_mbox_driver = { - }, - .probe = bcm2835_mbox_probe, - }; --module_platform_driver(bcm2835_mbox_driver); ++#define DW9807_PW_MIN_DELAY_US 100 ++#define DW9807_PW_DELAY_RANGE_US 10 + -+static int __init bcm2835_mbox_init(void) -+{ -+ return platform_driver_register(&bcm2835_mbox_driver); -+} -+arch_initcall(bcm2835_mbox_init); ++struct dw9807_cfg { ++ unsigned int idle_pos; ++ unsigned int default_pos; ++}; + -+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 --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c -index 3e7d4b20ab34..0b821a5b2db8 100644 ---- a/drivers/mailbox/mailbox.c -+++ b/drivers/mailbox/mailbox.c -@@ -82,12 +82,9 @@ static void msg_submit(struct mbox_chan *chan) - 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) -@@ -125,10 +122,11 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer) - struct mbox_chan *chan = &mbox->chansi; - - 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; - } - } + struct dw9807_device { + struct v4l2_ctrl_handler ctrls_vcm; + struct v4l2_subdev sd; + u16 current_val; ++ u16 idle_pos; ++ struct regulator *vdd; ++ struct notifier_block notifier; ++ bool first; + }; -diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c -index 72350343a56a..3c6a74b29683 100644 ---- a/drivers/media/common/videobuf2/videobuf2-core.c -+++ b/drivers/media/common/videobuf2/videobuf2-core.c -@@ -2140,12 +2140,12 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off, - return -EINVAL; + static inline struct dw9807_device *sd_to_dw9807_vcm( +@@ -109,6 +130,102 @@ static int dw9807_set_dac(struct i2c_client *client, u16 data) + return 0; } --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) { -@@ -2195,6 +2195,21 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type, - return -EINVAL; - } - -+ *dmabuf = dbuf; -+ return 0; ++/* ++ * The lens position is gradually moved in units of DW9807_CTRL_STEPS, ++ * to make the movements smoothly. In all cases, even when "start" and ++ * "end" are the same, the lens will be set to the "end" position. ++ * ++ * (We don't use hardware slew rate control, because it differs widely ++ * between otherwise-compatible ICs, and may need lens-specific tuning.) ++ */ ++static int dw9807_ramp(struct i2c_client *client, int start, int end) ++{ ++ int step, val, ret; ++ ++ if (start < end) ++ step = DW9807_CTRL_STEPS; ++ else ++ step = -DW9807_CTRL_STEPS; ++ ++ val = start; ++ while (true) { ++ val += step; ++ if (step * (val - end) >= 0) ++ val = end; ++ ret = dw9807_set_dac(client, val); ++ if (ret) ++ dev_err_ratelimited(&client->dev, "%s I2C failure: %d", ++ __func__, ret); ++ if (val == end) ++ break; ++ usleep_range(DW9807_CTRL_DELAY_US, DW9807_CTRL_DELAY_US + 10); ++ } ++ ++ return ret; +} -+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) ++static int dw9807_active(struct dw9807_device *dw9807_dev) +{ -+ struct dma_buf *dbuf; ++ struct i2c_client *client = v4l2_get_subdevdata(&dw9807_dev->sd); ++ const char tx_data2 = { DW9807_CTL_ADDR, 0x00 }; + int ret; + -+ ret = vb2_core_expbuf_dmabuf(q, type, index, plane, flags, &dbuf); -+ if (ret) ++ /* Power on */ ++ ret = i2c_master_send(client, tx_data, sizeof(tx_data)); ++ if (ret < 0) { ++ dev_err(&client->dev, "I2C write CTL fail ret = %d\n", 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 --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig -index 878f66ef2719..4c97729be222 100644 ---- a/drivers/media/i2c/Kconfig -+++ b/drivers/media/i2c/Kconfig -@@ -801,6 +801,17 @@ config VIDEO_IMX290 - 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. ++ dw9807_dev->first = true; + -+ To compile this driver as a module, choose M here: the -+ module will be called imx477. ++ return dw9807_ramp(client, dw9807_dev->idle_pos, dw9807_dev->current_val); ++} + - config VIDEO_IMX319 - tristate "Sony IMX319 sensor support" - depends on I2C && VIDEO_V4L2 -@@ -825,6 +836,17 @@ config VIDEO_IMX355 - To compile this driver as a module, choose M here: the - module will be called imx355. - -+config VIDEO_IMX519 -+ tristate "Arducam IMX519 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 Arducam -+ IMX519 camera. ++static int dw9807_standby(struct dw9807_device *dw9807_dev) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&dw9807_dev->sd); ++ const char tx_data2 = { DW9807_CTL_ADDR, 0x01 }; ++ int ret; + -+ To compile this driver as a module, choose M here: the -+ module will be called IMX519. ++ if (abs(dw9807_dev->current_val - dw9807_dev->idle_pos) > DW9807_CTRL_STEPS) ++ dw9807_ramp(client, dw9807_dev->current_val, dw9807_dev->idle_pos); + - config VIDEO_OV2640 - tristate "OmniVision OV2640 sensor support" - depends on VIDEO_V4L2 && I2C -@@ -1040,6 +1062,17 @@ config VIDEO_OV9640 - 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. ++ /* Power down */ ++ ret = i2c_master_send(client, tx_data, sizeof(tx_data)); ++ if (ret < 0) { ++ dev_err(&client->dev, "I2C write CTL fail ret = %d\n", ret); ++ return ret; ++ } + -+ To compile this driver as a module, choose M here: the -+ module will be called ov9281. ++ return 0; ++} + - config VIDEO_OV9650 - tristate "OmniVision OV9650/OV9652 sensor support" - depends on I2C && VIDEO_V4L2 -@@ -1060,6 +1093,18 @@ config VIDEO_OV13858 - 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. ++static int dw9807_regulator_event(struct notifier_block *nb, ++ unsigned long action, void *data) ++{ ++ struct dw9807_device *dw9807_dev = ++ container_of(nb, struct dw9807_device, notifier); + -+ To compile this driver as a module, choose M here: the -+ module will be called irs1125. ++ if (action & REGULATOR_EVENT_ENABLE) { ++ /* ++ * Initialisation delay between VDD low->high and the moment ++ * when the i2c command is available. ++ * From the datasheet, it should be 10ms + 2ms (max power ++ * up sequence duration) ++ */ ++ usleep_range(DW9807_PW_MIN_DELAY_US, ++ DW9807_PW_MIN_DELAY_US + ++ DW9807_PW_DELAY_RANGE_US); + - config VIDEO_VS6624 - tristate "ST VS6624 sensor support" - depends on VIDEO_V4L2 && I2C -diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile -index f0a77473979d..944aea27f362 100644 ---- a/drivers/media/i2c/Makefile -+++ b/drivers/media/i2c/Makefile -@@ -81,9 +81,11 @@ obj-$(CONFIG_VIDEO_OV7670) += ov7670.o - 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 -@@ -117,8 +119,10 @@ obj-$(CONFIG_VIDEO_IMX219) += imx219.o - 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_IMX519) += imx519.o - obj-$(CONFIG_VIDEO_MAX9286) += max9286.o - rdacm20-camera_module-objs := rdacm20.o max9271.o - obj-$(CONFIG_VIDEO_RDACM20) += rdacm20-camera_module.o -diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c -index 4498d14d3429..4103690a71df 100644 ---- a/drivers/media/i2c/adv7180.c -+++ b/drivers/media/i2c/adv7180.c -@@ -1248,6 +1248,7 @@ static const struct adv7180_chip_info adv7282_m_info = { - 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), -@@ -1259,6 +1260,7 @@ static const struct adv7180_chip_info adv7282_m_info = { - static int init_device(struct adv7180_state *state) ++ dw9807_active(dw9807_dev); ++ } else if (action & REGULATOR_EVENT_PRE_DISABLE) { ++ dw9807_standby(dw9807_dev); ++ } ++ ++ return 0; ++} ++ + static int dw9807_set_ctrl(struct v4l2_ctrl *ctrl) { - int ret; -+ int i; + struct dw9807_device *dev_vcm = container_of(ctrl->handler, +@@ -116,9 +233,11 @@ static int dw9807_set_ctrl(struct v4l2_ctrl *ctrl) - mutex_lock(&state->mutex); + if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) { + struct i2c_client *client = v4l2_get_subdevdata(&dev_vcm->sd); ++ int start = (dev_vcm->first) ? dev_vcm->current_val : ctrl->val; -@@ -1305,6 +1307,18 @@ static int init_device(struct adv7180_state *state) - goto out_unlock; ++ dev_vcm->first = false; + dev_vcm->current_val = ctrl->val; +- return dw9807_set_dac(client, ctrl->val); ++ return dw9807_ramp(client, start, ctrl->val); } -+ /* 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); + return -EINVAL; +@@ -163,7 +282,8 @@ static int dw9807_init_controls(struct dw9807_device *dev_vcm) + v4l2_ctrl_handler_init(hdl, 1); + + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_ABSOLUTE, +- 0, DW9807_MAX_FOCUS_POS, DW9807_FOCUS_STEPS, 0); ++ 0, DW9807_MAX_FOCUS_POS, DW9807_FOCUS_STEPS, ++ dev_vcm->current_val); + + dev_vcm->sd.ctrl_handler = hdl; + if (hdl->error) { +@@ -175,9 +295,32 @@ static int dw9807_init_controls(struct dw9807_device *dev_vcm) + return 0; + } + ++/* Compatible devices; in fact there are many similar chips. ++ * "data" holds the powered-off (zero current) lens position and a ++ * default/initial control value (which need not be the same as the powered-off ++ * value). ++ */ ++static const struct dw9807_cfg dw9807_cfg = { ++ .idle_pos = 0, ++ .default_pos = 0 ++}; + -+ if (ret == 0) { -+ state->input = i; -+ break; -+ } ++static const struct dw9807_cfg dw9817_cfg = { ++ .idle_pos = 512, ++ .default_pos = 480, ++}; ++ ++static const struct of_device_id dw9807_of_table = { ++ { .compatible = "dongwoon,dw9807-vcm", .data = &dw9807_cfg }, ++ { .compatible = "dongwoon,dw9817-vcm", .data = &dw9817_cfg }, ++ { /* sentinel */ } ++}; ++ + static int dw9807_probe(struct i2c_client *client) + { + struct dw9807_device *dw9807_dev; ++ const struct of_device_id *match; ++ const struct dw9807_cfg *cfg; + int rval; + + dw9807_dev = devm_kzalloc(&client->dev, sizeof(*dw9807_dev), +@@ -185,6 +328,31 @@ static int dw9807_probe(struct i2c_client *client) + if (dw9807_dev == NULL) + return -ENOMEM; + ++ dw9807_dev->vdd = devm_regulator_get_optional(&client->dev, "VDD"); ++ if (IS_ERR(dw9807_dev->vdd)) { ++ if (PTR_ERR(dw9807_dev->vdd) != -ENODEV) ++ return PTR_ERR(dw9807_dev->vdd); ++ ++ dw9807_dev->vdd = NULL; ++ } else { ++ dw9807_dev->notifier.notifier_call = dw9807_regulator_event; ++ ++ rval = regulator_register_notifier(dw9807_dev->vdd, ++ &dw9807_dev->notifier); ++ if (rval) { ++ dev_err(&client->dev, ++ "could not register regulator notifier\n"); ++ return rval; + } + } + - out_unlock: - mutex_unlock(&state->mutex); ++ match = i2c_of_match_device(dw9807_of_table, client); ++ if (match) { ++ cfg = (const struct dw9807_cfg *)match->data; ++ dw9807_dev->idle_pos = cfg->idle_pos; ++ dw9807_dev->current_val = cfg->default_pos; ++ } ++ + v4l2_i2c_subdev_init(&dw9807_dev->sd, client, &dw9807_ops); + dw9807_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + dw9807_dev->sd.internal_ops = &dw9807_int_ops; +@@ -203,7 +371,8 @@ static int dw9807_probe(struct i2c_client *client) + if (rval < 0) + goto err_cleanup; + +- pm_runtime_set_active(&client->dev); ++ if (!dw9807_dev->vdd) ++ pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_idle(&client->dev); + +@@ -221,6 +390,10 @@ static void dw9807_remove(struct i2c_client *client) + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct dw9807_device *dw9807_dev = sd_to_dw9807_vcm(sd); + ++ if (dw9807_dev->vdd) ++ regulator_unregister_notifier(dw9807_dev->vdd, ++ &dw9807_dev->notifier); ++ + pm_runtime_disable(&client->dev); + + dw9807_subdev_cleanup(dw9807_dev); +@@ -236,25 +409,11 @@ static int __maybe_unused dw9807_vcm_suspend(struct device *dev) + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct dw9807_device *dw9807_dev = sd_to_dw9807_vcm(sd); +- const char tx_data2 = { DW9807_CTL_ADDR, 0x01 }; +- int ret, val; +- +- for (val = dw9807_dev->current_val & ~(DW9807_CTRL_STEPS - 1); +- val >= 0; val -= DW9807_CTRL_STEPS) { +- ret = dw9807_set_dac(client, val); +- if (ret) +- dev_err_once(dev, "%s I2C failure: %d", __func__, ret); +- usleep_range(DW9807_CTRL_DELAY_US, DW9807_CTRL_DELAY_US + 10); +- } + +- /* Power down */ +- ret = i2c_master_send(client, tx_data, sizeof(tx_data)); +- if (ret < 0) { +- dev_err(&client->dev, "I2C write CTL fail ret = %d\n", ret); +- return ret; +- } ++ if (dw9807_dev->vdd) ++ return regulator_disable(dw9807_dev->vdd); + +- return 0; ++ return dw9807_standby(dw9807_dev); + } + + /* +@@ -268,35 +427,13 @@ static int __maybe_unused dw9807_vcm_resume(struct device *dev) + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct dw9807_device *dw9807_dev = sd_to_dw9807_vcm(sd); +- const char tx_data2 = { DW9807_CTL_ADDR, 0x00 }; +- int ret, val; +- +- /* Power on */ +- ret = i2c_master_send(client, tx_data, sizeof(tx_data)); +- if (ret < 0) { +- dev_err(&client->dev, "I2C write CTL fail ret = %d\n", ret); +- return ret; +- } + +- for (val = dw9807_dev->current_val % DW9807_CTRL_STEPS; +- val < dw9807_dev->current_val + DW9807_CTRL_STEPS - 1; +- val += DW9807_CTRL_STEPS) { +- ret = dw9807_set_dac(client, val); +- if (ret) +- dev_err_ratelimited(dev, "%s I2C failure: %d", +- __func__, ret); +- usleep_range(DW9807_CTRL_DELAY_US, DW9807_CTRL_DELAY_US + 10); +- } ++ if (dw9807_dev->vdd) ++ return regulator_enable(dw9807_dev->vdd); + +- return 0; ++ return dw9807_active(dw9807_dev); + } + +-static const struct of_device_id dw9807_of_table = { +- { .compatible = "dongwoon,dw9807-vcm" }, +- /* Compatibility for older firmware, NEVER USE THIS IN FIRMWARE! */ +- { .compatible = "dongwoon,dw9807" }, +- { /* sentinel */ } +-}; + MODULE_DEVICE_TABLE(of, dw9807_of_table); + static const struct dev_pm_ops dw9807_pm_ops = { diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c -index 4771d0ef2c46..7f0fdd6fd7bc 100644 +index 3afa3f79c8a2..aeab1a8cca94 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c -@@ -55,7 +55,7 @@ +@@ -77,7 +77,7 @@ #define IMX219_VTS_30FPS_640x480 0x06e3 #define IMX219_VTS_MAX 0xffff @@ -71062,7 +107718,31 @@ /*Frame Length Line*/ #define IMX219_FLL_MIN 0x08a6 -@@ -118,6 +118,16 @@ +@@ -85,8 +85,10 @@ + #define IMX219_FLL_STEP 1 + #define IMX219_FLL_DEFAULT 0x0c98 + +-/* HBLANK control - read only */ +-#define IMX219_PPL_DEFAULT 3448 ++/* HBLANK control range */ ++#define IMX219_PPL_MIN 3448 ++#define IMX219_PPL_MAX 0x7ff0 ++#define IMX219_REG_HTS CCI_REG16(0x0162) + + #define IMX219_REG_LINE_LENGTH_A CCI_REG16(0x0162) + #define IMX219_REG_X_ADD_STA_A CCI_REG16(0x0164) +@@ -102,8 +104,8 @@ + /* Binning Mode */ + #define IMX219_REG_BINNING_MODE CCI_REG16(0x0174) + #define IMX219_BINNING_NONE 0x0000 +-#define IMX219_BINNING_2X2 0x0101 +-#define IMX219_BINNING_2X2_ANALOG 0x0303 ++#define IMX219_BINNING_2X2_NORMAL 0x0101 ++#define IMX219_BINNING_2X2_SPECIAL 0x0303 + + #define IMX219_REG_CSI_DATA_FORMAT_A CCI_REG16(0x018c) + +@@ -159,6 +161,33 @@ #define IMX219_PIXEL_ARRAY_WIDTH 3280U #define IMX219_PIXEL_ARRAY_HEIGHT 2464U @@ -71076,77 +107756,218 @@ + NUM_PADS +}; + - struct imx219_reg { - u16 address; - u8 val; -@@ -536,7 +546,7 @@ static const struct imx219_mode supported_modes = { ++enum binning_mode { ++ BINNING_NONE, ++ BINNING_NORMAL_2x2, ++ BINNING_SPECIAL_2x2, ++}; ++ ++enum binning_bit_depths { ++ BINNING_IDX_8_BIT, ++ BINNING_IDX_10_BIT, ++ BINNING_IDX_MAX ++}; ++ ++struct imx219_reg { ++ u16 address; ++ u8 val; ++}; ++ + struct imx219_reg_list { + unsigned int num_of_regs; + const struct cci_reg_sequence *regs; +@@ -180,8 +209,8 @@ struct imx219_mode { + /* Default register values */ + struct imx219_reg_list reg_list; + +- /* 2x2 binning is used */ +- bool binning; ++ /* binning mode based on format code */ ++ enum binning_mode binningBINNING_IDX_MAX; + }; + + static const struct cci_reg_sequence imx219_common_regs = { +@@ -386,7 +415,10 @@ static const struct imx219_mode supported_modes = { + .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs), + .regs = mode_3280x2464_regs, + }, +- .binning = false, ++ .binning = { ++ BINNING_IDX_8_BIT = BINNING_NONE, ++ BINNING_IDX_10_BIT = BINNING_NONE, ++ }, + }, + { + /* 1080P 30fps cropped */ +@@ -403,7 +435,10 @@ static const struct imx219_mode supported_modes = { + .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs), + .regs = mode_1920_1080_regs, + }, +- .binning = false, ++ .binning = { ++ BINNING_IDX_8_BIT = BINNING_NONE, ++ BINNING_IDX_10_BIT = BINNING_NONE, ++ }, + }, + { + /* 2x2 binned 30fps mode */ +@@ -420,7 +455,10 @@ static const struct imx219_mode supported_modes = { + .num_of_regs = ARRAY_SIZE(mode_1640_1232_regs), + .regs = mode_1640_1232_regs, + }, +- .binning = true, ++ .binning = { ++ BINNING_IDX_8_BIT = BINNING_SPECIAL_2x2, ++ BINNING_IDX_10_BIT = BINNING_NORMAL_2x2, ++ }, + }, + { + /* 640x480 30fps mode */ +@@ -437,13 +475,16 @@ static const struct imx219_mode supported_modes = { + .num_of_regs = ARRAY_SIZE(mode_640_480_regs), + .regs = mode_640_480_regs, + }, +- .binning = true, ++ .binning = { ++ BINNING_IDX_8_BIT = BINNING_SPECIAL_2x2, ++ BINNING_IDX_10_BIT = BINNING_SPECIAL_2x2, ++ }, + }, + }; struct imx219 { struct v4l2_subdev sd; - struct media_pad pad; + struct media_pad padNUM_PADS; - struct v4l2_mbus_framefmt fmt; - -@@ -671,7 +681,7 @@ static void imx219_set_default_format(struct imx219 *imx219) + struct regmap *regmap; + struct clk *xclk; /* system clock to IMX219 */ +@@ -495,12 +536,64 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code) + return imx219_mbus_formatsi; + } - fmt = &imx219->fmt; - fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10; -- fmt->colorspace = V4L2_COLORSPACE_SRGB; -+ fmt->colorspace = V4L2_COLORSPACE_RAW; - fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); - fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, - fmt->colorspace, -@@ -685,18 +695,26 @@ static void imx219_set_default_format(struct imx219 *imx219) - static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) ++static int imx219_resolve_binning(struct imx219 *imx219, ++ const struct v4l2_mbus_framefmt *format, ++ enum binning_mode *binning) ++{ ++ u32 fmt; ++ ++ if (format) ++ fmt = format->code; ++ else ++ fmt = MEDIA_BUS_FMT_SRGGB10_1X10; ++ ++ switch (fmt) { ++ case MEDIA_BUS_FMT_SRGGB8_1X8: ++ case MEDIA_BUS_FMT_SGRBG8_1X8: ++ case MEDIA_BUS_FMT_SGBRG8_1X8: ++ case MEDIA_BUS_FMT_SBGGR8_1X8: ++ *binning = imx219->mode->binningBINNING_IDX_8_BIT; ++ return 0; ++ ++ case MEDIA_BUS_FMT_SRGGB10_1X10: ++ case MEDIA_BUS_FMT_SGRBG10_1X10: ++ case MEDIA_BUS_FMT_SGBRG10_1X10: ++ case MEDIA_BUS_FMT_SBGGR10_1X10: ++ *binning = imx219->mode->binningBINNING_IDX_10_BIT; ++ return 0; ++ } ++ return -EINVAL; ++} ++ ++static int imx219_get_rate_factor(struct imx219 *imx219, ++ const struct v4l2_mbus_framefmt *format) ++{ ++ enum binning_mode binning = BINNING_NONE; ++ int ret; ++ ++ ret = imx219_resolve_binning(imx219, format, &binning); ++ if (ret < 0) ++ return ret; ++ ++ switch (binning) { ++ case BINNING_NONE: ++ case BINNING_NORMAL_2x2: ++ return 1; ++ case BINNING_SPECIAL_2x2: ++ return 2; ++ } ++ return -EINVAL; ++} ++ + static int imx219_set_ctrl(struct v4l2_ctrl *ctrl) { - 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); + struct imx219 *imx219 = + container_of(ctrl->handler, struct imx219, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); + int ret = 0; ++ const struct v4l2_mbus_framefmt *format; ++ struct v4l2_subdev_state *state; ++ int rate_factor; + + if (ctrl->id == V4L2_CID_VBLANK) { + int exposure_max, exposure_def; +@@ -522,6 +615,10 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl) + if (pm_runtime_get_if_in_use(&client->dev) == 0) + return 0; -- /* Initialize try_fmt */ -- try_fmt->width = supported_modes0.width; -- try_fmt->height = supported_modes0.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_modes0.width; -+ try_fmt_img->height = supported_modes0.height; -+ try_fmt_img->code = imx219_get_format_code(imx219, -+ MEDIA_BUS_FMT_SRGGB10_1X10); -+ try_fmt_img->field = V4L2_FIELD_NONE; ++ state = v4l2_subdev_get_locked_active_state(&imx219->sd); ++ format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0); ++ rate_factor = imx219_get_rate_factor(imx219, format); + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + cci_write(imx219->regmap, IMX219_REG_ANALOG_GAIN, +@@ -529,7 +626,7 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl) + break; + case V4L2_CID_EXPOSURE: + cci_write(imx219->regmap, IMX219_REG_EXPOSURE, +- ctrl->val, &ret); ++ ctrl->val / rate_factor, &ret); + break; + case V4L2_CID_DIGITAL_GAIN: + cci_write(imx219->regmap, IMX219_REG_DIGITAL_GAIN, +@@ -546,7 +643,11 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl) + break; + case V4L2_CID_VBLANK: + cci_write(imx219->regmap, IMX219_REG_VTS, +- imx219->mode->height + ctrl->val, &ret); ++ (imx219->mode->height + ctrl->val) / rate_factor, &ret); ++ break; ++ case V4L2_CID_HBLANK: ++ cci_write(imx219->regmap, IMX219_REG_HTS, ++ imx219->mode->width + ctrl->val, &ret); + break; + case V4L2_CID_TEST_PATTERN_RED: + cci_write(imx219->regmap, IMX219_REG_TESTP_RED, +@@ -614,6 +715,13 @@ static int imx219_init_cfg(struct v4l2_subdev *sd, + crop->width = IMX219_PIXEL_ARRAY_WIDTH; + crop->height = IMX219_PIXEL_ARRAY_HEIGHT; + + /* 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; ++ format = v4l2_subdev_get_pad_format(sd, state, 1); ++ format->code = MEDIA_BUS_FMT_SENSOR_DATA; ++ format->width = IMX219_EMBEDDED_LINE_WIDTH; ++ format->height = IMX219_NUM_EMBEDDED_LINES; ++ format->field = V4L2_FIELD_NONE; ++ + return 0; + } - /* Initialize try_crop rectangle. */ - try_crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0); -@@ -805,10 +823,21 @@ static int imx219_enum_mbus_code(struct v4l2_subdev *sd, +@@ -623,10 +731,20 @@ static int imx219_enum_mbus_code(struct v4l2_subdev *sd, { struct imx219 *imx219 = to_imx219(sd); -- if (code->index >= (ARRAY_SIZE(codes) / 4)) +- if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4)) + if (code->pad >= NUM_PADS) return -EINVAL; -- code->code = imx219_get_format_code(imx219, codescode->index * 4); +- code->code = imx219_get_format_code(imx219, imx219_mbus_formatscode->index * 4); + if (code->pad == IMAGE_PAD) { -+ if (code->index >= (ARRAY_SIZE(codes) / 4)) ++ if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4)) + return -EINVAL; + -+ code->code = imx219_get_format_code(imx219, -+ codescode->index * 4); ++ code->code = imx219_get_format_code(imx219, imx219_mbus_formatscode->index * 4); + } else { + if (code->index > 0) + return -EINVAL; @@ -71156,27 +107977,29 @@ return 0; } -@@ -819,23 +848,36 @@ static int imx219_enum_frame_size(struct v4l2_subdev *sd, - { +@@ -638,68 +756,109 @@ static int imx219_enum_frame_size(struct v4l2_subdev *sd, struct imx219 *imx219 = to_imx219(sd); + u32 code; - if (fse->index >= ARRAY_SIZE(supported_modes)) + if (fse->pad >= NUM_PADS) return -EINVAL; -- if (fse->code != imx219_get_format_code(imx219, fse->code)) +- code = imx219_get_format_code(imx219, fse->code); +- if (fse->code != code) - return -EINVAL; + if (fse->pad == IMAGE_PAD) { + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; ++ ++ code = imx219_get_format_code(imx219, fse->code); ++ if (fse->code != code) ++ return -EINVAL; - fse->min_width = supported_modesfse->index.width; - fse->max_width = fse->min_width; - fse->min_height = supported_modesfse->index.height; - fse->max_height = fse->min_height; -+ if (fse->code != imx219_get_format_code(imx219, fse->code)) -+ return -EINVAL; -+ + fse->min_width = supported_modesfse->index.width; + fse->max_width = fse->min_width; + fse->min_height = supported_modesfse->index.height; @@ -71194,98 +108017,40 @@ return 0; } - static void imx219_reset_colorspace(struct v4l2_mbus_framefmt *fmt) - { -- fmt->colorspace = V4L2_COLORSPACE_SRGB; -+ fmt->colorspace = V4L2_COLORSPACE_RAW; - fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); - fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, - fmt->colorspace, -@@ -843,9 +885,9 @@ static void imx219_reset_colorspace(struct v4l2_mbus_framefmt *fmt) - 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; -@@ -853,20 +895,38 @@ static void imx219_update_pad_format(struct imx219 *imx219, - imx219_reset_colorspace(&fmt->format); - } - -+static void imx219_update_metadata_pad_format(struct v4l2_subdev_format *fmt) ++static unsigned long imx219_get_pixel_rate(struct imx219 *imx219, ++ const struct v4l2_mbus_framefmt *format) +{ -+ 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; ++ return ((imx219->lanes == 2) ? IMX219_PIXEL_RATE : ++ IMX219_PIXEL_RATE_4LANE) * imx219_get_rate_factor(imx219, format); +} + - static int __imx219_get_pad_format(struct imx219 *imx219, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) + static int imx219_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + 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; -@@ -896,51 +956,74 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, - int exposure_max, exposure_def, hblank; - unsigned int i; - -- mutex_lock(&imx219->mutex); -- -- for (i = 0; i < ARRAY_SIZE(codes); i++) -- if (codesi == 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, codesi); -+ mutex_lock(&imx219->mutex); + struct imx219 *imx219 = to_imx219(sd); + const struct imx219_mode *mode; +- int exposure_max, exposure_def, hblank; ++ int exposure_max, exposure_def, hblank, pixel_rate; + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; - 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_update_pad_format(imx219, mode, &fmt->format, fmt->format.code); +- +- format = v4l2_subdev_get_pad_format(sd, sd_state, 0); +- crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0); +- +- *format = fmt->format; +- *crop = mode->crop; ++ if (fmt->pad >= NUM_PADS) ++ return -EINVAL; + +- if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - imx219->mode = mode; - /* Update limits and set FPS to default */ - __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN, @@ -71310,1086 +108075,1841 @@ - __v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1, - hblank); + if (fmt->pad == IMAGE_PAD) { -+ for (i = 0; i < ARRAY_SIZE(codes); i++) -+ if (codesi == fmt->format.code) -+ break; -+ if (i >= ARRAY_SIZE(codes)) -+ i = 0; -+ -+ /* Bayer order varies with flips */ -+ fmt->format.code = imx219_get_format_code(imx219, codesi); -+ + 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; ++ fmt->format.width, fmt->format.height); ++ ++ imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code); ++ ++ format = v4l2_subdev_get_pad_format(sd, sd_state, 0); ++ crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0); ++ ++ *format = fmt->format; ++ *crop = mode->crop; ++ ++ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { ++ u32 prev_hts = imx219->mode->width + imx219->hblank->val; ++ + 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, ++ __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 -+ */ ++ /* 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; ++ 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_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. ++ * Retain PPL setting from previous mode so that the ++ * line time does not change on a mode change. ++ * Limits have to be recomputed as the controls define ++ * the blanking only, so PPL values need to have the ++ * mode width subtracted. + */ -+ 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); -+ } ++ hblank = prev_hts - mode->width; ++ __v4l2_ctrl_modify_range(imx219->hblank, ++ IMX219_PPL_MIN - mode->width, ++ IMX219_PPL_MAX - mode->width, ++ 1, IMX219_PPL_MIN - mode->width); ++ __v4l2_ctrl_s_ctrl(imx219->hblank, hblank); ++ ++ /* Scale the pixel rate based on the mode specific factor */ ++ pixel_rate = imx219_get_pixel_rate(imx219, &fmt->format); ++ __v4l2_ctrl_modify_range(imx219->pixel_rate, pixel_rate, ++ pixel_rate, 1, pixel_rate); ++ } ++ } else { ++ format = v4l2_subdev_get_pad_format(sd, sd_state, 1); ++ /* Don't allow the embedded data format to be changed */ ++ fmt->format = *format; + } + + return 0; +@@ -730,24 +889,20 @@ static int imx219_set_framefmt(struct imx219 *imx219, + static int imx219_set_binning(struct imx219 *imx219, + const struct v4l2_mbus_framefmt *format) + { +- if (!imx219->mode->binning) ++ enum binning_mode binning = BINNING_NONE; ++ ++ imx219_resolve_binning(imx219, format, &binning); ++ ++ switch (binning) { ++ case BINNING_NONE: + return cci_write(imx219->regmap, IMX219_REG_BINNING_MODE, + IMX219_BINNING_NONE, NULL); +- +- switch (format->code) { +- case MEDIA_BUS_FMT_SRGGB8_1X8: +- case MEDIA_BUS_FMT_SGRBG8_1X8: +- case MEDIA_BUS_FMT_SGBRG8_1X8: +- case MEDIA_BUS_FMT_SBGGR8_1X8: ++ case BINNING_NORMAL_2x2: + return cci_write(imx219->regmap, IMX219_REG_BINNING_MODE, +- IMX219_BINNING_2X2_ANALOG, NULL); +- +- case MEDIA_BUS_FMT_SRGGB10_1X10: +- case MEDIA_BUS_FMT_SGRBG10_1X10: +- case MEDIA_BUS_FMT_SGBRG10_1X10: +- case MEDIA_BUS_FMT_SBGGR10_1X10: ++ IMX219_BINNING_2X2_NORMAL, NULL); ++ case BINNING_SPECIAL_2x2: + return cci_write(imx219->regmap, IMX219_REG_BINNING_MODE, +- IMX219_BINNING_2X2, NULL); ++ IMX219_BINNING_2X2_SPECIAL, NULL); } - mutex_unlock(&imx219->mutex); -@@ -1508,16 +1591,18 @@ static int imx219_probe(struct i2c_client *client) + return -EINVAL; +@@ -1053,11 +1208,6 @@ static const struct v4l2_subdev_ops imx219_subdev_ops = { + }; - /* 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; + +-static unsigned long imx219_get_pixel_rate(struct imx219 *imx219) +-{ +- return (imx219->lanes == 2) ? IMX219_PIXEL_RATE : IMX219_PIXEL_RATE_4LANE; +-} +- + /* Initialize control handlers */ + static int imx219_init_controls(struct imx219 *imx219) + { +@@ -1065,7 +1215,7 @@ static int imx219_init_controls(struct imx219 *imx219) + struct v4l2_ctrl_handler *ctrl_hdlr; + unsigned int height = imx219->mode->height; + struct v4l2_fwnode_device_properties props; +- int exposure_max, exposure_def, hblank; ++ int exposure_max, exposure_def, hblank, pixel_rate; + int i, ret; + + ctrl_hdlr = &imx219->ctrl_handler; +@@ -1074,11 +1224,11 @@ static int imx219_init_controls(struct imx219 *imx219) + return ret; + + /* By default, PIXEL_RATE is read only */ ++ pixel_rate = imx219_get_pixel_rate(imx219, NULL); + imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_PIXEL_RATE, +- imx219_get_pixel_rate(imx219), +- imx219_get_pixel_rate(imx219), 1, +- imx219_get_pixel_rate(imx219)); ++ pixel_rate, pixel_rate, 1, ++ pixel_rate); + + imx219->link_freq = + v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx219_ctrl_ops, +@@ -1094,12 +1244,11 @@ static int imx219_init_controls(struct imx219 *imx219) + V4L2_CID_VBLANK, IMX219_VBLANK_MIN, + IMX219_VTS_MAX - height, 1, + imx219->mode->vts_def - height); +- hblank = IMX219_PPL_DEFAULT - imx219->mode->width; ++ hblank = IMX219_PPL_MIN - imx219->mode->width; + imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, +- V4L2_CID_HBLANK, hblank, hblank, ++ V4L2_CID_HBLANK, hblank, ++ IMX219_PPL_MIN - imx219->mode->width, + 1, hblank); +- if (imx219->hblank) +- imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + exposure_max = imx219->mode->vts_def - 4; + exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? + exposure_max : IMX219_EXPOSURE_DEFAULT; +@@ -1319,9 +1468,10 @@ static int imx219_probe(struct i2c_client *client) imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; -- /* Initialize source pad */ + /* Initialize source pad */ - imx219->pad.flags = MEDIA_PAD_FL_SOURCE; -+ /* Initialize source pads */ + imx219->padIMAGE_PAD.flags = MEDIA_PAD_FL_SOURCE; + imx219->padMETADATA_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 --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c -index adcddf3204f7..def912308daa 100644 ---- a/drivers/media/i2c/imx290.c -+++ b/drivers/media/i2c/imx290.c -@@ -1,6 +1,12 @@ - // 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. - * -@@ -13,6 +19,7 @@ - #include <linux/gpio/consumer.h> +diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c +index e196565e846e..e30e14d63823 100644 +--- a/drivers/media/i2c/imx258.c ++++ b/drivers/media/i2c/imx258.c +@@ -7,6 +7,7 @@ #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> -@@ -22,15 +29,29 @@ ++#include <linux/regulator/consumer.h> + #include <media/v4l2-ctrls.h> + #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> - #include <media/v4l2-subdev.h> +@@ -19,6 +20,8 @@ + #define IMX258_MODE_STANDBY 0x00 + #define IMX258_MODE_STREAMING 0x01 + ++#define IMX258_REG_RESET 0x0103 ++ + /* Chip ID */ + #define IMX258_REG_CHIP_ID 0x0016 + #define IMX258_CHIP_ID 0x0258 +@@ -27,23 +30,20 @@ + #define IMX258_VTS_30FPS 0x0c50 + #define IMX258_VTS_30FPS_2K 0x0638 + #define IMX258_VTS_30FPS_VGA 0x034c +-#define IMX258_VTS_MAX 0xffff ++#define IMX258_VTS_MAX 65525 + +-/*Frame Length Line*/ +-#define IMX258_FLL_MIN 0x08a6 +-#define IMX258_FLL_MAX 0xffff +-#define IMX258_FLL_STEP 1 +-#define IMX258_FLL_DEFAULT 0x0c98 +- +-/* HBLANK control - read only */ +-#define IMX258_PPL_DEFAULT 5352 ++#define IMX258_REG_VTS 0x0340 + + /* Exposure control */ + #define IMX258_REG_EXPOSURE 0x0202 ++#define IMX258_EXPOSURE_OFFSET 10 + #define IMX258_EXPOSURE_MIN 4 + #define IMX258_EXPOSURE_STEP 1 + #define IMX258_EXPOSURE_DEFAULT 0x640 +-#define IMX258_EXPOSURE_MAX 65535 ++#define IMX258_EXPOSURE_MAX (IMX258_VTS_MAX - IMX258_EXPOSURE_OFFSET) ++ ++/* HBLANK control - read only */ ++#define IMX258_PPL_DEFAULT 5352 + + /* Analog gain control */ + #define IMX258_REG_ANALOG_GAIN 0x0204 +@@ -71,16 +71,28 @@ + #define IMX258_HDR_RATIO_STEP 1 + #define IMX258_HDR_RATIO_DEFAULT 0x0 -+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 -@@ -39,6 +60,13 @@ - #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", -@@ -56,18 +84,31 @@ struct imx290_mode { - u32 width; - u32 height; - u32 hmax; -+ u32 vmax; - u8 link_freq_index; -+ struct v4l2_rect crop; ++/* Long exposure multiplier */ ++#define IMX258_LONG_EXP_SHIFT_MAX 7 ++#define IMX258_LONG_EXP_SHIFT_REG 0x3002 + -+ const struct imx290_regval *mode_data; -+ u32 mode_data_size; -+ const struct imx290_regval *lane_data; -+ u32 lane_data_size; + /* Test Pattern Control */ + #define IMX258_REG_TEST_PATTERN 0x0600 + ++#define IMX258_CLK_BLANK_STOP 0x4040 + + /* Orientation */ + #define REG_MIRROR_FLIP_CONTROL 0x0101 +-#define REG_CONFIG_MIRROR_FLIP 0x03 ++#define REG_CONFIG_MIRROR_HFLIP 0x01 ++#define REG_CONFIG_MIRROR_VFLIP 0x02 + #define REG_CONFIG_FLIP_TEST_PATTERN 0x02 + +-/* Input clock frequency in Hz */ +-#define IMX258_INPUT_CLOCK_FREQ 19200000 ++/* IMX258 native and active pixel array size. */ ++#define IMX258_NATIVE_WIDTH 4224U ++#define IMX258_NATIVE_HEIGHT 3192U ++#define IMX258_PIXEL_ARRAY_LEFT 8U ++#define IMX258_PIXEL_ARRAY_TOP 16U ++#define IMX258_PIXEL_ARRAY_WIDTH 4208U ++#define IMX258_PIXEL_ARRAY_HEIGHT 3120U -- const struct imx290_regval *data; -- u32 data_size; -+ /* Clock setup can vary. Index as enum imx290_clk_index */ -+ const struct imx290_regval *clk_data2; -+ u32 clk_size; + struct imx258_reg { + u16 address; +@@ -92,12 +104,22 @@ struct imx258_reg_list { + const struct imx258_reg *regs; }; - struct imx290 { - struct device *dev; - struct clk *xclk; -+ u32 xclk_freq; - struct regmap *regmap; - u8 nlanes; - u8 bpp; -+ u16 hmax_min; ++struct imx258_link_cfg { ++ unsigned int lf_to_pix_rate_factor; ++ struct imx258_reg_list reg_list; ++}; + -+ const struct imx290_pixfmt *formats; - - struct v4l2_subdev sd; - struct media_pad pad; -@@ -80,6 +121,11 @@ struct imx290 { - 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; ++#define IMX258_LANE_CONFIGS 2 ++#define IMX258_2_LANE_MODE 0 ++#define IMX258_4_LANE_MODE 1 ++ + /* Link frequency config */ + struct imx258_link_freq_config { ++ u64 link_frequency; + u32 pixels_per_line; - struct mutex lock; - }; -@@ -89,11 +135,18 @@ struct imx290_pixfmt { - u8 bpp; +- /* PLL registers for this link frequency */ +- struct imx258_reg_list reg_list; ++ /* Configuration for this link frequency / num lanes selection */ ++ struct imx258_link_cfg link_cfgIMX258_LANE_CONFIGS; }; --static const struct imx290_pixfmt imx290_formats = { -+#define IMX290_NUM_FORMATS 2 + /* Mode : resolution and related config&values */ +@@ -115,10 +137,37 @@ struct imx258_mode { + u32 link_freq_index; + /* Default register values */ + struct imx258_reg_list reg_list; ++ ++ /* Analog crop rectangle. */ ++ struct v4l2_rect crop; ++}; ++ ++/* 4208x3120 needs 1267Mbps/lane, 4 lanes. Use that rate on 2 lanes as well */ ++static const struct imx258_reg mipi_1267mbps_19_2mhz_2l = { ++ { 0x0136, 0x13 }, ++ { 0x0137, 0x33 }, ++ { 0x0301, 0x0A }, ++ { 0x0303, 0x02 }, ++ { 0x0305, 0x03 }, ++ { 0x0306, 0x00 }, ++ { 0x0307, 0xC6 }, ++ { 0x0309, 0x0A }, ++ { 0x030B, 0x01 }, ++ { 0x030D, 0x02 }, ++ { 0x030E, 0x00 }, ++ { 0x030F, 0xD8 }, ++ { 0x0310, 0x00 }, ++ ++ { 0x0114, 0x01 }, ++ { 0x0820, 0x09 }, ++ { 0x0821, 0xa6 }, ++ { 0x0822, 0x66 }, ++ { 0x0823, 0x66 }, + }; + +-/* 4208x3118 needs 1267Mbps/lane, 4 lanes */ +-static const struct imx258_reg mipi_data_rate_1267mbps = { ++static const struct imx258_reg mipi_1267mbps_19_2mhz_4l = { ++ { 0x0136, 0x13 }, ++ { 0x0137, 0x33 }, + { 0x0301, 0x05 }, + { 0x0303, 0x02 }, + { 0x0305, 0x03 }, +@@ -130,13 +179,61 @@ static const struct imx258_reg mipi_data_rate_1267mbps = { + { 0x030E, 0x00 }, + { 0x030F, 0xD8 }, + { 0x0310, 0x00 }, ++ ++ { 0x0114, 0x03 }, + { 0x0820, 0x13 }, + { 0x0821, 0x4C }, + { 0x0822, 0xCC }, + { 0x0823, 0xCC }, + }; + +-static const struct imx258_reg mipi_data_rate_640mbps = { ++static const struct imx258_reg mipi_1272mbps_24mhz_2l = { ++ { 0x0136, 0x18 }, ++ { 0x0137, 0x00 }, ++ { 0x0301, 0x0a }, ++ { 0x0303, 0x02 }, ++ { 0x0305, 0x04 }, ++ { 0x0306, 0x00 }, ++ { 0x0307, 0xD4 }, ++ { 0x0309, 0x0A }, ++ { 0x030B, 0x01 }, ++ { 0x030D, 0x02 }, ++ { 0x030E, 0x00 }, ++ { 0x030F, 0xD8 }, ++ { 0x0310, 0x00 }, ++ ++ { 0x0114, 0x01 }, ++ { 0x0820, 0x13 }, ++ { 0x0821, 0x4C }, ++ { 0x0822, 0xCC }, ++ { 0x0823, 0xCC }, ++}; ++ ++static const struct imx258_reg mipi_1272mbps_24mhz_4l = { ++ { 0x0136, 0x18 }, ++ { 0x0137, 0x00 }, ++ { 0x0301, 0x05 }, ++ { 0x0303, 0x02 }, ++ { 0x0305, 0x04 }, ++ { 0x0306, 0x00 }, ++ { 0x0307, 0xD4 }, ++ { 0x0309, 0x0A }, ++ { 0x030B, 0x01 }, ++ { 0x030D, 0x02 }, ++ { 0x030E, 0x00 }, ++ { 0x030F, 0xD8 }, ++ { 0x0310, 0x00 }, ++ ++ { 0x0114, 0x03 }, ++ { 0x0820, 0x13 }, ++ { 0x0821, 0xE0 }, ++ { 0x0822, 0x00 }, ++ { 0x0823, 0x00 }, ++}; ++ ++static const struct imx258_reg mipi_640mbps_19_2mhz_2l = { ++ { 0x0136, 0x13 }, ++ { 0x0137, 0x33 }, + { 0x0301, 0x05 }, + { 0x0303, 0x02 }, + { 0x0305, 0x03 }, +@@ -148,18 +245,82 @@ static const struct imx258_reg mipi_data_rate_640mbps = { + { 0x030E, 0x00 }, + { 0x030F, 0xD8 }, + { 0x0310, 0x00 }, +- { 0x0820, 0x0A }, ++ ++ { 0x0114, 0x01 }, ++ { 0x0820, 0x05 }, + { 0x0821, 0x00 }, + { 0x0822, 0x00 }, + { 0x0823, 0x00 }, + }; + +-static const struct imx258_reg mode_4208x3118_regs = { ++static const struct imx258_reg mipi_640mbps_19_2mhz_4l = { + { 0x0136, 0x13 }, + { 0x0137, 0x33 }, ++ { 0x0301, 0x05 }, ++ { 0x0303, 0x02 }, ++ { 0x0305, 0x03 }, ++ { 0x0306, 0x00 }, ++ { 0x0307, 0x64 }, ++ { 0x0309, 0x0A }, ++ { 0x030B, 0x01 }, ++ { 0x030D, 0x02 }, ++ { 0x030E, 0x00 }, ++ { 0x030F, 0xD8 }, ++ { 0x0310, 0x00 }, ++ ++ { 0x0114, 0x03 }, ++ { 0x0820, 0x0A }, ++ { 0x0821, 0x00 }, ++ { 0x0822, 0x00 }, ++ { 0x0823, 0x00 }, ++}; ++ ++static const struct imx258_reg mipi_642mbps_24mhz_2l = { ++ { 0x0136, 0x18 }, ++ { 0x0137, 0x00 }, ++ { 0x0301, 0x05 }, ++ { 0x0303, 0x02 }, ++ { 0x0305, 0x04 }, ++ { 0x0306, 0x00 }, ++ { 0x0307, 0x6B }, ++ { 0x0309, 0x0A }, ++ { 0x030B, 0x01 }, ++ { 0x030D, 0x02 }, ++ { 0x030E, 0x00 }, ++ { 0x030F, 0xD8 }, ++ { 0x0310, 0x00 }, ++ ++ { 0x0114, 0x01 }, ++ { 0x0820, 0x0A }, ++ { 0x0821, 0x00 }, ++ { 0x0822, 0x00 }, ++ { 0x0823, 0x00 }, ++}; ++ ++static const struct imx258_reg mipi_642mbps_24mhz_4l = { ++ { 0x0136, 0x18 }, ++ { 0x0137, 0x00 }, ++ { 0x0301, 0x05 }, ++ { 0x0303, 0x02 }, ++ { 0x0305, 0x04 }, ++ { 0x0306, 0x00 }, ++ { 0x0307, 0x6B }, ++ { 0x0309, 0x0A }, ++ { 0x030B, 0x01 }, ++ { 0x030D, 0x02 }, ++ { 0x030E, 0x00 }, ++ { 0x030F, 0xD8 }, ++ { 0x0310, 0x00 }, ++ ++ { 0x0114, 0x03 }, ++ { 0x0820, 0x0A }, ++ { 0x0821, 0x00 }, ++ { 0x0822, 0x00 }, ++ { 0x0823, 0x00 }, ++}; ++ ++static const struct imx258_reg mode_4208x3120_regs = { + { 0x3051, 0x00 }, +- { 0x3052, 0x00 }, +- { 0x4E21, 0x14 }, + { 0x6B11, 0xCF }, + { 0x7FF0, 0x08 }, + { 0x7FF1, 0x0F }, +@@ -182,7 +343,6 @@ static const struct imx258_reg mode_4208x3118_regs = { + { 0x7FA8, 0x03 }, + { 0x7FA9, 0xFE }, + { 0x7B24, 0x81 }, +- { 0x7B25, 0x00 }, + { 0x6564, 0x07 }, + { 0x6B0D, 0x41 }, + { 0x653D, 0x04 }, +@@ -204,11 +364,8 @@ static const struct imx258_reg mode_4208x3118_regs = { + { 0x5F05, 0xED }, + { 0x0112, 0x0A }, + { 0x0113, 0x0A }, +- { 0x0114, 0x03 }, + { 0x0342, 0x14 }, + { 0x0343, 0xE8 }, +- { 0x0340, 0x0C }, +- { 0x0341, 0x50 }, + { 0x0344, 0x00 }, + { 0x0345, 0x00 }, + { 0x0346, 0x00 }, +@@ -216,7 +373,7 @@ static const struct imx258_reg mode_4208x3118_regs = { + { 0x0348, 0x10 }, + { 0x0349, 0x6F }, + { 0x034A, 0x0C }, +- { 0x034B, 0x2E }, ++ { 0x034B, 0x2F }, + { 0x0381, 0x01 }, + { 0x0383, 0x01 }, + { 0x0385, 0x01 }, +@@ -242,9 +399,7 @@ static const struct imx258_reg mode_4208x3118_regs = { + { 0x034D, 0x70 }, + { 0x034E, 0x0C }, + { 0x034F, 0x30 }, +- { 0x0350, 0x01 }, +- { 0x0202, 0x0C }, +- { 0x0203, 0x46 }, ++ { 0x0350, 0x00 }, + { 0x0204, 0x00 }, + { 0x0205, 0x00 }, + { 0x020E, 0x01 }, +@@ -274,11 +429,7 @@ static const struct imx258_reg mode_4208x3118_regs = { + }; + + static const struct imx258_reg mode_2104_1560_regs = { +- { 0x0136, 0x13 }, +- { 0x0137, 0x33 }, + { 0x3051, 0x00 }, +- { 0x3052, 0x00 }, +- { 0x4E21, 0x14 }, + { 0x6B11, 0xCF }, + { 0x7FF0, 0x08 }, + { 0x7FF1, 0x0F }, +@@ -301,7 +452,6 @@ static const struct imx258_reg mode_2104_1560_regs = { + { 0x7FA8, 0x03 }, + { 0x7FA9, 0xFE }, + { 0x7B24, 0x81 }, +- { 0x7B25, 0x00 }, + { 0x6564, 0x07 }, + { 0x6B0D, 0x41 }, + { 0x653D, 0x04 }, +@@ -323,11 +473,8 @@ static const struct imx258_reg mode_2104_1560_regs = { + { 0x5F05, 0xED }, + { 0x0112, 0x0A }, + { 0x0113, 0x0A }, +- { 0x0114, 0x03 }, + { 0x0342, 0x14 }, + { 0x0343, 0xE8 }, +- { 0x0340, 0x06 }, +- { 0x0341, 0x38 }, + { 0x0344, 0x00 }, + { 0x0345, 0x00 }, + { 0x0346, 0x00 }, +@@ -335,7 +482,7 @@ static const struct imx258_reg mode_2104_1560_regs = { + { 0x0348, 0x10 }, + { 0x0349, 0x6F }, + { 0x034A, 0x0C }, +- { 0x034B, 0x2E }, ++ { 0x034B, 0x2F }, + { 0x0381, 0x01 }, + { 0x0383, 0x01 }, + { 0x0385, 0x01 }, +@@ -346,11 +493,11 @@ static const struct imx258_reg mode_2104_1560_regs = { + { 0x0404, 0x00 }, + { 0x0405, 0x20 }, + { 0x0408, 0x00 }, +- { 0x0409, 0x02 }, ++ { 0x0409, 0x00 }, + { 0x040A, 0x00 }, + { 0x040B, 0x00 }, + { 0x040C, 0x10 }, +- { 0x040D, 0x6A }, ++ { 0x040D, 0x70 }, + { 0x040E, 0x06 }, + { 0x040F, 0x18 }, + { 0x3038, 0x00 }, +@@ -361,9 +508,7 @@ static const struct imx258_reg mode_2104_1560_regs = { + { 0x034D, 0x38 }, + { 0x034E, 0x06 }, + { 0x034F, 0x18 }, +- { 0x0350, 0x01 }, +- { 0x0202, 0x06 }, +- { 0x0203, 0x2E }, ++ { 0x0350, 0x00 }, + { 0x0204, 0x00 }, + { 0x0205, 0x00 }, + { 0x020E, 0x01 }, +@@ -393,11 +538,7 @@ static const struct imx258_reg mode_2104_1560_regs = { + }; + + static const struct imx258_reg mode_1048_780_regs = { +- { 0x0136, 0x13 }, +- { 0x0137, 0x33 }, + { 0x3051, 0x00 }, +- { 0x3052, 0x00 }, +- { 0x4E21, 0x14 }, + { 0x6B11, 0xCF }, + { 0x7FF0, 0x08 }, + { 0x7FF1, 0x0F }, +@@ -420,7 +561,6 @@ static const struct imx258_reg mode_1048_780_regs = { + { 0x7FA8, 0x03 }, + { 0x7FA9, 0xFE }, + { 0x7B24, 0x81 }, +- { 0x7B25, 0x00 }, + { 0x6564, 0x07 }, + { 0x6B0D, 0x41 }, + { 0x653D, 0x04 }, +@@ -442,11 +582,8 @@ static const struct imx258_reg mode_1048_780_regs = { + { 0x5F05, 0xED }, + { 0x0112, 0x0A }, + { 0x0113, 0x0A }, +- { 0x0114, 0x03 }, + { 0x0342, 0x14 }, + { 0x0343, 0xE8 }, +- { 0x0340, 0x03 }, +- { 0x0341, 0x4C }, + { 0x0344, 0x00 }, + { 0x0345, 0x00 }, + { 0x0346, 0x00 }, +@@ -454,7 +591,7 @@ static const struct imx258_reg mode_1048_780_regs = { + { 0x0348, 0x10 }, + { 0x0349, 0x6F }, + { 0x034A, 0x0C }, +- { 0x034B, 0x2E }, ++ { 0x034B, 0x2F }, + { 0x0381, 0x01 }, + { 0x0383, 0x01 }, + { 0x0385, 0x01 }, +@@ -465,11 +602,11 @@ static const struct imx258_reg mode_1048_780_regs = { + { 0x0404, 0x00 }, + { 0x0405, 0x40 }, + { 0x0408, 0x00 }, +- { 0x0409, 0x06 }, ++ { 0x0409, 0x00 }, + { 0x040A, 0x00 }, + { 0x040B, 0x00 }, + { 0x040C, 0x10 }, +- { 0x040D, 0x64 }, ++ { 0x040D, 0x70 }, + { 0x040E, 0x03 }, + { 0x040F, 0x0C }, + { 0x3038, 0x00 }, +@@ -480,9 +617,7 @@ static const struct imx258_reg mode_1048_780_regs = { + { 0x034D, 0x18 }, + { 0x034E, 0x03 }, + { 0x034F, 0x0C }, +- { 0x0350, 0x01 }, +- { 0x0202, 0x03 }, +- { 0x0203, 0x42 }, ++ { 0x0350, 0x00 }, + { 0x0204, 0x00 }, + { 0x0205, 0x00 }, + { 0x020E, 0x01 }, +@@ -511,6 +646,50 @@ static const struct imx258_reg mode_1048_780_regs = { + { 0x0220, 0x00 }, + }; + ++struct imx258_variant_cfg { ++ const struct imx258_reg *regs; ++ unsigned int num_regs; ++}; ++ ++static const struct imx258_reg imx258_cfg_regs = { ++ { 0x3052, 0x00 }, ++ { 0x4E21, 0x14 }, ++ { 0x7B25, 0x00 }, ++}; ++ ++static const struct imx258_variant_cfg imx258_cfg = { ++ .regs = imx258_cfg_regs, ++ .num_regs = ARRAY_SIZE(imx258_cfg_regs), ++}; ++ ++static const struct imx258_reg imx258_pdaf_cfg_regs = { ++ { 0x3052, 0x01 }, ++ { 0x4E21, 0x10 }, ++ { 0x7B25, 0x01 }, ++}; ++ ++static const struct imx258_variant_cfg imx258_pdaf_cfg = { ++ .regs = imx258_pdaf_cfg_regs, ++ .num_regs = ARRAY_SIZE(imx258_pdaf_cfg_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 = { ++ /* 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 struct imx290_pixfmt imx290_colour_formatsIMX290_NUM_FORMATS = { - { MEDIA_BUS_FMT_SRGGB10_1X10, 10 }, - { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, + static const char * const imx258_test_pattern_menu = { + "Disabled", + "Solid Colour", +@@ -519,9 +698,15 @@ static const char * const imx258_test_pattern_menu = { + "Pseudorandom Sequence (PN9)", }; -+static const struct imx290_pixfmt imx290_mono_formatsIMX290_NUM_FORMATS = { -+ { MEDIA_BUS_FMT_Y10_1X10, 10 }, -+ { MEDIA_BUS_FMT_Y12_1X12, 12 }, +-/* Configurations for supported link frequencies */ +-#define IMX258_LINK_FREQ_634MHZ 633600000ULL +-#define IMX258_LINK_FREQ_320MHZ 320000000ULL ++/* regulator supplies */ ++static const char * const imx258_supply_name = { ++ /* Supplies can be enabled in any order */ ++ "vana", /* Analog (2.8V) supply */ ++ "vdig", /* Digital Core (1.05V) supply */ ++ "vif", /* IF (1.8V) supply */ +}; + - static const struct regmap_config imx290_regmap_config = { - .reg_bits = 16, - .val_bits = 8, -@@ -113,11 +166,7 @@ static const char * const imx290_test_pattern_menu = { ++#define IMX258_NUM_SUPPLIES ARRAY_SIZE(imx258_supply_name) - 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 }, -@@ -171,8 +220,33 @@ static const struct imx290_regval imx290_global_init_settings = { - { 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 }, -@@ -182,15 +256,36 @@ static const struct imx290_regval imx290_1080p_settings = { - { 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 }, -@@ -209,8 +304,33 @@ static const struct imx290_regval imx290_1080p_settings = { - { 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 }, -@@ -220,15 +340,36 @@ static const struct imx290_regval imx290_720p_settings = { - { 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 }, -@@ -308,18 +449,46 @@ static const struct imx290_mode imx290_modes_2lanes = { - { - .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), + enum { + IMX258_LINK_FREQ_1267MBPS, +@@ -529,37 +714,103 @@ enum { + }; + + /* +- * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample +- * data rate => double data rate; number of lanes => 4; bits per pixel => 10 ++ * Pixel rate does not necessarily relate to link frequency on this sensor as ++ * there is a FIFO between the pixel array pipeline and the MIPI serializer. ++ * The recommendation from Sony is that the pixel array is always run with a ++ * line length of 5352 pixels, which means that there is a large amount of ++ * blanking time for the 1048x780 mode. There is no need to replicate this ++ * blanking on the CSI2 bus, and the configuration of register 0x0301 allows the ++ * divider to be altered. ++ * ++ * The actual factor between link frequency and pixel rate is in the ++ * imx258_link_cfg, so use this to convert between the two. ++ * bits per pixel being 10, and D-PHY being DDR is assumed by this function, so ++ * the value is only the combination of number of lanes and pixel clock divider. + */ +-static u64 link_freq_to_pixel_rate(u64 f) ++static u64 link_freq_to_pixel_rate(u64 f, const struct imx258_link_cfg *link_cfg) + { +- f *= 2 * 4; ++ f *= 2 * link_cfg->lf_to_pix_rate_factor; + do_div(f, 10); + + return f; + } + + /* Menu items for LINK_FREQ V4L2 control */ +-static const s64 link_freq_menu_items = { ++/* Configurations for supported link frequencies */ ++#define IMX258_LINK_FREQ_634MHZ 633600000ULL ++#define IMX258_LINK_FREQ_320MHZ 320000000ULL ++ ++static const s64 link_freq_menu_items_19_2 = { + IMX258_LINK_FREQ_634MHZ, + IMX258_LINK_FREQ_320MHZ, + }; + ++/* Configurations for supported link frequencies */ ++#define IMX258_LINK_FREQ_636MHZ 636000000ULL ++#define IMX258_LINK_FREQ_321MHZ 321000000ULL ++ ++static const s64 link_freq_menu_items_24 = { ++ IMX258_LINK_FREQ_636MHZ, ++ IMX258_LINK_FREQ_321MHZ, ++}; ++ ++#define REGS(_list) { .num_of_regs = ARRAY_SIZE(_list), .regs = _list, } ++ + /* Link frequency configs */ +-static const struct imx258_link_freq_config link_freq_configs = { ++static const struct imx258_link_freq_config link_freq_configs_19_2 = { + IMX258_LINK_FREQ_1267MBPS = { + .pixels_per_line = IMX258_PPL_DEFAULT, +- .reg_list = { +- .num_of_regs = ARRAY_SIZE(mipi_data_rate_1267mbps), +- .regs = mipi_data_rate_1267mbps, ++ .link_cfg = { ++ IMX258_2_LANE_MODE = { ++ .lf_to_pix_rate_factor = 2 * 2, ++ .reg_list = REGS(mipi_1267mbps_19_2mhz_2l), ++ }, ++ IMX258_4_LANE_MODE = { ++ .lf_to_pix_rate_factor = 4, ++ .reg_list = REGS(mipi_1267mbps_19_2mhz_4l), ++ }, + } + }, + IMX258_LINK_FREQ_640MBPS = { + .pixels_per_line = IMX258_PPL_DEFAULT, +- .reg_list = { +- .num_of_regs = ARRAY_SIZE(mipi_data_rate_640mbps), +- .regs = mipi_data_rate_640mbps, ++ .link_cfg = { ++ IMX258_2_LANE_MODE = { ++ .lf_to_pix_rate_factor = 2, ++ .reg_list = REGS(mipi_640mbps_19_2mhz_2l), ++ }, ++ IMX258_4_LANE_MODE = { ++ .lf_to_pix_rate_factor = 4, ++ .reg_list = REGS(mipi_640mbps_19_2mhz_4l), ++ }, ++ } ++ }, ++}; ++ ++static const struct imx258_link_freq_config link_freq_configs_24 = { ++ IMX258_LINK_FREQ_1267MBPS = { ++ .pixels_per_line = IMX258_PPL_DEFAULT, ++ .link_cfg = { ++ IMX258_2_LANE_MODE = { ++ .lf_to_pix_rate_factor = 2, ++ .reg_list = REGS(mipi_1272mbps_24mhz_2l), ++ }, ++ IMX258_4_LANE_MODE = { ++ .lf_to_pix_rate_factor = 4, ++ .reg_list = REGS(mipi_1272mbps_24mhz_4l), ++ }, ++ } ++ }, ++ IMX258_LINK_FREQ_640MBPS = { ++ .pixels_per_line = IMX258_PPL_DEFAULT, ++ .link_cfg = { ++ IMX258_2_LANE_MODE = { ++ .lf_to_pix_rate_factor = 2 * 2, ++ .reg_list = REGS(mipi_642mbps_24mhz_2l), ++ }, ++ IMX258_4_LANE_MODE = { ++ .lf_to_pix_rate_factor = 4, ++ .reg_list = REGS(mipi_642mbps_24mhz_4l), ++ }, + } }, + }; +@@ -568,14 +819,20 @@ static const struct imx258_link_freq_config link_freq_configs = { + static const struct imx258_mode supported_modes = { { - .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), + .width = 4208, +- .height = 3118, ++ .height = 3120, + .vts_def = IMX258_VTS_30FPS, + .vts_min = IMX258_VTS_30FPS, + .reg_list = { +- .num_of_regs = ARRAY_SIZE(mode_4208x3118_regs), +- .regs = mode_4208x3118_regs, ++ .num_of_regs = ARRAY_SIZE(mode_4208x3120_regs), ++ .regs = mode_4208x3120_regs, + }, + .link_freq_index = IMX258_LINK_FREQ_1267MBPS, + .crop = { -+ .left = 4 + 8 + 320, -+ .top = 12 + 8 + 180, -+ .width = 1280, -+ .height = 720, ++ .left = IMX258_PIXEL_ARRAY_LEFT, ++ .top = IMX258_PIXEL_ARRAY_TOP, ++ .width = 4208, ++ .height = 3120, + }, -+ .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), }, - }; - -@@ -328,17 +497,45 @@ static const struct imx290_mode imx290_modes_4lanes = { - .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), + { + .width = 2104, +@@ -587,6 +844,12 @@ static const struct imx258_mode supported_modes = { + .regs = mode_2104_1560_regs, + }, + .link_freq_index = IMX258_LINK_FREQ_640MBPS, + .crop = { -+ .left = 4 + 8, -+ .top = 12 + 8, -+ .width = 1920, -+ .height = 1080, ++ .left = IMX258_PIXEL_ARRAY_LEFT, ++ .top = IMX258_PIXEL_ARRAY_TOP, ++ .width = 4208, ++ .height = 3120, + }, -+ .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), + .width = 1048, +@@ -598,6 +861,12 @@ static const struct imx258_mode supported_modes = { + .regs = mode_1048_780_regs, + }, + .link_freq_index = IMX258_LINK_FREQ_640MBPS, + .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, ++ .left = IMX258_PIXEL_ARRAY_LEFT, ++ .top = IMX258_PIXEL_ARRAY_TOP, ++ .width = 4208, ++ .height = 3120, + }, -+ .clk_size = ARRAY_SIZE(imx290_37_125mhz_clock_720p), }, }; -@@ -452,6 +649,64 @@ static int imx290_set_gain(struct imx290 *imx290, u32 value) - return ret; +@@ -605,6 +874,8 @@ struct imx258 { + struct v4l2_subdev sd; + struct media_pad pad; + ++ const struct imx258_variant_cfg *variant_cfg; ++ + struct v4l2_ctrl_handler ctrl_handler; + /* V4L2 Controls */ + struct v4l2_ctrl *link_freq; +@@ -612,10 +883,19 @@ struct imx258 { + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *exposure; ++ struct v4l2_ctrl *hflip; ++ struct v4l2_ctrl *vflip; ++ /* Current long exposure factor in use. Set through V4L2_CID_VBLANK */ ++ unsigned int long_exp_shift; + + /* Current mode */ + const struct imx258_mode *cur_mode; + ++ const struct imx258_link_freq_config *link_freq_configs; ++ const s64 *link_freq_menu_items; ++ unsigned int lane_mode_idx; ++ unsigned int csi2_flags; ++ + /* + * Mutex for serialized access: + * Protect sensor module set pad format and start/stop streaming safely. +@@ -626,6 +906,7 @@ struct imx258 { + bool streaming; + + struct clk *clk; ++ struct regulator_bulk_data suppliesIMX258_NUM_SUPPLIES; + }; + + static inline struct imx258 *to_imx258(struct v4l2_subdev *_sd) +@@ -707,18 +988,39 @@ static int imx258_write_regs(struct imx258 *imx258, + return 0; } -+static int imx290_set_exposure(struct imx290 *imx290, u32 value) ++/* Get bayer order based on flip setting. */ ++static u32 imx258_get_format_code(struct imx258 *imx258) +{ -+ u32 exposure = (imx290->current_mode->height + imx290->vblank->val) - -+ value - 1; -+ int ret; ++ unsigned int i; + -+ ret = imx290_write_buffered_reg(imx290, IMX290_EXPOSURE_LOW, 3, -+ exposure); -+ if (ret) -+ dev_err(imx290->dev, "Unable to write exposure\n"); ++ lockdep_assert_held(&imx258->mutex); + -+ return ret; ++ i = (imx258->vflip->val ? 2 : 0) | ++ (imx258->hflip->val ? 1 : 0); ++ ++ return codesi; +} + /* Open sub-device */ + static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) + { ++ struct imx258 *imx258 = to_imx258(sd); + struct v4l2_mbus_framefmt *try_fmt = + v4l2_subdev_get_try_format(sd, fh->state, 0); ++ struct v4l2_rect *try_crop; + + /* Initialize try_fmt */ + try_fmt->width = supported_modes0.width; + try_fmt->height = supported_modes0.height; +- try_fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; ++ try_fmt->code = imx258_get_format_code(imx258); + try_fmt->field = V4L2_FIELD_NONE; + ++ /* Initialize try_crop */ ++ try_crop = v4l2_subdev_get_try_crop(sd, fh->state, 0); ++ try_crop->left = IMX258_PIXEL_ARRAY_LEFT; ++ try_crop->top = IMX258_PIXEL_ARRAY_TOP; ++ try_crop->width = IMX258_PIXEL_ARRAY_WIDTH; ++ try_crop->height = IMX258_PIXEL_ARRAY_HEIGHT; + -+static int imx290_set_hmax(struct imx290 *imx290, u32 val) + return 0; + } + +@@ -749,6 +1051,39 @@ static int imx258_update_digital_gain(struct imx258 *imx258, u32 len, u32 val) + return 0; + } + ++static void imx258_adjust_exposure_range(struct imx258 *imx258) +{ -+ 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"); ++ int exposure_max, exposure_def; + -+ return ret; ++ /* Honour the VBLANK limits when setting exposure. */ ++ exposure_max = imx258->cur_mode->height + imx258->vblank->val - ++ IMX258_EXPOSURE_OFFSET; ++ exposure_def = min(exposure_max, imx258->exposure->val); ++ __v4l2_ctrl_modify_range(imx258->exposure, imx258->exposure->minimum, ++ exposure_max, imx258->exposure->step, ++ exposure_def); +} + -+static int imx290_set_vmax(struct imx290 *imx290, u32 val) ++static int imx258_set_frame_length(struct imx258 *imx258, unsigned int 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"); ++ imx258->long_exp_shift = 0; + -+ /* -+ * 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); ++ while (val > IMX258_VTS_MAX) { ++ imx258->long_exp_shift++; ++ val >>= 1; ++ } + -+ /* -+ * 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); ++ ret = imx258_write_reg(imx258, IMX258_REG_VTS, ++ IMX258_REG_VALUE_16BIT, val); ++ if (ret) ++ return ret; + -+ return ret; ++ return imx258_write_reg(imx258, IMX258_LONG_EXP_SHIFT_REG, ++ IMX258_REG_VALUE_08BIT, imx258->long_exp_shift); +} + - /* Stop streaming */ - static int imx290_stop_streaming(struct imx290 *imx290) + static int imx258_set_ctrl(struct v4l2_ctrl *ctrl) { -@@ -471,15 +726,35 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) - struct imx290 *imx290 = container_of(ctrl->handler, - struct imx290, ctrls); + struct imx258 *imx258 = +@@ -756,6 +1091,13 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl) + struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); 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); ++ /* ++ * The VBLANK control may change the limits of usable exposure, so check ++ * and adjust if necessary. ++ */ ++ if (ctrl->id == V4L2_CID_VBLANK) ++ imx258_adjust_exposure_range(imx258); ++ + /* + * Applying V4L2 control value only happens + * when power is up for streaming +@@ -772,7 +1114,7 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_EXPOSURE: + ret = imx258_write_reg(imx258, IMX258_REG_EXPOSURE, + IMX258_REG_VALUE_16BIT, +- ctrl->val); ++ ctrl->val >> imx258->long_exp_shift); + break; + case V4L2_CID_DIGITAL_GAIN: + ret = imx258_update_digital_gain(imx258, IMX258_REG_VALUE_16BIT, +@@ -782,10 +1124,6 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl) + ret = imx258_write_reg(imx258, IMX258_REG_TEST_PATTERN, + IMX258_REG_VALUE_16BIT, + ctrl->val); +- ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL, +- IMX258_REG_VALUE_08BIT, +- !ctrl->val ? REG_CONFIG_MIRROR_FLIP : +- REG_CONFIG_FLIP_TEST_PATTERN); + break; + case V4L2_CID_WIDE_DYNAMIC_RANGE: + if (!ctrl->val) { +@@ -803,6 +1141,19 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl) + BIT(IMX258_HDR_RATIO_MAX)); + } 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); ++ ret = imx258_set_frame_length(imx258, ++ imx258->cur_mode->height + 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); ++ case V4L2_CID_HFLIP: ++ ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL, ++ IMX258_REG_VALUE_08BIT, ++ (imx258->hflip->val ? ++ REG_CONFIG_MIRROR_HFLIP : 0) | ++ (imx258->vflip->val ? ++ REG_CONFIG_MIRROR_VFLIP : 0)); + break; - case V4L2_CID_TEST_PATTERN: - if (ctrl->val) { - imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW, 0x00); -@@ -519,10 +794,12 @@ static int imx290_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) + default: + dev_info(&client->dev, + "ctrl(id:0x%x,val:0x%x) is not handled\n", +@@ -824,11 +1175,13 @@ static int imx258_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) { -- if (code->index >= ARRAY_SIZE(imx290_formats)) -+ const struct imx290 *imx290 = to_imx290(sd); +- /* Only one bayer order(GRBG) is supported */ ++ struct imx258 *imx258 = to_imx258(sd); + -+ if (code->index >= IMX290_NUM_FORMATS) ++ /* Only one bayer format (10 bit) is supported */ + if (code->index > 0) return -EINVAL; -- code->code = imx290_formatscode->index.code; -+ code->code = imx290->formatscode->index.code; +- code->code = MEDIA_BUS_FMT_SGRBG10_1X10; ++ code->code = imx258_get_format_code(imx258); return 0; } -@@ -534,8 +811,8 @@ static int imx290_enum_frame_size(struct v4l2_subdev *sd, - const struct imx290 *imx290 = to_imx290(sd); - const struct imx290_mode *imx290_modes = imx290_modes_ptr(imx290); - -- if ((fse->code != imx290_formats0.code) && -- (fse->code != imx290_formats1.code)) -+ if (fse->code != imx290->formats0.code && -+ fse->code != imx290->formats1.code) +@@ -837,10 +1190,11 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) + { ++ struct imx258 *imx258 = to_imx258(sd); + if (fse->index >= ARRAY_SIZE(supported_modes)) return -EINVAL; - if (fse->index >= imx290_modes_num(imx290)) -@@ -576,23 +853,9 @@ static inline u8 imx290_get_link_freq_index(struct imx290 *imx290) - return imx290->current_mode->link_freq_index; - } +- if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) ++ if (fse->code != imx258_get_format_code(imx258)) + return -EINVAL; --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; + fse->min_width = supported_modesfse->index.width; +@@ -851,12 +1205,13 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd, + return 0; } - static int imx290_set_fmt(struct v4l2_subdev *sd, -@@ -613,22 +876,30 @@ static int imx290_set_fmt(struct v4l2_subdev *sd, +-static void imx258_update_pad_format(const struct imx258_mode *mode, ++static void imx258_update_pad_format(struct imx258 *imx258, ++ const struct imx258_mode *mode, + struct v4l2_subdev_format *fmt) + { fmt->format.width = mode->width; fmt->format.height = mode->height; - -- for (i = 0; i < ARRAY_SIZE(imx290_formats); i++) -- if (imx290_formatsi.code == fmt->format.code) -+ for (i = 0; i < IMX290_NUM_FORMATS; i++) -+ if (imx290->formatsi.code == fmt->format.code) - break; - -- if (i >= ARRAY_SIZE(imx290_formats)) -+ if (i >= IMX290_NUM_FORMATS) - i = 0; - -- fmt->format.code = imx290_formatsi.code; -+ fmt->format.code = imx290->formatsi.code; +- fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; ++ fmt->format.code = imx258_get_format_code(imx258); fmt->format.field = V4L2_FIELD_NONE; -+ fmt->format.colorspace = V4L2_COLORSPACE_RAW; -+ 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); + } + +@@ -869,7 +1224,7 @@ static int __imx258_get_pad_format(struct imx258 *imx258, + sd_state, + fmt->pad); + else +- imx258_update_pad_format(imx258->cur_mode, fmt); ++ imx258_update_pad_format(imx258, imx258->cur_mode, fmt); + return 0; + } +@@ -893,8 +1248,10 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_format *fmt) + { + struct imx258 *imx258 = to_imx258(sd); +- const struct imx258_mode *mode; ++ const struct imx258_link_freq_config *link_freq_cfgs; ++ const struct imx258_link_cfg *link_cfg; + struct v4l2_mbus_framefmt *framefmt; ++ const struct imx258_mode *mode; + s32 vblank_def; + s32 vblank_min; + s64 h_blank; +@@ -903,13 +1260,12 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, + + mutex_lock(&imx258->mutex); + +- /* Only one raw bayer(GBRG) order is supported */ +- fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; ++ fmt->format.code = imx258_get_format_code(imx258); + + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), width, height, + fmt->format.width, fmt->format.height); +- imx258_update_pad_format(mode, fmt); ++ imx258_update_pad_format(imx258, mode, fmt); 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_formatsi.bpp; -+ imx290->bpp = imx290->formatsi.bpp; - - if (imx290->link_freq) - __v4l2_ctrl_s_ctrl(imx290->link_freq, -@@ -636,6 +907,30 @@ static int imx290_set_fmt(struct v4l2_subdev *sd, - 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; -@@ -665,6 +960,7 @@ static int imx290_write_current_format(struct imx290 *imx290) - - 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)); -@@ -674,6 +970,7 @@ static int imx290_write_current_format(struct imx290 *imx290) - } - 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)); -@@ -690,28 +987,62 @@ static int imx290_write_current_format(struct imx290 *imx290) + framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + *framefmt = fmt->format; +@@ -917,9 +1273,14 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, + imx258->cur_mode = mode; + __v4l2_ctrl_s_ctrl(imx258->link_freq, mode->link_freq_index); + +- link_freq = link_freq_menu_itemsmode->link_freq_index; +- pixel_rate = link_freq_to_pixel_rate(link_freq); +- __v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate); ++ link_freq = imx258->link_freq_menu_itemsmode->link_freq_index; ++ link_freq_cfgs = ++ &imx258->link_freq_configsmode->link_freq_index; ++ ++ link_cfg = &link_freq_cfgs->link_cfgimx258->lane_mode_idx; ++ pixel_rate = link_freq_to_pixel_rate(link_freq, link_cfg); ++ __v4l2_ctrl_modify_range(imx258->pixel_rate, pixel_rate, ++ pixel_rate, 1, pixel_rate); + /* Update limits and set FPS to default */ + vblank_def = imx258->cur_mode->vts_def - + imx258->cur_mode->height; +@@ -927,11 +1288,12 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, + imx258->cur_mode->height; + __v4l2_ctrl_modify_range( + imx258->vblank, vblank_min, +- IMX258_VTS_MAX - imx258->cur_mode->height, 1, +- vblank_def); ++ ((1 << IMX258_LONG_EXP_SHIFT_MAX) * IMX258_VTS_MAX) - ++ imx258->cur_mode->height, ++ 1, vblank_def); + __v4l2_ctrl_s_ctrl(imx258->vblank, vblank_def); + h_blank = +- link_freq_configsmode->link_freq_index.pixels_per_line ++ imx258->link_freq_configsmode->link_freq_index.pixels_per_line + - imx258->cur_mode->width; + __v4l2_ctrl_modify_range(imx258->hblank, h_blank, + h_blank, 1, h_blank); +@@ -942,36 +1304,107 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, 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, ++__imx258_get_pad_crop(struct imx258 *imx258, ++ struct v4l2_subdev_state *sd_state, + 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); ++ return v4l2_subdev_get_try_crop(&imx258->sd, sd_state, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: -+ return &imx290->current_mode->crop; ++ return &imx258->cur_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, ++static int imx258_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: { -+ struct imx290 *imx290 = to_imx290(sd); ++ struct imx258 *imx258 = to_imx258(sd); + -+ mutex_lock(&imx290->lock); -+ sel->r = *__imx290_get_pad_crop(imx290, cfg, sel->pad, ++ mutex_lock(&imx258->mutex); ++ sel->r = *__imx258_get_pad_crop(imx258, sd_state, sel->pad, + sel->which); -+ mutex_unlock(&imx290->lock); ++ mutex_unlock(&imx258->mutex); + + 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; ++ sel->r.top = 0; ++ sel->r.width = IMX258_NATIVE_WIDTH; ++ sel->r.height = IMX258_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; ++ sel->r.left = IMX258_PIXEL_ARRAY_LEFT; ++ sel->r.top = IMX258_PIXEL_ARRAY_TOP; ++ sel->r.width = IMX258_PIXEL_ARRAY_WIDTH; ++ sel->r.height = IMX258_PIXEL_ARRAY_HEIGHT; + + return 0; - } - -- return 0; ++ } ++ + return -EINVAL; - } - ++} ++ /* Start streaming */ - static int imx290_start_streaming(struct imx290 *imx290) + static int imx258_start_streaming(struct imx258 *imx258) { -+ enum imx290_clk_index clk_idx = imx290->xclk_freq == 37125000 ? -+ CLK_37_125 : CLK_74_25; - int ret; - - /* Set init register settings */ -@@ -723,6 +1054,14 @@ static int imx290_start_streaming(struct imx290 *imx290) - return ret; - } + struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); + const struct imx258_reg_list *reg_list; ++ const struct imx258_link_freq_config *link_freq_cfg; + int ret, link_freq_index; -+ ret = imx290_set_register_array(imx290, -+ imx290->current_mode->clk_dataclk_idx, -+ imx290->current_mode->clk_size); -+ if (ret < 0) { -+ dev_err(imx290->dev, "Could not set clock registers\n"); ++ ret = imx258_write_reg(imx258, IMX258_REG_RESET, IMX258_REG_VALUE_08BIT, ++ 0x01); ++ if (ret) { ++ dev_err(&client->dev, "%s failed to reset sensor\n", __func__); + return ret; + } ++ usleep_range(10000, 15000); + - /* Apply the register values related to current frame format */ - ret = imx290_write_current_format(imx290); - if (ret < 0) { -@@ -731,15 +1070,22 @@ static int imx290_start_streaming(struct imx290 *imx290) + /* Setup PLL */ + link_freq_index = imx258->cur_mode->link_freq_index; +- reg_list = &link_freq_configslink_freq_index.reg_list; ++ link_freq_cfg = &imx258->link_freq_configslink_freq_index; ++ ++ reg_list = &link_freq_cfg->link_cfgimx258->lane_mode_idx.reg_list; + ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs); + if (ret) { + dev_err(&client->dev, "%s failed to set plls\n", __func__); + return ret; } - /* 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"); +- /* Apply default values of current mode */ +- reg_list = &imx258->cur_mode->reg_list; +- ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs); ++ ret = imx258_write_regs(imx258, imx258->variant_cfg->regs, ++ imx258->variant_cfg->num_regs); + if (ret) { +- dev_err(&client->dev, "%s failed to set mode\n", __func__); ++ dev_err(&client->dev, "%s failed to set variant config\n", ++ __func__); return ret; } -- ret = imx290_set_hmax(imx290, imx290->current_mode->hmax); -- if (ret < 0) + +- /* Set Orientation be 180 degree */ +- ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL, +- IMX258_REG_VALUE_08BIT, REG_CONFIG_MIRROR_FLIP); ++ ret = imx258_write_reg(imx258, IMX258_CLK_BLANK_STOP, ++ IMX258_REG_VALUE_08BIT, ++ imx258->csi2_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK ? ++ 1 : 0); + if (ret) { +- dev_err(&client->dev, "%s failed to set orientation\n", +- __func__); ++ dev_err(&client->dev, "%s failed to set clock lane mode\n", __func__); ++ return ret; ++ } + -+ /* 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"); ++ /* Apply default values of current mode */ ++ reg_list = &imx258->cur_mode->reg_list; ++ ret = imx258_write_regs(imx258, 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(imx290->sd.ctrl_handler); -@@ -780,6 +1126,9 @@ static int imx290_set_stream(struct v4l2_subdev *sd, int enable) - 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: +@@ -1011,9 +1444,19 @@ static int imx258_power_on(struct device *dev) + struct imx258 *imx258 = to_imx258(sd); + int ret; + ++ ret = regulator_bulk_enable(IMX258_NUM_SUPPLIES, ++ imx258->supplies); ++ if (ret) { ++ dev_err(dev, "%s: failed to enable regulators\n", ++ __func__); ++ return ret; ++ } ++ + ret = clk_prepare_enable(imx258->clk); +- if (ret) ++ if (ret) { + dev_err(dev, "failed to enable clock\n"); ++ regulator_bulk_disable(IMX258_NUM_SUPPLIES, imx258->supplies); ++ } -@@ -797,49 +1146,6 @@ static int imx290_get_regulators(struct device *dev, struct imx290 *imx290) - imx290->supplies); + return ret; } +@@ -1024,6 +1467,7 @@ static int imx258_power_off(struct device *dev) + struct imx258 *imx258 = to_imx258(sd); --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); -@@ -864,9 +1170,6 @@ static int imx290_power_on(struct device *dev) - gpiod_set_value_cansleep(imx290->rst_gpio, 0); - usleep_range(30000, 31000); + clk_disable_unprepare(imx258->clk); ++ regulator_bulk_disable(IMX258_NUM_SUPPLIES, imx258->supplies); -- /* Set data lane count */ -- imx290_set_data_lanes(imx290); -- return 0; } +@@ -1134,6 +1578,7 @@ static const struct v4l2_subdev_pad_ops imx258_pad_ops = { + .get_fmt = imx258_get_pad_format, + .set_fmt = imx258_set_pad_format, + .enum_frame_size = imx258_enum_frame_size, ++ .get_selection = imx258_get_selection, + }; + + static const struct v4l2_subdev_ops imx258_subdev_ops = { +@@ -1149,13 +1594,13 @@ static const struct v4l2_subdev_internal_ops imx258_internal_ops = { + static int imx258_init_controls(struct imx258 *imx258) + { + struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); ++ const struct imx258_link_freq_config *link_freq_cfgs; + struct v4l2_fwnode_device_properties props; + struct v4l2_ctrl_handler *ctrl_hdlr; +- struct v4l2_ctrl *vflip, *hflip; ++ const struct imx258_link_cfg *link_cfg; + s64 vblank_def; + s64 vblank_min; +- s64 pixel_rate_min; +- s64 pixel_rate_max; ++ s64 pixel_rate; + int ret; -@@ -897,6 +1200,7 @@ static const struct v4l2_subdev_pad_ops imx290_pad_ops = { - .enum_frame_size = imx290_enum_frame_size, - .get_fmt = imx290_get_fmt, - .set_fmt = imx290_set_fmt, -+ .get_selection = imx290_get_selection, - }; + ctrl_hdlr = &imx258->ctrl_handler; +@@ -1168,31 +1613,33 @@ static int imx258_init_controls(struct imx258 *imx258) + imx258->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, + &imx258_ctrl_ops, + V4L2_CID_LINK_FREQ, +- ARRAY_SIZE(link_freq_menu_items) - 1, ++ ARRAY_SIZE(link_freq_menu_items_19_2) - 1, + 0, +- link_freq_menu_items); ++ imx258->link_freq_menu_items); + + if (imx258->link_freq) + imx258->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + +- /* The driver only supports one bayer order and flips by default. */ +- hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, +- V4L2_CID_HFLIP, 1, 1, 1, 1); +- if (hflip) +- hflip->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ imx258->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 1); ++ if (imx258->hflip) ++ imx258->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ imx258->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 1); ++ if (imx258->vflip) ++ imx258->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + +- vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, +- V4L2_CID_VFLIP, 1, 1, 1, 1); +- if (vflip) +- vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ link_freq_cfgs = &imx258->link_freq_configs0; ++ link_cfg = link_freq_cfgsimx258->lane_mode_idx.link_cfg; ++ pixel_rate = link_freq_to_pixel_rate(imx258->link_freq_menu_items0, ++ link_cfg); + +- pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items0); +- pixel_rate_min = link_freq_to_pixel_rate(link_freq_menu_items1); + /* By default, PIXEL_RATE is read only */ + imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, + V4L2_CID_PIXEL_RATE, +- pixel_rate_min, pixel_rate_max, +- 1, pixel_rate_max); ++ pixel_rate, pixel_rate, ++ 1, pixel_rate); + + + vblank_def = imx258->cur_mode->vts_def - imx258->cur_mode->height; +@@ -1203,9 +1650,6 @@ static int imx258_init_controls(struct imx258 *imx258) + IMX258_VTS_MAX - imx258->cur_mode->height, 1, + vblank_def); - static const struct v4l2_subdev_ops imx290_subdev_ops = { -@@ -930,16 +1234,24 @@ static s64 imx290_check_link_freqs(const struct imx290 *imx290, - return 0; +- if (imx258->vblank) +- imx258->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; +- + imx258->hblank = v4l2_ctrl_new_std( + ctrl_hdlr, &imx258_ctrl_ops, V4L2_CID_HBLANK, + IMX258_PPL_DEFAULT - imx258->cur_mode->width, +@@ -1272,9 +1716,33 @@ static void imx258_free_controls(struct imx258 *imx258) + mutex_destroy(&imx258->mutex); } -+static const struct of_device_id imx290_of_match = { -+ { .compatible = "sony,imx290", .data = imx290_colour_formats }, -+ { .compatible = "sony,imx290-mono", .data = imx290_mono_formats }, ++static int imx258_get_regulators(struct imx258 *imx258, ++ struct i2c_client *client) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < IMX258_NUM_SUPPLIES; i++) ++ imx258->suppliesi.supply = imx258_supply_namei; ++ ++ return devm_regulator_bulk_get(&client->dev, ++ IMX258_NUM_SUPPLIES, ++ imx258->supplies); ++} ++ ++static const struct of_device_id imx258_dt_ids = { ++ { .compatible = "sony,imx258", .data = &imx258_cfg }, ++ { .compatible = "sony,imx258-pdaf", .data = &imx258_pdaf_cfg }, + { /* sentinel */ } +}; + - static int imx290_probe(struct i2c_client *client) + static int imx258_probe(struct i2c_client *client) { -+ struct v4l2_fwnode_device_properties props; - struct device *dev = &client->dev; - struct fwnode_handle *endpoint; - /* Only CSI2 is supported for now: */ - struct v4l2_fwnode_endpoint ep = { - .bus_type = V4L2_MBUS_CSI2_DPHY - }; + struct imx258 *imx258; ++ struct fwnode_handle *endpoint; ++ 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; + u32 val = 0; -@@ -954,6 +1266,11 @@ static int imx290_probe(struct i2c_client *client) - return -ENODEV; - } +@@ -1282,6 +1750,10 @@ static int imx258_probe(struct i2c_client *client) + if (!imx258) + return -ENOMEM; -+ match = of_match_device(imx290_of_match, dev); -+ if (!match) -+ return -ENODEV; -+ imx290->formats = (const struct imx290_pixfmt *)match->data; ++ ret = imx258_get_regulators(imx258, client); ++ if (ret) ++ return ret; + - endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); - if (!endpoint) { - dev_err(dev, "Endpoint node not found\n"); -@@ -977,6 +1294,7 @@ static int imx290_probe(struct i2c_client *client) - ret = -EINVAL; - goto free_err; + imx258->clk = devm_clk_get_optional(&client->dev, NULL); + if (IS_ERR(imx258->clk)) + return dev_err_probe(&client->dev, PTR_ERR(imx258->clk), +@@ -1291,21 +1763,75 @@ static int imx258_probe(struct i2c_client *client) + "no clock provided, using clock-frequency property\n"); + + device_property_read_u32(&client->dev, "clock-frequency", &val); ++ } else if (IS_ERR(imx258->clk)) { ++ return dev_err_probe(&client->dev, PTR_ERR(imx258->clk), ++ "error getting clock\n"); + } else { + val = clk_get_rate(imx258->clk); } -+ imx290->hmax_min = IMX290_HMAX_MIN; +- if (val != IMX258_INPUT_CLOCK_FREQ) { +- dev_err(&client->dev, "input clock frequency not supported\n"); ++ ++ switch (val) { ++ case 19200000: ++ imx258->link_freq_configs = link_freq_configs_19_2; ++ imx258->link_freq_menu_items = link_freq_menu_items_19_2; ++ break; ++ case 24000000: ++ imx258->link_freq_configs = link_freq_configs_24; ++ imx258->link_freq_menu_items = link_freq_menu_items_24; ++ break; ++ default: ++ dev_err(&client->dev, "input clock frequency of %u not supported\n", ++ val); + return -EINVAL; + } + ++ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); ++ if (!endpoint) { ++ dev_err(&client->dev, "Endpoint node not found\n"); ++ return -EINVAL; ++ } ++ ++ ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep); ++ fwnode_handle_put(endpoint); ++ if (ret == -ENXIO) { ++ dev_err(&client->dev, "Unsupported bus type, should be CSI2\n"); ++ goto error_endpoint_poweron; ++ } else if (ret) { ++ dev_err(&client->dev, "Parsing endpoint node failed\n"); ++ goto error_endpoint_poweron; ++ } ++ ++ /* Get number of data lanes */ ++ switch (ep.bus.mipi_csi2.num_data_lanes) { ++ case 2: ++ imx258->lane_mode_idx = IMX258_2_LANE_MODE; ++ break; ++ case 4: ++ imx258->lane_mode_idx = IMX258_4_LANE_MODE; ++ break; ++ default: ++ dev_err(&client->dev, "Invalid data lanes: %u\n", ++ ep.bus.mipi_csi2.num_data_lanes); ++ ret = -EINVAL; ++ goto error_endpoint_poweron; ++ } ++ ++ imx258->csi2_flags = ep.bus.mipi_csi2.flags; ++ ++ match = i2c_of_match_device(imx258_dt_ids, client); ++ if (!match || !match->data) ++ imx258->variant_cfg = &imx258_cfg; ++ else ++ imx258->variant_cfg = ++ (const struct imx258_variant_cfg *)match->data; ++ + /* Initialize subdev */ + v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops); - dev_dbg(dev, "Using %u data lanes\n", imx290->nlanes); + /* Will be powered off via pm_runtime_idle */ + ret = imx258_power_on(&client->dev); + if (ret) +- return ret; ++ goto error_endpoint_poweron; -@@ -1003,21 +1321,21 @@ static int imx290_probe(struct i2c_client *client) - } + /* Check module identity */ + ret = imx258_identify_module(imx258); +@@ -1350,6 +1876,9 @@ static int imx258_probe(struct i2c_client *client) + error_identify: + imx258_power_off(&client->dev); - 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; - } ++error_endpoint_poweron: ++ v4l2_fwnode_endpoint_free(&ep); ++ + return ret; + } - /* 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; - } +@@ -1382,10 +1911,6 @@ static const struct acpi_device_id imx258_acpi_ids = { + MODULE_DEVICE_TABLE(acpi, imx258_acpi_ids); + #endif -- 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; -@@ -1046,10 +1364,35 @@ static int imx290_probe(struct i2c_client *client) - */ - imx290_entity_init_cfg(&imx290->sd, NULL); +-static const struct of_device_id imx258_dt_ids = { +- { .compatible = "sony,imx258" }, +- { /* sentinel */ } +-}; + MODULE_DEVICE_TABLE(of, imx258_dt_ids); -- v4l2_ctrl_handler_init(&imx290->ctrls, 4); -+ v4l2_ctrl_handler_init(&imx290->ctrls, 11); + static struct i2c_driver imx258_i2c_driver = { +diff --git a/drivers/media/i2c/imx296.c b/drivers/media/i2c/imx296.c +index 3b4539b622b4..e87cc1dc038e 100644 +--- a/drivers/media/i2c/imx296.c ++++ b/drivers/media/i2c/imx296.c +@@ -20,6 +20,10 @@ + #include <media/v4l2-fwnode.h> + #include <media/v4l2-subdev.h> - 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); ++static int trigger_mode; ++module_param(trigger_mode, int, 0644); ++MODULE_PARM_DESC(trigger_mode, "Set trigger mode: 0=default, 1=XTRIG"); + -+ 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); + #define IMX296_PIXEL_ARRAY_WIDTH 1456 + #define IMX296_PIXEL_ARRAY_HEIGHT 1088 + +@@ -150,9 +154,9 @@ + #define IMX296_FID0_ROIPH1 IMX296_REG_16BIT(0x3310) + #define IMX296_FID0_ROIPV1 IMX296_REG_16BIT(0x3312) + #define IMX296_FID0_ROIWH1 IMX296_REG_16BIT(0x3314) +-#define IMX296_FID0_ROIWH1_MIN 80 ++#define IMX296_FID0_ROIWH1_MIN 96 + #define IMX296_FID0_ROIWV1 IMX296_REG_16BIT(0x3316) +-#define IMX296_FID0_ROIWV1_MIN 4 ++#define IMX296_FID0_ROIWV1_MIN 88 + + #define IMX296_CM_HSST_STARTTMG IMX296_REG_16BIT(0x4018) + #define IMX296_CM_HSST_ENDTMG IMX296_REG_16BIT(0x401a) +@@ -171,6 +175,7 @@ + #define IMX296_CKREQSEL IMX296_REG_8BIT(0x4101) + #define IMX296_CKREQSEL_HS BIT(2) + #define IMX296_GTTABLENUM IMX296_REG_8BIT(0x4114) ++#define IMX296_MIPIC_AREA3W IMX296_REG_16BIT(0x4182) + #define IMX296_CTRL418C IMX296_REG_8BIT(0x418c) + + struct imx296_clk_params { +@@ -209,6 +214,8 @@ struct imx296 { + struct v4l2_ctrl_handler ctrls; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; ++ struct v4l2_ctrl *vflip; ++ struct v4l2_ctrl *hflip; + }; + + static inline struct imx296 *to_imx296(struct v4l2_subdev *sd) +@@ -250,6 +257,36 @@ static int imx296_write(struct imx296 *sensor, u32 addr, u32 value, int *err) + return ret; + } + ++/* ++ * 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 mbus_codes = { ++ /* 10-bit modes. */ ++ MEDIA_BUS_FMT_SRGGB10_1X10, ++ MEDIA_BUS_FMT_SGRBG10_1X10, ++ MEDIA_BUS_FMT_SGBRG10_1X10, ++ MEDIA_BUS_FMT_SBGGR10_1X10, ++}; ++ ++static u32 imx296_mbus_code(const struct imx296 *sensor) ++{ ++ unsigned int i = 0; ++ ++ if (sensor->mono) ++ return MEDIA_BUS_FMT_Y10_1X10; ++ ++ if (sensor->vflip && sensor->hflip) ++ i = (sensor->vflip->val ? 2 : 0) | (sensor->hflip->val ? 1 : 0); ++ ++ return mbus_codesi; ++} ++ + static int imx296_power_on(struct imx296 *sensor) + { + int ret; +@@ -344,6 +381,13 @@ static int imx296_s_ctrl(struct v4l2_ctrl *ctrl) + &ret); + break; + ++ case V4L2_CID_HFLIP: ++ case V4L2_CID_VFLIP: ++ imx296_write(sensor, IMX296_CTRL0E, ++ sensor->vflip->val | (sensor->hflip->val << 1), ++ &ret); ++ break; ++ + case V4L2_CID_TEST_PATTERN: + if (ctrl->val) { + imx296_write(sensor, IMX296_PGHPOS, 8, &ret); +@@ -383,10 +427,36 @@ static const struct v4l2_ctrl_ops imx296_ctrl_ops = { + .s_ctrl = imx296_s_ctrl, + }; + ++static void imx296_setup_hblank(struct imx296 *sensor, unsigned int width) ++{ ++ /* ++ * Horizontal blanking is controlled through the HMAX register, which ++ * contains a line length in contains a line length in units of an ++ * internal 74.25 MHz clock derived from the INCLK. The HMAX value is ++ * currently fixed to 1100, convert it to a number of pixels based on ++ * the nominal pixel rate. ++ * ++ * Horizontal blanking is fixed, regardless of the crop width, so ++ * ensure the hblank limits are adjusted to account for this. ++ */ ++ unsigned int hblank = 1100 * 1188000000ULL / 10 / 74250000 - width; ++ ++ if (!sensor->hblank) { ++ sensor->hblank = v4l2_ctrl_new_std(&sensor->ctrls, ++ &imx296_ctrl_ops, ++ V4L2_CID_HBLANK, hblank, ++ hblank, 1, hblank); ++ if (sensor->hblank) ++ sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ } else { ++ __v4l2_ctrl_modify_range(sensor->hblank, hblank, hblank, 1, ++ hblank); ++ } ++} + -+ imx290->hflip = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, + static int imx296_ctrls_init(struct imx296 *sensor) + { + struct v4l2_fwnode_device_properties props; +- unsigned int hblank; + int ret; + + ret = v4l2_fwnode_device_parse(sensor->dev, &props); +@@ -401,19 +471,17 @@ static int imx296_ctrls_init(struct imx296 *sensor) + V4L2_CID_ANALOGUE_GAIN, IMX296_GAIN_MIN, + IMX296_GAIN_MAX, 1, IMX296_GAIN_MIN); + +- /* +- * Horizontal blanking is controlled through the HMAX register, which +- * contains a line length in INCK clock units. The INCK frequency is +- * fixed to 74.25 MHz. The HMAX value is currently fixed to 1100, +- * convert it to a number of pixels based on the nominal pixel rate. +- */ +- hblank = 1100 * 1188000000ULL / 10 / 74250000 +- - IMX296_PIXEL_ARRAY_WIDTH; +- sensor->hblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops, +- V4L2_CID_HBLANK, hblank, hblank, 1, +- hblank); +- if (sensor->hblank) +- sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); -+ imx290->vflip = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, ++ if (sensor->hflip && !sensor->mono) ++ sensor->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); ++ if (sensor->vflip && !sensor->mono) ++ sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ imx296_setup_hblank(sensor, IMX296_PIXEL_ARRAY_WIDTH); + + sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops, + V4L2_CID_VBLANK, 30, +@@ -468,7 +536,7 @@ static const struct { + { IMX296_REG_8BIT(0x30a4), 0x5f }, + { IMX296_REG_8BIT(0x30a8), 0x91 }, + { IMX296_REG_8BIT(0x30ac), 0x28 }, +- { IMX296_REG_8BIT(0x30af), 0x09 }, ++ { IMX296_REG_8BIT(0x30af), 0x0b }, + { IMX296_REG_8BIT(0x30df), 0x00 }, + { IMX296_REG_8BIT(0x3165), 0x00 }, + { IMX296_REG_8BIT(0x3169), 0x10 }, +@@ -526,8 +594,11 @@ static int imx296_setup(struct imx296 *sensor, struct v4l2_subdev_state *state) + imx296_write(sensor, IMX296_FID0_ROIPV1, crop->top, &ret); + imx296_write(sensor, IMX296_FID0_ROIWH1, crop->width, &ret); + imx296_write(sensor, IMX296_FID0_ROIWV1, crop->height, &ret); ++ imx296_write(sensor, IMX296_MIPIC_AREA3W, crop->height, &ret); + } else { + imx296_write(sensor, IMX296_FID0_ROI, 0, &ret); ++ imx296_write(sensor, IMX296_MIPIC_AREA3W, ++ IMX296_PIXEL_ARRAY_HEIGHT, &ret); + } - imx290->link_freq = - v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops, -@@ -1069,6 +1412,15 @@ static int imx290_probe(struct i2c_client *client) - ARRAY_SIZE(imx290_test_pattern_menu) - 1, - 0, 0, imx290_test_pattern_menu); + imx296_write(sensor, IMX296_CTRL0D, +@@ -566,7 +637,7 @@ static int imx296_setup(struct imx296 *sensor, struct v4l2_subdev_state *state) + imx296_write(sensor, IMX296_CTRL418C, sensor->clk_params->ctrl418c, + &ret); + +- imx296_write(sensor, IMX296_GAINDLY, IMX296_GAINDLY_NONE, &ret); ++ imx296_write(sensor, IMX296_GAINDLY, IMX296_GAINDLY_1FRAME, &ret); + imx296_write(sensor, IMX296_BLKLEVEL, 0x03c, &ret); -+ ret = v4l2_fwnode_device_parse(&client->dev, &props); -+ if (ret) -+ goto free_ctrl; + return ret; +@@ -578,8 +649,19 @@ static int imx296_stream_on(struct imx296 *sensor) + + imx296_write(sensor, IMX296_CTRL00, 0, &ret); + usleep_range(2000, 5000); + -+ ret = v4l2_ctrl_new_fwnode_properties(&imx290->ctrls, &imx290_ctrl_ops, -+ &props); -+ if (ret) -+ goto free_ctrl; ++ /* external trigger mode: 0=normal, 1=triggered */ ++ imx296_write(sensor, IMX296_CTRL0B, ++ (trigger_mode == 1) ? IMX296_CTRL0B_TRIGEN : 0, &ret); ++ imx296_write(sensor, IMX296_LOWLAGTRG, ++ (trigger_mode == 1) ? IMX296_LOWLAGTRG_FAST : 0, &ret); + - imx290->sd.ctrl_handler = &imx290->ctrls; + imx296_write(sensor, IMX296_CTRL0A, 0, &ret); - if (imx290->ctrls.error) { -@@ -1091,6 +1443,9 @@ static int imx290_probe(struct i2c_client *client) - goto free_ctrl; - } ++ /* vflip and hflip cannot change during streaming */ ++ __v4l2_ctrl_grab(sensor->vflip, 1); ++ __v4l2_ctrl_grab(sensor->hflip, 1); ++ + return ret; + } -+ /* Initialize the frame format (this also sets imx290->current_mode) */ -+ imx290_entity_init_cfg(&imx290->sd, NULL); +@@ -590,6 +672,9 @@ static int imx296_stream_off(struct imx296 *sensor) + imx296_write(sensor, IMX296_CTRL0A, IMX296_CTRL0A_XMSTA, &ret); + imx296_write(sensor, IMX296_CTRL00, IMX296_CTRL00_STANDBY, &ret); + ++ __v4l2_ctrl_grab(sensor->vflip, 0); ++ __v4l2_ctrl_grab(sensor->hflip, 0); + - ret = v4l2_async_register_subdev(&imx290->sd); - if (ret < 0) { - dev_err(dev, "Could not register v4l2 device\n"); -@@ -1142,10 +1497,6 @@ static int imx290_remove(struct i2c_client *client) + return ret; + } + +@@ -660,8 +745,7 @@ static int imx296_enum_mbus_code(struct v4l2_subdev *sd, + if (code->index != 0) + return -EINVAL; + +- code->code = sensor->mono ? MEDIA_BUS_FMT_Y10_1X10 +- : MEDIA_BUS_FMT_SBGGR10_1X10; ++ code->code = imx296_mbus_code(sensor); + return 0; } +@@ -671,10 +755,15 @@ static int imx296_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_size_enum *fse) + { + const struct v4l2_mbus_framefmt *format; ++ struct imx296 *sensor = to_imx296(sd); --static const struct of_device_id imx290_of_match = { -- { .compatible = "sony,imx290" }, -- { /* sentinel */ } --}; - MODULE_DEVICE_TABLE(of, imx290_of_match); + format = v4l2_subdev_get_pad_format(sd, state, fse->pad); + +- if (fse->index >= 2 || fse->code != format->code) ++ /* ++ * Binning does not seem to work on either mono or colour sensor ++ * variants. Disable enumerating the binned frame size for now. ++ */ ++ if (fse->index >= 1 || fse->code != imx296_mbus_code(sensor)) + return -EINVAL; + + fse->min_width = IMX296_PIXEL_ARRAY_WIDTH / (fse->index + 1); +@@ -696,35 +785,12 @@ static int imx296_set_format(struct v4l2_subdev *sd, + crop = v4l2_subdev_get_pad_crop(sd, state, fmt->pad); + format = v4l2_subdev_get_pad_format(sd, state, fmt->pad); + +- /* +- * Binning is only allowed when cropping is disabled according to the +- * documentation. This should be double-checked. +- */ +- if (crop->width == IMX296_PIXEL_ARRAY_WIDTH && +- crop->height == IMX296_PIXEL_ARRAY_HEIGHT) { +- unsigned int width; +- unsigned int height; +- unsigned int hratio; +- unsigned int vratio; +- +- /* Clamp the width and height to avoid dividing by zero. */ +- width = clamp_t(unsigned int, fmt->format.width, +- crop->width / 2, crop->width); +- height = clamp_t(unsigned int, fmt->format.height, +- crop->height / 2, crop->height); +- +- hratio = DIV_ROUND_CLOSEST(crop->width, width); +- vratio = DIV_ROUND_CLOSEST(crop->height, height); +- +- format->width = crop->width / hratio; +- format->height = crop->height / vratio; +- } else { +- format->width = crop->width; +- format->height = crop->height; +- } ++ format->width = crop->width; ++ format->height = crop->height; ++ ++ imx296_setup_hblank(sensor, format->width); + +- format->code = sensor->mono ? MEDIA_BUS_FMT_Y10_1X10 +- : MEDIA_BUS_FMT_SBGGR10_1X10; ++ format->code = imx296_mbus_code(sensor); + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_RAW; + format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; +@@ -960,6 +1026,8 @@ static int imx296_identify_model(struct imx296 *sensor) + return ret; + } - static struct i2c_driver imx290_i2c_driver = { ++ usleep_range(2000, 5000); ++ + ret = imx296_read(sensor, IMX296_SENSOR_INFO); + if (ret < 0) { + dev_err(sensor->dev, "failed to read sensor information (%d)\n", diff --git a/drivers/media/i2c/imx477.c b/drivers/media/i2c/imx477.c new file mode 100644 -index 000000000000..b2d4fb54cb1e +index 000000000000..dce7f2b4fa57 --- /dev/null +++ b/drivers/media/i2c/imx477.c -@@ -0,0 +1,2309 @@ +@@ -0,0 +1,2339 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * A V4L2 driver for Sony IMX477 cameras. @@ -72446,6 +109966,10 @@ +#define IMX477_REG_FRAME_LENGTH 0x0340 +#define IMX477_FRAME_LENGTH_MAX 0xffdc + ++/* H_TIMING internal */ ++#define IMX477_REG_LINE_LENGTH 0x0342 ++#define IMX477_LINE_LENGTH_MAX 0xfff0 ++ +/* Long exposure multiplier */ +#define IMX477_LONG_EXP_SHIFT_MAX 7 +#define IMX477_LONG_EXP_SHIFT_REG 0x3100 @@ -72453,7 +109977,7 @@ +/* Exposure control */ +#define IMX477_REG_EXPOSURE 0x0202 +#define IMX477_EXPOSURE_OFFSET 22 -+#define IMX477_EXPOSURE_MIN 20 ++#define IMX477_EXPOSURE_MIN 4 +#define IMX477_EXPOSURE_STEP 1 +#define IMX477_EXPOSURE_DEFAULT 0x640 +#define IMX477_EXPOSURE_MAX (IMX477_FRAME_LENGTH_MAX - \ @@ -72552,9 +110076,14 @@ + struct imx477_reg_list reg_list; +}; + ++static const s64 imx477_link_freq_menu = { ++ IMX477_DEFAULT_LINK_FREQ, ++}; ++ +static const struct imx477_reg mode_common_regs = { + {0x0136, 0x18}, + {0x0137, 0x00}, ++ {0x0138, 0x01}, + {0xe000, 0x00}, + {0xe07a, 0x01}, + {0x0808, 0x02}, @@ -72994,7 +110523,7 @@ + {0x0385, 0x01}, + {0x0387, 0x01}, + {0x0900, 0x01}, -+ {0x0901, 0x12}, ++ {0x0901, 0x22}, + {0x0902, 0x02}, + {0x3140, 0x02}, + {0x3c00, 0x00}, @@ -73019,7 +110548,7 @@ + {0x9e9f, 0x00}, + {0xa2a9, 0x60}, + {0xa2b7, 0x00}, -+ {0x0401, 0x01}, ++ {0x0401, 0x00}, + {0x0404, 0x00}, + {0x0405, 0x20}, + {0x0408, 0x00}, @@ -73095,7 +110624,7 @@ + {0x0385, 0x01}, + {0x0387, 0x01}, + {0x0900, 0x01}, -+ {0x0901, 0x12}, ++ {0x0901, 0x22}, + {0x0902, 0x02}, + {0x3140, 0x02}, + {0x3c00, 0x00}, @@ -73120,7 +110649,7 @@ + {0x9e9f, 0x00}, + {0xa2a9, 0x60}, + {0xa2b7, 0x00}, -+ {0x0401, 0x01}, ++ {0x0401, 0x00}, + {0x0404, 0x00}, + {0x0405, 0x20}, + {0x0408, 0x00}, @@ -73497,6 +111026,7 @@ + struct v4l2_ctrl_handler ctrl_handler; + /* V4L2 Controls */ + struct v4l2_ctrl *pixel_rate; ++ struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *hflip; @@ -73506,6 +111036,9 @@ + /* Current mode */ + const struct imx477_mode *mode; + ++ /* Trigger mode */ ++ int trigger_mode_of; ++ + /* + * Mutex for serialized access: + * Protect sensor module set pad format and start/stop streaming safely. @@ -73660,9 +111193,9 @@ +{ + struct imx477 *imx477 = to_imx477(sd); + struct v4l2_mbus_framefmt *try_fmt_img = -+ v4l2_subdev_get_try_format(sd, fh->pad, IMAGE_PAD); ++ v4l2_subdev_get_try_format(sd, fh->state, IMAGE_PAD); + struct v4l2_mbus_framefmt *try_fmt_meta = -+ v4l2_subdev_get_try_format(sd, fh->pad, METADATA_PAD); ++ v4l2_subdev_get_try_format(sd, fh->state, METADATA_PAD); + struct v4l2_rect *try_crop; + + mutex_lock(&imx477->mutex); @@ -73681,7 +111214,7 @@ + try_fmt_meta->field = V4L2_FIELD_NONE; + + /* Initialize try_crop */ -+ try_crop = v4l2_subdev_get_try_crop(sd, fh->pad, IMAGE_PAD); ++ try_crop = v4l2_subdev_get_try_crop(sd, fh->state, IMAGE_PAD); + try_crop->left = IMX477_PIXEL_ARRAY_LEFT; + try_crop->top = IMX477_PIXEL_ARRAY_TOP; + try_crop->width = IMX477_PIXEL_ARRAY_WIDTH; @@ -73791,6 +111324,10 @@ + ret = imx477_set_frame_length(imx477, + imx477->mode->height + ctrl->val); + break; ++ case V4L2_CID_HBLANK: ++ ret = imx477_write_reg(imx477, IMX477_REG_LINE_LENGTH, 2, ++ imx477->mode->width + ctrl->val); ++ break; + default: + dev_info(&client->dev, + "ctrl(id:0x%x,val:0x%x) is not handled\n", @@ -73809,7 +111346,7 @@ +}; + +static int imx477_enum_mbus_code(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct imx477 *imx477 = to_imx477(sd); @@ -73834,7 +111371,7 @@ +} + +static int imx477_enum_frame_size(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct imx477 *imx477 = to_imx477(sd); @@ -73900,7 +111437,7 @@ +} + +static int imx477_get_pad_format(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct imx477 *imx477 = to_imx477(sd); @@ -73912,7 +111449,8 @@ + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *try_fmt = -+ v4l2_subdev_get_try_format(&imx477->sd, cfg, fmt->pad); ++ v4l2_subdev_get_try_format(&imx477->sd, sd_state, ++ 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) : @@ -73951,7 +111489,7 @@ + +static void imx477_set_framing_limits(struct imx477 *imx477) +{ -+ unsigned int frm_length_min, frm_length_default, hblank; ++ unsigned int frm_length_min, frm_length_default, hblank_min; + const struct imx477_mode *mode = imx477->mode; + + frm_length_min = imx477_get_frame_length(mode, &mode->timeperframe_min); @@ -73970,17 +111508,14 @@ + /* 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); ++ hblank_min = mode->line_length_pix - mode->width; ++ __v4l2_ctrl_modify_range(imx477->hblank, hblank_min, ++ IMX477_LINE_LENGTH_MAX, 1, hblank_min); ++ __v4l2_ctrl_s_ctrl(imx477->hblank, hblank_min); +} + +static int imx477_set_pad_format(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *framefmt; @@ -74009,17 +111544,17 @@ + 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, ++ framefmt = v4l2_subdev_get_try_format(sd, sd_state, + fmt->pad); + *framefmt = fmt->format; -+ } else { ++ } else if (imx477->mode != mode) { + 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, ++ framefmt = v4l2_subdev_get_try_format(sd, sd_state, + fmt->pad); + *framefmt = fmt->format; + } else { @@ -74034,12 +111569,13 @@ +} + +static const struct v4l2_rect * -+__imx477_get_pad_crop(struct imx477 *imx477, struct v4l2_subdev_pad_config *cfg, ++__imx477_get_pad_crop(struct imx477 *imx477, ++ struct v4l2_subdev_state *sd_state, + 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); ++ return v4l2_subdev_get_try_crop(&imx477->sd, sd_state, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return &imx477->mode->crop; + } @@ -74048,7 +111584,7 @@ +} + +static int imx477_get_selection(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { @@ -74056,7 +111592,7 @@ + struct imx477 *imx477 = to_imx477(sd); + + mutex_lock(&imx477->mutex); -+ sel->r = *__imx477_get_pad_crop(imx477, cfg, sel->pad, ++ sel->r = *__imx477_get_pad_crop(imx477, sd_state, sel->pad, + sel->which); + mutex_unlock(&imx477->mutex); + @@ -74090,7 +111626,7 @@ + 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; ++ int ret, tm; + + if (!imx477->common_regs_written) { + ret = imx477_write_regs(imx477, mode_common_regs, @@ -74121,26 +111657,22 @@ + imx477_write_reg(imx477, 0x0b05, IMX477_REG_VALUE_08BIT, !!dpc_enable); + imx477_write_reg(imx477, 0x0b06, IMX477_REG_VALUE_08BIT, !!dpc_enable); + -+ /* Set vsync trigger mode */ -+ if (trigger_mode != 0) { -+ /* trigger_mode == 1 for source, 2 for sink */ -+ const u32 val = (trigger_mode == 1) ? 1 : 0; -+ -+ imx477_write_reg(imx477, IMX477_REG_MC_MODE, -+ IMX477_REG_VALUE_08BIT, 1); -+ imx477_write_reg(imx477, IMX477_REG_MS_SEL, -+ IMX477_REG_VALUE_08BIT, val); -+ imx477_write_reg(imx477, IMX477_REG_XVS_IO_CTRL, -+ IMX477_REG_VALUE_08BIT, val); -+ imx477_write_reg(imx477, IMX477_REG_EXTOUT_EN, -+ IMX477_REG_VALUE_08BIT, val); -+ } -+ + /* Apply customized values from user */ + ret = __v4l2_ctrl_handler_setup(imx477->sd.ctrl_handler); + if (ret) + return ret; + ++ /* Set vsync trigger mode: 0=standalone, 1=source, 2=sink */ ++ tm = (imx477->trigger_mode_of >= 0) ? imx477->trigger_mode_of : trigger_mode; ++ imx477_write_reg(imx477, IMX477_REG_MC_MODE, ++ IMX477_REG_VALUE_08BIT, (tm > 0) ? 1 : 0); ++ imx477_write_reg(imx477, IMX477_REG_MS_SEL, ++ IMX477_REG_VALUE_08BIT, (tm <= 1) ? 1 : 0); ++ imx477_write_reg(imx477, IMX477_REG_XVS_IO_CTRL, ++ IMX477_REG_VALUE_08BIT, (tm == 1) ? 1 : 0); ++ imx477_write_reg(imx477, IMX477_REG_EXTOUT_EN, ++ IMX477_REG_VALUE_08BIT, (tm == 1) ? 1 : 0); ++ + /* set stream on register */ + return imx477_write_reg(imx477, IMX477_REG_MODE_SELECT, + IMX477_REG_VALUE_08BIT, IMX477_MODE_STREAMING); @@ -74157,6 +111689,10 @@ + IMX477_REG_VALUE_08BIT, IMX477_MODE_STANDBY); + if (ret) + dev_err(&client->dev, "%s failed to set stream\n", __func__); ++ ++ /* Stop driving XVS out (there is still a weak pull-up) */ ++ imx477_write_reg(imx477, IMX477_REG_EXTOUT_EN, ++ IMX477_REG_VALUE_08BIT, 0); +} + +static int imx477_set_stream(struct v4l2_subdev *sd, int enable) @@ -74380,6 +111916,17 @@ + IMX477_PIXEL_RATE, + IMX477_PIXEL_RATE, 1, + IMX477_PIXEL_RATE); ++ if (imx477->pixel_rate) ++ imx477->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ ++ /* LINK_FREQ is also read only */ ++ imx477->link_freq = ++ v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx477_ctrl_ops, ++ V4L2_CID_LINK_FREQ, ++ ARRAY_SIZE(imx477_link_freq_menu) - 1, 0, ++ imx477_link_freq_menu); ++ if (imx477->link_freq) ++ imx477->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + /* + * Create the controls here, but mode specific limits are setup @@ -74390,10 +111937,6 @@ + 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, @@ -74457,9 +112000,13 @@ + + imx477->sd.ctrl_handler = ctrl_hdlr; + ++ mutex_lock(&imx477->mutex); ++ + /* Setup exposure and frame/line length limits. */ + imx477_set_framing_limits(imx477); + ++ mutex_unlock(&imx477->mutex); ++ + return 0; + +error: @@ -74556,6 +112103,7 @@ + struct imx477 *imx477; + const struct of_device_id *match; + int ret; ++ u32 tm_of; + + imx477 = devm_kzalloc(&client->dev, sizeof(*imx477), GFP_KERNEL); + if (!imx477) @@ -74573,6 +112121,10 @@ + if (imx477_check_hwcfg(dev)) + return -EINVAL; + ++ /* Default the trigger mode from OF to -1, which means invalid */ ++ ret = of_property_read_u32(dev->of_node, "trigger-mode", &tm_of); ++ imx477->trigger_mode_of = (ret == 0) ? tm_of : -1; ++ + /* Get system clock (xclk) */ + imx477->xclk = devm_clk_get(dev, NULL); + if (IS_ERR(imx477->xclk)) { @@ -74638,7 +112190,7 @@ + goto error_handler_free; + } + -+ ret = v4l2_async_register_subdev_sensor_common(&imx477->sd); ++ ret = v4l2_async_register_subdev_sensor(&imx477->sd); + if (ret < 0) { + dev_err(dev, "failed to register sensor sub-device: %d\n", ret); + goto error_media_entity; @@ -74660,7 +112212,7 @@ + return ret; +} + -+static int imx477_remove(struct i2c_client *client) ++static void imx477_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx477 *imx477 = to_imx477(sd); @@ -74673,8 +112225,6 @@ + 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); @@ -74690,7 +112240,7 @@ + .of_match_table = imx477_dt_ids, + .pm = &imx477_pm_ops, + }, -+ .probe_new = imx477_probe, ++ .probe = imx477_probe, + .remove = imx477_remove, +}; + @@ -74701,10 +112251,10 @@ +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/imx519.c b/drivers/media/i2c/imx519.c new file mode 100644 -index 000000000000..675b4a94e065 +index 000000000000..7cb63e018764 --- /dev/null +++ b/drivers/media/i2c/imx519.c -@@ -0,0 +1,2091 @@ +@@ -0,0 +1,2146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * A V4L2 driver for Sony IMX519 cameras. @@ -74743,10 +112293,10 @@ + +#define IMX519_XCLK_FREQ 24000000 + -+#define IMX519_DEFAULT_LINK_FREQ 493500000 ++#define IMX519_DEFAULT_LINK_FREQ 408000000 + -+/* Pixel rate is fixed at 686MHz for all the modes */ -+#define IMX519_PIXEL_RATE 686000000 ++/* Pixel rate is fixed at 426MHz for all the modes */ ++#define IMX519_PIXEL_RATE 426666667 + +/* V_TIMING internal */ +#define IMX519_REG_FRAME_LENGTH 0x0340 @@ -74759,7 +112309,7 @@ +/* Exposure control */ +#define IMX519_REG_EXPOSURE 0x0202 +#define IMX519_EXPOSURE_OFFSET 32 -+#define IMX519_EXPOSURE_MIN 1 ++#define IMX519_EXPOSURE_MIN 20 +#define IMX519_EXPOSURE_STEP 1 +#define IMX519_EXPOSURE_DEFAULT 0x3e8 +#define IMX519_EXPOSURE_MAX (IMX519_FRAME_LENGTH_MAX - \ @@ -74801,7 +112351,7 @@ +#define IMX519_TEST_PATTERN_GB_DEFAULT 0 + +/* Embedded metadata stream structure */ -+#define IMX519_EMBEDDED_LINE_WIDTH 16384 ++#define IMX519_EMBEDDED_LINE_WIDTH (5820 * 3) +#define IMX519_NUM_EMBEDDED_LINES 1 + +enum pad_types { @@ -74852,7 +112402,12 @@ + struct imx519_reg_list reg_list; +}; + ++static const s64 imx519_link_freq_menu = { ++ IMX519_DEFAULT_LINK_FREQ, ++}; ++ +static const struct imx519_reg mode_common_regs = { ++ {0x0100, 0x00}, + {0x0136, 0x18}, + {0x0137, 0x00}, + {0x3c7e, 0x01}, @@ -75125,6 +112680,7 @@ + {0xae05, 0x03}, + {0xbc1c, 0x08}, + {0xbcf1, 0x02}, ++ {0x38a3, 0x00}, +}; + +/* 16 mpix 10fps */ @@ -75133,8 +112689,8 @@ + {0x0112, 0x0a}, + {0x0113, 0x0a}, + {0x0114, 0x01}, -+ {0x0342, 0x42}, -+ {0x0343, 0x00}, ++ {0x0342, 0x31}, ++ {0x0343, 0x6a}, + {0x0340, 0x0d}, + {0x0341, 0xf4}, + {0x0344, 0x00}, @@ -75171,22 +112727,30 @@ + {0x034f, 0xa8}, + {0x0301, 0x06}, + {0x0303, 0x04}, -+ {0x0305, 0x04}, ++ {0x0305, 0x06}, + {0x0306, 0x01}, -+ {0x0307, 0x57}, ++ {0x0307, 0x40}, + {0x0309, 0x0a}, + {0x030b, 0x02}, + {0x030d, 0x04}, + {0x030e, 0x01}, -+ {0x030f, 0x49}, ++ {0x030f, 0x10}, + {0x0310, 0x01}, -+ {0x0820, 0x07}, -+ {0x0821, 0xb6}, ++ {0x0820, 0x0a}, ++ {0x0821, 0x20}, + {0x0822, 0x00}, + {0x0823, 0x00}, + {0x3e20, 0x01}, -+ {0x3e37, 0x00}, ++ {0x3e37, 0x01}, + {0x3e3b, 0x00}, ++ {0x38a4, 0x00}, ++ {0x38a5, 0x00}, ++ {0x38a6, 0x00}, ++ {0x38a7, 0x00}, ++ {0x38a8, 0x01}, ++ {0x38a9, 0x23}, ++ {0x38aa, 0x01}, ++ {0x38ab, 0x23}, + {0x0106, 0x00}, + {0x0b00, 0x00}, + {0x3230, 0x00}, @@ -75210,8 +112774,8 @@ + {0x0112, 0x0a}, + {0x0113, 0x0a}, + {0x0114, 0x01}, -+ {0x0342, 0x38}, -+ {0x0343, 0x70}, ++ {0x0342, 0x28}, ++ {0x0343, 0xf6}, + {0x0340, 0x08}, + {0x0341, 0xd4}, + {0x0344, 0x01}, @@ -75248,22 +112812,30 @@ + {0x034f, 0x70}, + {0x0301, 0x06}, + {0x0303, 0x04}, -+ {0x0305, 0x04}, ++ {0x0305, 0x06}, + {0x0306, 0x01}, -+ {0x0307, 0x57}, ++ {0x0307, 0x40}, + {0x0309, 0x0a}, + {0x030b, 0x02}, + {0x030d, 0x04}, + {0x030e, 0x01}, -+ {0x030f, 0x49}, ++ {0x030f, 0x10}, + {0x0310, 0x01}, -+ {0x0820, 0x07}, -+ {0x0821, 0xb6}, ++ {0x0820, 0x0a}, ++ {0x0821, 0x20}, + {0x0822, 0x00}, + {0x0823, 0x00}, + {0x3e20, 0x01}, -+ {0x3e37, 0x00}, ++ {0x3e37, 0x01}, + {0x3e3b, 0x00}, ++ {0x38a4, 0x00}, ++ {0x38a5, 0x00}, ++ {0x38a6, 0x00}, ++ {0x38a7, 0x00}, ++ {0x38a8, 0x00}, ++ {0x38a9, 0xf0}, ++ {0x38aa, 0x00}, ++ {0x38ab, 0xb4}, + {0x0106, 0x00}, + {0x0b00, 0x00}, + {0x3230, 0x00}, @@ -75287,10 +112859,10 @@ + {0x0112, 0x0a}, + {0x0113, 0x0a}, + {0x0114, 0x01}, -+ {0x0342, 0x24}, -+ {0x0343, 0x12}, -+ {0x0340, 0x09}, -+ {0x0341, 0xac}, ++ {0x0342, 0x19}, ++ {0x0343, 0x70}, ++ {0x0340, 0x08}, ++ {0x0341, 0x88}, + {0x0344, 0x00}, + {0x0345, 0x00}, + {0x0346, 0x00}, @@ -75305,8 +112877,8 @@ + {0x0900, 0x01}, + {0x0901, 0x22}, + {0x0902, 0x0a}, -+ {0x3f4c, 0x01}, -+ {0x3f4d, 0x01}, ++ {0x3f4c, 0x05}, ++ {0x3f4d, 0x03}, + {0x4254, 0x7f}, + {0x0401, 0x00}, + {0x0404, 0x00}, @@ -75325,22 +112897,30 @@ + {0x034f, 0xd4}, + {0x0301, 0x06}, + {0x0303, 0x04}, -+ {0x0305, 0x04}, ++ {0x0305, 0x06}, + {0x0306, 0x01}, -+ {0x0307, 0x57}, ++ {0x0307, 0x40}, + {0x0309, 0x0a}, + {0x030b, 0x02}, + {0x030d, 0x04}, + {0x030e, 0x01}, -+ {0x030f, 0x49}, ++ {0x030f, 0x10}, + {0x0310, 0x01}, -+ {0x0820, 0x07}, -+ {0x0821, 0xb6}, ++ {0x0820, 0x0a}, ++ {0x0821, 0x20}, + {0x0822, 0x00}, + {0x0823, 0x00}, + {0x3e20, 0x01}, -+ {0x3e37, 0x00}, ++ {0x3e37, 0x01}, + {0x3e3b, 0x00}, ++ {0x38a4, 0x00}, ++ {0x38a5, 0x00}, ++ {0x38a6, 0x00}, ++ {0x38a7, 0x00}, ++ {0x38a8, 0x00}, ++ {0x38a9, 0x91}, ++ {0x38aa, 0x00}, ++ {0x38ab, 0x91}, + {0x0106, 0x00}, + {0x0b00, 0x00}, + {0x3230, 0x00}, @@ -75364,8 +112944,8 @@ + {0x0112, 0x0a}, + {0x0113, 0x0a}, + {0x0114, 0x01}, -+ {0x0342, 0x25}, -+ {0x0343, 0xd9}, ++ {0x0342, 0x17}, ++ {0x0343, 0x8b}, + {0x0340, 0x04}, + {0x0341, 0x9c}, + {0x0344, 0x01}, @@ -75382,8 +112962,8 @@ + {0x0900, 0x01}, + {0x0901, 0x22}, + {0x0902, 0x0a}, -+ {0x3f4c, 0x01}, -+ {0x3f4d, 0x01}, ++ {0x3f4c, 0x05}, ++ {0x3f4d, 0x03}, + {0x4254, 0x7f}, + {0x0401, 0x00}, + {0x0404, 0x00}, @@ -75402,22 +112982,30 @@ + {0x034f, 0x38}, + {0x0301, 0x06}, + {0x0303, 0x04}, -+ {0x0305, 0x04}, ++ {0x0305, 0x06}, + {0x0306, 0x01}, -+ {0x0307, 0x57}, ++ {0x0307, 0x40}, + {0x0309, 0x0a}, + {0x030b, 0x02}, + {0x030d, 0x04}, + {0x030e, 0x01}, -+ {0x030f, 0x49}, ++ {0x030f, 0x10}, + {0x0310, 0x01}, -+ {0x0820, 0x07}, -+ {0x0821, 0xb6}, ++ {0x0820, 0x0a}, ++ {0x0821, 0x20}, + {0x0822, 0x00}, + {0x0823, 0x00}, + {0x3e20, 0x01}, -+ {0x3e37, 0x00}, ++ {0x3e37, 0x01}, + {0x3e3b, 0x00}, ++ {0x38a4, 0x00}, ++ {0x38a5, 0x00}, ++ {0x38a6, 0x00}, ++ {0x38a7, 0x00}, ++ {0x38a8, 0x00}, ++ {0x38a9, 0x78}, ++ {0x38aa, 0x00}, ++ {0x38ab, 0x5a}, + {0x0106, 0x00}, + {0x0b00, 0x00}, + {0x3230, 0x00}, @@ -75441,8 +113029,8 @@ + {0x0112, 0x0a}, + {0x0113, 0x0a}, + {0x0114, 0x01}, -+ {0x0342, 0x1b}, -+ {0x0343, 0x3b}, ++ {0x0342, 0x18}, ++ {0x0343, 0x00}, + {0x0340, 0x03}, + {0x0341, 0x34}, + {0x0344, 0x04}, @@ -75459,8 +113047,8 @@ + {0x0900, 0x01}, + {0x0901, 0x22}, + {0x0902, 0x0a}, -+ {0x3f4c, 0x01}, -+ {0x3f4d, 0x01}, ++ {0x3f4c, 0x05}, ++ {0x3f4d, 0x03}, + {0x4254, 0x7f}, + {0x0401, 0x00}, + {0x0404, 0x00}, @@ -75479,22 +113067,30 @@ + {0x034f, 0xd0}, + {0x0301, 0x06}, + {0x0303, 0x04}, -+ {0x0305, 0x04}, ++ {0x0305, 0x06}, + {0x0306, 0x01}, -+ {0x0307, 0x57}, ++ {0x0307, 0x40}, + {0x0309, 0x0a}, + {0x030b, 0x02}, + {0x030d, 0x04}, + {0x030e, 0x01}, -+ {0x030f, 0x49}, ++ {0x030f, 0x10}, + {0x0310, 0x01}, -+ {0x0820, 0x07}, -+ {0x0821, 0xb6}, ++ {0x0820, 0x0a}, ++ {0x0821, 0x20}, + {0x0822, 0x00}, + {0x0823, 0x00}, + {0x3e20, 0x01}, -+ {0x3e37, 0x00}, ++ {0x3e37, 0x01}, + {0x3e3b, 0x00}, ++ {0x38a4, 0x00}, ++ {0x38a5, 0x00}, ++ {0x38a6, 0x00}, ++ {0x38a7, 0x00}, ++ {0x38a8, 0x00}, ++ {0x38a9, 0x50}, ++ {0x38aa, 0x00}, ++ {0x38ab, 0x3c}, + {0x0106, 0x00}, + {0x0b00, 0x00}, + {0x3230, 0x00}, @@ -75517,7 +113113,7 @@ + { + .width = 4656, + .height = 3496, -+ .line_length_pix = 0x4200, ++ .line_length_pix = 0x316a, + .crop = { + .left = IMX519_PIXEL_ARRAY_LEFT, + .top = IMX519_PIXEL_ARRAY_TOP, @@ -75526,11 +113122,11 @@ + }, + .timeperframe_min = { + .numerator = 100, -+ .denominator = 1000 ++ .denominator = 900 + }, + .timeperframe_default = { + .numerator = 100, -+ .denominator = 1000 ++ .denominator = 900 + }, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_4656x3496_regs), @@ -75540,7 +113136,7 @@ + { + .width = 3840, + .height = 2160, -+ .line_length_pix = 0x3870, ++ .line_length_pix = 0x28f6, + .crop = { + .left = IMX519_PIXEL_ARRAY_LEFT + 408, + .top = IMX519_PIXEL_ARRAY_TOP + 672, @@ -75549,11 +113145,11 @@ + }, + .timeperframe_min = { + .numerator = 100, -+ .denominator = 2100 ++ .denominator = 1800 + }, + .timeperframe_default = { + .numerator = 100, -+ .denominator = 2100 ++ .denominator = 1800 + }, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_3840x2160_regs), @@ -75563,7 +113159,7 @@ + { + .width = 2328, + .height = 1748, -+ .line_length_pix = 0x2412, ++ .line_length_pix = 0x1970, + .crop = { + .left = IMX519_PIXEL_ARRAY_LEFT, + .top = IMX519_PIXEL_ARRAY_TOP, @@ -75586,7 +113182,7 @@ + { + .width = 1920, + .height = 1080, -+ .line_length_pix = 0x25D9, ++ .line_length_pix = 0x178b, + .crop = { + .left = IMX519_PIXEL_ARRAY_LEFT + 408, + .top = IMX519_PIXEL_ARRAY_TOP + 674, @@ -75609,7 +113205,7 @@ + { + .width = 1280, + .height = 720, -+ .line_length_pix = 0x1B3B, ++ .line_length_pix = 0x1800, + .crop = { + .left = IMX519_PIXEL_ARRAY_LEFT + 1048, + .top = IMX519_PIXEL_ARRAY_TOP + 1042, @@ -75618,11 +113214,11 @@ + }, + .timeperframe_min = { + .numerator = 100, -+ .denominator = 12000 ++ .denominator = 8000 + }, + .timeperframe_default = { + .numerator = 100, -+ .denominator = 12000 ++ .denominator = 8000 + }, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1280x720_regs), @@ -75818,9 +113414,9 @@ +{ + struct imx519 *imx519 = to_imx519(sd); + struct v4l2_mbus_framefmt *try_fmt_img = -+ v4l2_subdev_get_try_format(sd, fh->pad, IMAGE_PAD); ++ v4l2_subdev_get_try_format(sd, fh->state, IMAGE_PAD); + struct v4l2_mbus_framefmt *try_fmt_meta = -+ v4l2_subdev_get_try_format(sd, fh->pad, METADATA_PAD); ++ v4l2_subdev_get_try_format(sd, fh->state, METADATA_PAD); + struct v4l2_rect *try_crop; + + mutex_lock(&imx519->mutex); @@ -75838,7 +113434,7 @@ + try_fmt_meta->field = V4L2_FIELD_NONE; + + /* Initialize try_crop */ -+ try_crop = v4l2_subdev_get_try_crop(sd, fh->pad, IMAGE_PAD); ++ try_crop = v4l2_subdev_get_try_crop(sd, fh->state, IMAGE_PAD); + try_crop->left = IMX519_PIXEL_ARRAY_LEFT; + try_crop->top = IMX519_PIXEL_ARRAY_TOP; + try_crop->width = IMX519_PIXEL_ARRAY_WIDTH; @@ -75966,7 +113562,7 @@ +}; + +static int imx519_enum_mbus_code(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct imx519 *imx519 = to_imx519(sd); @@ -75990,7 +113586,7 @@ +} + +static int imx519_enum_frame_size(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct imx519 *imx519 = to_imx519(sd); @@ -76051,7 +113647,7 @@ +} + +static int imx519_get_pad_format(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct imx519 *imx519 = to_imx519(sd); @@ -76063,7 +113659,8 @@ + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *try_fmt = -+ v4l2_subdev_get_try_format(&imx519->sd, cfg, fmt->pad); ++ v4l2_subdev_get_try_format(&imx519->sd, sd_state, ++ fmt->pad); + /* update the code which could change due to vflip or hflip: */ + try_fmt->code = fmt->pad == IMAGE_PAD ? + imx519_get_format_code(imx519) : @@ -76131,7 +113728,7 @@ +} + +static int imx519_set_pad_format(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *framefmt; @@ -76154,7 +113751,7 @@ + fmt->format.height); + imx519_update_image_pad_format(imx519, mode, fmt); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { -+ framefmt = v4l2_subdev_get_try_format(sd, cfg, ++ framefmt = v4l2_subdev_get_try_format(sd, sd_state, + fmt->pad); + *framefmt = fmt->format; + } else { @@ -76164,7 +113761,7 @@ + } + } else { + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { -+ framefmt = v4l2_subdev_get_try_format(sd, cfg, ++ framefmt = v4l2_subdev_get_try_format(sd, sd_state, + fmt->pad); + *framefmt = fmt->format; + } else { @@ -76179,12 +113776,12 @@ +} + +static const struct v4l2_rect * -+__imx519_get_pad_crop(struct imx519 *imx519, struct v4l2_subdev_pad_config *cfg, ++__imx519_get_pad_crop(struct imx519 *imx519, struct v4l2_subdev_state *sd_state, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: -+ return v4l2_subdev_get_try_crop(&imx519->sd, cfg, pad); ++ return v4l2_subdev_get_try_crop(&imx519->sd, sd_state, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return &imx519->mode->crop; + } @@ -76193,7 +113790,7 @@ +} + +static int imx519_get_selection(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { @@ -76201,7 +113798,7 @@ + struct imx519 *imx519 = to_imx519(sd); + + mutex_lock(&imx519->mutex); -+ sel->r = *__imx519_get_pad_crop(imx519, cfg, sel->pad, ++ sel->r = *__imx519_get_pad_crop(imx519, sd_state, sel->pad, + sel->which); + mutex_unlock(&imx519->mutex); + @@ -76483,6 +114080,7 @@ + struct v4l2_ctrl_handler *ctrl_hdlr; + struct i2c_client *client = v4l2_get_subdevdata(&imx519->sd); + struct v4l2_fwnode_device_properties props; ++ struct v4l2_ctrl *link_freq; + unsigned int i; + int ret; + @@ -76501,6 +114099,15 @@ + IMX519_PIXEL_RATE, 1, + IMX519_PIXEL_RATE); + ++ /* LINK_FREQ is also read only */ ++ link_freq = ++ v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx519_ctrl_ops, ++ V4L2_CID_LINK_FREQ, ++ ARRAY_SIZE(imx519_link_freq_menu) - 1, 0, ++ imx519_link_freq_menu); ++ if (link_freq) ++ link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ + /* + * Create the controls here, but mode specific limits are setup + * in the imx519_set_framing_limits() call below. @@ -76735,7 +114342,7 @@ + goto error_handler_free; + } + -+ ret = v4l2_async_register_subdev_sensor_common(&imx519->sd); ++ ret = v4l2_async_register_subdev_sensor(&imx519->sd); + if (ret < 0) { + dev_err(dev, "failed to register sensor sub-device: %d\n", ret); + goto error_media_entity; @@ -76757,7 +114364,7 @@ + return ret; +} + -+static int imx519_remove(struct i2c_client *client) ++static void imx519_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx519 *imx519 = to_imx519(sd); @@ -76770,8 +114377,6 @@ + if (!pm_runtime_status_suspended(&client->dev)) + imx519_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); -+ -+ return 0; +} + +MODULE_DEVICE_TABLE(of, imx519_dt_ids); @@ -76787,7 +114392,7 @@ + .of_match_table = imx519_dt_ids, + .pm = &imx519_pm_ops, + }, -+ .probe_new = imx519_probe, ++ .probe = imx519_probe, + .remove = imx519_remove, +}; + @@ -76796,12 +114401,2134 @@ +MODULE_AUTHOR("Lee Jackson <info@arducam.com>"); +MODULE_DESCRIPTION("Sony IMX519 sensor driver"); +MODULE_LICENSE("GPL v2"); +diff --git a/drivers/media/i2c/imx708.c b/drivers/media/i2c/imx708.c +new file mode 100644 +index 000000000000..29b1d4479c50 +--- /dev/null ++++ b/drivers/media/i2c/imx708.c +@@ -0,0 +1,2116 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * A V4L2 driver for Sony IMX708 cameras. ++ * Copyright (C) 2022, Raspberry Pi Ltd ++ * ++ * Based on Sony imx477 camera driver ++ * Copyright (C) 2020 Raspberry Pi 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/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> ++ ++/* ++ * Parameter to adjust Quad Bayer re-mosaic broken line correction ++ * strength, used in full-resolution mode only. Set zero to disable. ++ */ ++static int qbc_adjust = 2; ++module_param(qbc_adjust, int, 0644); ++MODULE_PARM_DESC(qbc_adjust, "Quad Bayer broken line correction strength 0,2-5"); ++ ++#define IMX708_REG_VALUE_08BIT 1 ++#define IMX708_REG_VALUE_16BIT 2 ++ ++/* Chip ID */ ++#define IMX708_REG_CHIP_ID 0x0016 ++#define IMX708_CHIP_ID 0x0708 ++ ++#define IMX708_REG_MODE_SELECT 0x0100 ++#define IMX708_MODE_STANDBY 0x00 ++#define IMX708_MODE_STREAMING 0x01 ++ ++#define IMX708_REG_ORIENTATION 0x101 ++ ++#define IMX708_INCLK_FREQ 24000000 ++ ++/* Default initial pixel rate, will get updated for each mode. */ ++#define IMX708_INITIAL_PIXEL_RATE 590000000 ++ ++/* V_TIMING internal */ ++#define IMX708_REG_FRAME_LENGTH 0x0340 ++#define IMX708_FRAME_LENGTH_MAX 0xffff ++ ++/* Long exposure multiplier */ ++#define IMX708_LONG_EXP_SHIFT_MAX 7 ++#define IMX708_LONG_EXP_SHIFT_REG 0x3100 ++ ++/* Exposure control */ ++#define IMX708_REG_EXPOSURE 0x0202 ++#define IMX708_EXPOSURE_OFFSET 48 ++#define IMX708_EXPOSURE_DEFAULT 0x640 ++#define IMX708_EXPOSURE_STEP 1 ++#define IMX708_EXPOSURE_MIN 1 ++#define IMX708_EXPOSURE_MAX (IMX708_FRAME_LENGTH_MAX - \ ++ IMX708_EXPOSURE_OFFSET) ++ ++/* Analog gain control */ ++#define IMX708_REG_ANALOG_GAIN 0x0204 ++#define IMX708_ANA_GAIN_MIN 112 ++#define IMX708_ANA_GAIN_MAX 960 ++#define IMX708_ANA_GAIN_STEP 1 ++#define IMX708_ANA_GAIN_DEFAULT IMX708_ANA_GAIN_MIN ++ ++/* Digital gain control */ ++#define IMX708_REG_DIGITAL_GAIN 0x020e ++#define IMX708_DGTL_GAIN_MIN 0x0100 ++#define IMX708_DGTL_GAIN_MAX 0xffff ++#define IMX708_DGTL_GAIN_DEFAULT 0x0100 ++#define IMX708_DGTL_GAIN_STEP 1 ++ ++/* Colour balance controls */ ++#define IMX708_REG_COLOUR_BALANCE_RED 0x0b90 ++#define IMX708_REG_COLOUR_BALANCE_BLUE 0x0b92 ++#define IMX708_COLOUR_BALANCE_MIN 0x01 ++#define IMX708_COLOUR_BALANCE_MAX 0xffff ++#define IMX708_COLOUR_BALANCE_STEP 0x01 ++#define IMX708_COLOUR_BALANCE_DEFAULT 0x100 ++ ++/* Test Pattern Control */ ++#define IMX708_REG_TEST_PATTERN 0x0600 ++#define IMX708_TEST_PATTERN_DISABLE 0 ++#define IMX708_TEST_PATTERN_SOLID_COLOR 1 ++#define IMX708_TEST_PATTERN_COLOR_BARS 2 ++#define IMX708_TEST_PATTERN_GREY_COLOR 3 ++#define IMX708_TEST_PATTERN_PN9 4 ++ ++/* Test pattern colour components */ ++#define IMX708_REG_TEST_PATTERN_R 0x0602 ++#define IMX708_REG_TEST_PATTERN_GR 0x0604 ++#define IMX708_REG_TEST_PATTERN_B 0x0606 ++#define IMX708_REG_TEST_PATTERN_GB 0x0608 ++#define IMX708_TEST_PATTERN_COLOUR_MIN 0 ++#define IMX708_TEST_PATTERN_COLOUR_MAX 0x0fff ++#define IMX708_TEST_PATTERN_COLOUR_STEP 1 ++ ++#define IMX708_REG_BASE_SPC_GAINS_L 0x7b10 ++#define IMX708_REG_BASE_SPC_GAINS_R 0x7c00 ++ ++/* HDR exposure ratio (long:med == med:short) */ ++#define IMX708_HDR_EXPOSURE_RATIO 4 ++#define IMX708_REG_MID_EXPOSURE 0x3116 ++#define IMX708_REG_SHT_EXPOSURE 0x0224 ++#define IMX708_REG_MID_ANALOG_GAIN 0x3118 ++#define IMX708_REG_SHT_ANALOG_GAIN 0x0216 ++ ++/* QBC Re-mosaic broken line correction registers */ ++#define IMX708_LPF_INTENSITY_EN 0xC428 ++#define IMX708_LPF_INTENSITY_ENABLED 0x00 ++#define IMX708_LPF_INTENSITY_DISABLED 0x01 ++#define IMX708_LPF_INTENSITY 0xC429 ++ ++/* ++ * Metadata buffer holds a variety of data, all sent with the same VC/DT (0x12). ++ * It comprises two scanlines (of up to 5760 bytes each, for 4608 pixels) ++ * of embedded data, one line of PDAF data, and two lines of AE-HIST data ++ * (AE histograms are valid for HDR mode and empty in non-HDR modes). ++ */ ++#define IMX708_EMBEDDED_LINE_WIDTH (5 * 5760) ++#define IMX708_NUM_EMBEDDED_LINES 1 ++ ++enum pad_types { ++ IMAGE_PAD, ++ METADATA_PAD, ++ NUM_PADS ++}; ++ ++/* IMX708 native and active pixel array size. */ ++#define IMX708_NATIVE_WIDTH 4640U ++#define IMX708_NATIVE_HEIGHT 2658U ++#define IMX708_PIXEL_ARRAY_LEFT 16U ++#define IMX708_PIXEL_ARRAY_TOP 24U ++#define IMX708_PIXEL_ARRAY_WIDTH 4608U ++#define IMX708_PIXEL_ARRAY_HEIGHT 2592U ++ ++struct imx708_reg { ++ u16 address; ++ u8 val; ++}; ++ ++struct imx708_reg_list { ++ unsigned int num_of_regs; ++ const struct imx708_reg *regs; ++}; ++ ++/* Mode : resolution and related config&values */ ++struct imx708_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. */ ++ unsigned int vblank_min; ++ ++ /* Default framerate. */ ++ unsigned int vblank_default; ++ ++ /* Default register values */ ++ struct imx708_reg_list reg_list; ++ ++ /* Not all modes have the same pixel rate. */ ++ u64 pixel_rate; ++ ++ /* Not all modes have the same minimum exposure. */ ++ u32 exposure_lines_min; ++ ++ /* Not all modes have the same exposure lines step. */ ++ u32 exposure_lines_step; ++ ++ /* HDR flag, used for checking if the current mode is HDR */ ++ bool hdr; ++ ++ /* Quad Bayer Re-mosaic flag */ ++ bool remosaic; ++}; ++ ++/* Default PDAF pixel correction gains */ ++static const u8 pdaf_gains29 = { ++ { 0x4c, 0x4c, 0x4c, 0x46, 0x3e, 0x38, 0x35, 0x35, 0x35 }, ++ { 0x35, 0x35, 0x35, 0x38, 0x3e, 0x46, 0x4c, 0x4c, 0x4c } ++}; ++ ++/* Link frequency setup */ ++enum { ++ IMX708_LINK_FREQ_450MHZ, ++ IMX708_LINK_FREQ_447MHZ, ++ IMX708_LINK_FREQ_453MHZ, ++}; ++ ++static const s64 link_freqs = { ++ IMX708_LINK_FREQ_450MHZ = 450000000, ++ IMX708_LINK_FREQ_447MHZ = 447000000, ++ IMX708_LINK_FREQ_453MHZ = 453000000, ++}; ++ ++/* 450MHz is the nominal "default" link frequency */ ++static const struct imx708_reg link_450Mhz_regs = { ++ {0x030E, 0x01}, ++ {0x030F, 0x2c}, ++}; ++ ++static const struct imx708_reg link_447Mhz_regs = { ++ {0x030E, 0x01}, ++ {0x030F, 0x2a}, ++}; ++ ++static const struct imx708_reg link_453Mhz_regs = { ++ {0x030E, 0x01}, ++ {0x030F, 0x2e}, ++}; ++ ++static const struct imx708_reg_list link_freq_regs = { ++ IMX708_LINK_FREQ_450MHZ = { ++ .regs = link_450Mhz_regs, ++ .num_of_regs = ARRAY_SIZE(link_450Mhz_regs) ++ }, ++ IMX708_LINK_FREQ_447MHZ = { ++ .regs = link_447Mhz_regs, ++ .num_of_regs = ARRAY_SIZE(link_447Mhz_regs) ++ }, ++ IMX708_LINK_FREQ_453MHZ = { ++ .regs = link_453Mhz_regs, ++ .num_of_regs = ARRAY_SIZE(link_453Mhz_regs) ++ }, ++}; ++ ++static const struct imx708_reg mode_common_regs = { ++ {0x0100, 0x00}, ++ {0x0136, 0x18}, ++ {0x0137, 0x00}, ++ {0x33F0, 0x02}, ++ {0x33F1, 0x05}, ++ {0x3062, 0x00}, ++ {0x3063, 0x12}, ++ {0x3068, 0x00}, ++ {0x3069, 0x12}, ++ {0x306A, 0x00}, ++ {0x306B, 0x30}, ++ {0x3076, 0x00}, ++ {0x3077, 0x30}, ++ {0x3078, 0x00}, ++ {0x3079, 0x30}, ++ {0x5E54, 0x0C}, ++ {0x6E44, 0x00}, ++ {0xB0B6, 0x01}, ++ {0xE829, 0x00}, ++ {0xF001, 0x08}, ++ {0xF003, 0x08}, ++ {0xF00D, 0x10}, ++ {0xF00F, 0x10}, ++ {0xF031, 0x08}, ++ {0xF033, 0x08}, ++ {0xF03D, 0x10}, ++ {0xF03F, 0x10}, ++ {0x0112, 0x0A}, ++ {0x0113, 0x0A}, ++ {0x0114, 0x01}, ++ {0x0B8E, 0x01}, ++ {0x0B8F, 0x00}, ++ {0x0B94, 0x01}, ++ {0x0B95, 0x00}, ++ {0x3400, 0x01}, ++ {0x3478, 0x01}, ++ {0x3479, 0x1c}, ++ {0x3091, 0x01}, ++ {0x3092, 0x00}, ++ {0x3419, 0x00}, ++ {0xBCF1, 0x02}, ++ {0x3094, 0x01}, ++ {0x3095, 0x01}, ++ {0x3362, 0x00}, ++ {0x3363, 0x00}, ++ {0x3364, 0x00}, ++ {0x3365, 0x00}, ++ {0x0138, 0x01}, ++}; ++ ++/* 10-bit. */ ++static const struct imx708_reg mode_4608x2592_regs = { ++ {0x0342, 0x3D}, ++ {0x0343, 0x20}, ++ {0x0340, 0x0A}, ++ {0x0341, 0x59}, ++ {0x0344, 0x00}, ++ {0x0345, 0x00}, ++ {0x0346, 0x00}, ++ {0x0347, 0x00}, ++ {0x0348, 0x11}, ++ {0x0349, 0xFF}, ++ {0x034A, 0X0A}, ++ {0x034B, 0x1F}, ++ {0x0220, 0x62}, ++ {0x0222, 0x01}, ++ {0x0900, 0x00}, ++ {0x0901, 0x11}, ++ {0x0902, 0x0A}, ++ {0x3200, 0x01}, ++ {0x3201, 0x01}, ++ {0x32D5, 0x01}, ++ {0x32D6, 0x00}, ++ {0x32DB, 0x01}, ++ {0x32DF, 0x00}, ++ {0x350C, 0x00}, ++ {0x350D, 0x00}, ++ {0x0408, 0x00}, ++ {0x0409, 0x00}, ++ {0x040A, 0x00}, ++ {0x040B, 0x00}, ++ {0x040C, 0x12}, ++ {0x040D, 0x00}, ++ {0x040E, 0x0A}, ++ {0x040F, 0x20}, ++ {0x034C, 0x12}, ++ {0x034D, 0x00}, ++ {0x034E, 0x0A}, ++ {0x034F, 0x20}, ++ {0x0301, 0x05}, ++ {0x0303, 0x02}, ++ {0x0305, 0x02}, ++ {0x0306, 0x00}, ++ {0x0307, 0x7C}, ++ {0x030B, 0x02}, ++ {0x030D, 0x04}, ++ {0x0310, 0x01}, ++ {0x3CA0, 0x00}, ++ {0x3CA1, 0x64}, ++ {0x3CA4, 0x00}, ++ {0x3CA5, 0x00}, ++ {0x3CA6, 0x00}, ++ {0x3CA7, 0x00}, ++ {0x3CAA, 0x00}, ++ {0x3CAB, 0x00}, ++ {0x3CB8, 0x00}, ++ {0x3CB9, 0x08}, ++ {0x3CBA, 0x00}, ++ {0x3CBB, 0x00}, ++ {0x3CBC, 0x00}, ++ {0x3CBD, 0x3C}, ++ {0x3CBE, 0x00}, ++ {0x3CBF, 0x00}, ++ {0x0202, 0x0A}, ++ {0x0203, 0x29}, ++ {0x0224, 0x01}, ++ {0x0225, 0xF4}, ++ {0x3116, 0x01}, ++ {0x3117, 0xF4}, ++ {0x0204, 0x00}, ++ {0x0205, 0x00}, ++ {0x0216, 0x00}, ++ {0x0217, 0x00}, ++ {0x0218, 0x01}, ++ {0x0219, 0x00}, ++ {0x020E, 0x01}, ++ {0x020F, 0x00}, ++ {0x3118, 0x00}, ++ {0x3119, 0x00}, ++ {0x311A, 0x01}, ++ {0x311B, 0x00}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x01}, ++ {0x341f, 0x20}, ++ {0x3420, 0x00}, ++ {0x3421, 0xd8}, ++ {0x3366, 0x00}, ++ {0x3367, 0x00}, ++ {0x3368, 0x00}, ++ {0x3369, 0x00}, ++}; ++ ++static const struct imx708_reg mode_2x2binned_regs = { ++ {0x0342, 0x1E}, ++ {0x0343, 0x90}, ++ {0x0340, 0x05}, ++ {0x0341, 0x38}, ++ {0x0344, 0x00}, ++ {0x0345, 0x00}, ++ {0x0346, 0x00}, ++ {0x0347, 0x00}, ++ {0x0348, 0x11}, ++ {0x0349, 0xFF}, ++ {0x034A, 0X0A}, ++ {0x034B, 0x1F}, ++ {0x0220, 0x62}, ++ {0x0222, 0x01}, ++ {0x0900, 0x01}, ++ {0x0901, 0x22}, ++ {0x0902, 0x08}, ++ {0x3200, 0x41}, ++ {0x3201, 0x41}, ++ {0x32D5, 0x00}, ++ {0x32D6, 0x00}, ++ {0x32DB, 0x01}, ++ {0x32DF, 0x00}, ++ {0x350C, 0x00}, ++ {0x350D, 0x00}, ++ {0x0408, 0x00}, ++ {0x0409, 0x00}, ++ {0x040A, 0x00}, ++ {0x040B, 0x00}, ++ {0x040C, 0x09}, ++ {0x040D, 0x00}, ++ {0x040E, 0x05}, ++ {0x040F, 0x10}, ++ {0x034C, 0x09}, ++ {0x034D, 0x00}, ++ {0x034E, 0x05}, ++ {0x034F, 0x10}, ++ {0x0301, 0x05}, ++ {0x0303, 0x02}, ++ {0x0305, 0x02}, ++ {0x0306, 0x00}, ++ {0x0307, 0x7A}, ++ {0x030B, 0x02}, ++ {0x030D, 0x04}, ++ {0x0310, 0x01}, ++ {0x3CA0, 0x00}, ++ {0x3CA1, 0x3C}, ++ {0x3CA4, 0x00}, ++ {0x3CA5, 0x3C}, ++ {0x3CA6, 0x00}, ++ {0x3CA7, 0x00}, ++ {0x3CAA, 0x00}, ++ {0x3CAB, 0x00}, ++ {0x3CB8, 0x00}, ++ {0x3CB9, 0x1C}, ++ {0x3CBA, 0x00}, ++ {0x3CBB, 0x08}, ++ {0x3CBC, 0x00}, ++ {0x3CBD, 0x1E}, ++ {0x3CBE, 0x00}, ++ {0x3CBF, 0x0A}, ++ {0x0202, 0x05}, ++ {0x0203, 0x08}, ++ {0x0224, 0x01}, ++ {0x0225, 0xF4}, ++ {0x3116, 0x01}, ++ {0x3117, 0xF4}, ++ {0x0204, 0x00}, ++ {0x0205, 0x70}, ++ {0x0216, 0x00}, ++ {0x0217, 0x70}, ++ {0x0218, 0x01}, ++ {0x0219, 0x00}, ++ {0x020E, 0x01}, ++ {0x020F, 0x00}, ++ {0x3118, 0x00}, ++ {0x3119, 0x70}, ++ {0x311A, 0x01}, ++ {0x311B, 0x00}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x00}, ++ {0x341f, 0x90}, ++ {0x3420, 0x00}, ++ {0x3421, 0x6c}, ++ {0x3366, 0x00}, ++ {0x3367, 0x00}, ++ {0x3368, 0x00}, ++ {0x3369, 0x00}, ++}; ++ ++static const struct imx708_reg mode_2x2binned_720p_regs = { ++ {0x0342, 0x14}, ++ {0x0343, 0x60}, ++ {0x0340, 0x04}, ++ {0x0341, 0xB6}, ++ {0x0344, 0x03}, ++ {0x0345, 0x00}, ++ {0x0346, 0x01}, ++ {0x0347, 0xB0}, ++ {0x0348, 0x0E}, ++ {0x0349, 0xFF}, ++ {0x034A, 0x08}, ++ {0x034B, 0x6F}, ++ {0x0220, 0x62}, ++ {0x0222, 0x01}, ++ {0x0900, 0x01}, ++ {0x0901, 0x22}, ++ {0x0902, 0x08}, ++ {0x3200, 0x41}, ++ {0x3201, 0x41}, ++ {0x32D5, 0x00}, ++ {0x32D6, 0x00}, ++ {0x32DB, 0x01}, ++ {0x32DF, 0x01}, ++ {0x350C, 0x00}, ++ {0x350D, 0x00}, ++ {0x0408, 0x00}, ++ {0x0409, 0x00}, ++ {0x040A, 0x00}, ++ {0x040B, 0x00}, ++ {0x040C, 0x06}, ++ {0x040D, 0x00}, ++ {0x040E, 0x03}, ++ {0x040F, 0x60}, ++ {0x034C, 0x06}, ++ {0x034D, 0x00}, ++ {0x034E, 0x03}, ++ {0x034F, 0x60}, ++ {0x0301, 0x05}, ++ {0x0303, 0x02}, ++ {0x0305, 0x02}, ++ {0x0306, 0x00}, ++ {0x0307, 0x76}, ++ {0x030B, 0x02}, ++ {0x030D, 0x04}, ++ {0x0310, 0x01}, ++ {0x3CA0, 0x00}, ++ {0x3CA1, 0x3C}, ++ {0x3CA4, 0x01}, ++ {0x3CA5, 0x5E}, ++ {0x3CA6, 0x00}, ++ {0x3CA7, 0x00}, ++ {0x3CAA, 0x00}, ++ {0x3CAB, 0x00}, ++ {0x3CB8, 0x00}, ++ {0x3CB9, 0x0C}, ++ {0x3CBA, 0x00}, ++ {0x3CBB, 0x04}, ++ {0x3CBC, 0x00}, ++ {0x3CBD, 0x1E}, ++ {0x3CBE, 0x00}, ++ {0x3CBF, 0x05}, ++ {0x0202, 0x04}, ++ {0x0203, 0x86}, ++ {0x0224, 0x01}, ++ {0x0225, 0xF4}, ++ {0x3116, 0x01}, ++ {0x3117, 0xF4}, ++ {0x0204, 0x00}, ++ {0x0205, 0x70}, ++ {0x0216, 0x00}, ++ {0x0217, 0x70}, ++ {0x0218, 0x01}, ++ {0x0219, 0x00}, ++ {0x020E, 0x01}, ++ {0x020F, 0x00}, ++ {0x3118, 0x00}, ++ {0x3119, 0x70}, ++ {0x311A, 0x01}, ++ {0x311B, 0x00}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x00}, ++ {0x341f, 0x60}, ++ {0x3420, 0x00}, ++ {0x3421, 0x48}, ++ {0x3366, 0x00}, ++ {0x3367, 0x00}, ++ {0x3368, 0x00}, ++ {0x3369, 0x00}, ++}; ++ ++static const struct imx708_reg mode_hdr_regs = { ++ {0x0342, 0x14}, ++ {0x0343, 0x60}, ++ {0x0340, 0x0A}, ++ {0x0341, 0x5B}, ++ {0x0344, 0x00}, ++ {0x0345, 0x00}, ++ {0x0346, 0x00}, ++ {0x0347, 0x00}, ++ {0x0348, 0x11}, ++ {0x0349, 0xFF}, ++ {0x034A, 0X0A}, ++ {0x034B, 0x1F}, ++ {0x0220, 0x01}, ++ {0x0222, IMX708_HDR_EXPOSURE_RATIO}, ++ {0x0900, 0x00}, ++ {0x0901, 0x11}, ++ {0x0902, 0x0A}, ++ {0x3200, 0x01}, ++ {0x3201, 0x01}, ++ {0x32D5, 0x00}, ++ {0x32D6, 0x00}, ++ {0x32DB, 0x01}, ++ {0x32DF, 0x00}, ++ {0x350C, 0x00}, ++ {0x350D, 0x00}, ++ {0x0408, 0x00}, ++ {0x0409, 0x00}, ++ {0x040A, 0x00}, ++ {0x040B, 0x00}, ++ {0x040C, 0x09}, ++ {0x040D, 0x00}, ++ {0x040E, 0x05}, ++ {0x040F, 0x10}, ++ {0x034C, 0x09}, ++ {0x034D, 0x00}, ++ {0x034E, 0x05}, ++ {0x034F, 0x10}, ++ {0x0301, 0x05}, ++ {0x0303, 0x02}, ++ {0x0305, 0x02}, ++ {0x0306, 0x00}, ++ {0x0307, 0xA2}, ++ {0x030B, 0x02}, ++ {0x030D, 0x04}, ++ {0x0310, 0x01}, ++ {0x3CA0, 0x00}, ++ {0x3CA1, 0x00}, ++ {0x3CA4, 0x00}, ++ {0x3CA5, 0x00}, ++ {0x3CA6, 0x00}, ++ {0x3CA7, 0x28}, ++ {0x3CAA, 0x00}, ++ {0x3CAB, 0x00}, ++ {0x3CB8, 0x00}, ++ {0x3CB9, 0x30}, ++ {0x3CBA, 0x00}, ++ {0x3CBB, 0x00}, ++ {0x3CBC, 0x00}, ++ {0x3CBD, 0x32}, ++ {0x3CBE, 0x00}, ++ {0x3CBF, 0x00}, ++ {0x0202, 0x0A}, ++ {0x0203, 0x2B}, ++ {0x0224, 0x0A}, ++ {0x0225, 0x2B}, ++ {0x3116, 0x0A}, ++ {0x3117, 0x2B}, ++ {0x0204, 0x00}, ++ {0x0205, 0x00}, ++ {0x0216, 0x00}, ++ {0x0217, 0x00}, ++ {0x0218, 0x01}, ++ {0x0219, 0x00}, ++ {0x020E, 0x01}, ++ {0x020F, 0x00}, ++ {0x3118, 0x00}, ++ {0x3119, 0x00}, ++ {0x311A, 0x01}, ++ {0x311B, 0x00}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x00}, ++ {0x341f, 0x90}, ++ {0x3420, 0x00}, ++ {0x3421, 0x6c}, ++ {0x3360, 0x01}, ++ {0x3361, 0x01}, ++ {0x3366, 0x09}, ++ {0x3367, 0x00}, ++ {0x3368, 0x05}, ++ {0x3369, 0x10}, ++}; ++ ++/* Mode configs. Keep separate lists for when HDR is enabled or not. */ ++static const struct imx708_mode supported_modes_10bit_no_hdr = { ++ { ++ /* Full resolution. */ ++ .width = 4608, ++ .height = 2592, ++ .line_length_pix = 0x3d20, ++ .crop = { ++ .left = IMX708_PIXEL_ARRAY_LEFT, ++ .top = IMX708_PIXEL_ARRAY_TOP, ++ .width = 4608, ++ .height = 2592, ++ }, ++ .vblank_min = 58, ++ .vblank_default = 58, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_4608x2592_regs), ++ .regs = mode_4608x2592_regs, ++ }, ++ .pixel_rate = 595200000, ++ .exposure_lines_min = 8, ++ .exposure_lines_step = 1, ++ .hdr = false, ++ .remosaic = true ++ }, ++ { ++ /* regular 2x2 binned. */ ++ .width = 2304, ++ .height = 1296, ++ .line_length_pix = 0x1e90, ++ .crop = { ++ .left = IMX708_PIXEL_ARRAY_LEFT, ++ .top = IMX708_PIXEL_ARRAY_TOP, ++ .width = 4608, ++ .height = 2592, ++ }, ++ .vblank_min = 40, ++ .vblank_default = 1198, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_2x2binned_regs), ++ .regs = mode_2x2binned_regs, ++ }, ++ .pixel_rate = 585600000, ++ .exposure_lines_min = 4, ++ .exposure_lines_step = 2, ++ .hdr = false, ++ .remosaic = false ++ }, ++ { ++ /* 2x2 binned and cropped for 720p. */ ++ .width = 1536, ++ .height = 864, ++ .line_length_pix = 0x1460, ++ .crop = { ++ .left = IMX708_PIXEL_ARRAY_LEFT + 768, ++ .top = IMX708_PIXEL_ARRAY_TOP + 432, ++ .width = 3072, ++ .height = 1728, ++ }, ++ .vblank_min = 40, ++ .vblank_default = 2755, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_2x2binned_720p_regs), ++ .regs = mode_2x2binned_720p_regs, ++ }, ++ .pixel_rate = 566400000, ++ .exposure_lines_min = 4, ++ .exposure_lines_step = 2, ++ .hdr = false, ++ .remosaic = false ++ }, ++}; ++ ++static const struct imx708_mode supported_modes_10bit_hdr = { ++ { ++ /* There's only one HDR mode, which is 2x2 downscaled */ ++ .width = 2304, ++ .height = 1296, ++ .line_length_pix = 0x1460, ++ .crop = { ++ .left = IMX708_PIXEL_ARRAY_LEFT, ++ .top = IMX708_PIXEL_ARRAY_TOP, ++ .width = 4608, ++ .height = 2592, ++ }, ++ .vblank_min = 3673, ++ .vblank_default = 3673, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_hdr_regs), ++ .regs = mode_hdr_regs, ++ }, ++ .pixel_rate = 777600000, ++ .exposure_lines_min = 8 * IMX708_HDR_EXPOSURE_RATIO * IMX708_HDR_EXPOSURE_RATIO, ++ .exposure_lines_step = 2 * IMX708_HDR_EXPOSURE_RATIO * IMX708_HDR_EXPOSURE_RATIO, ++ .hdr = true, ++ .remosaic = false ++ } ++}; ++ ++/* ++ * 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 = { ++ /* 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 imx708_test_pattern_menu = { ++ "Disabled", ++ "Color Bars", ++ "Solid Color", ++ "Grey Color Bars", ++ "PN9" ++}; ++ ++static const int imx708_test_pattern_val = { ++ IMX708_TEST_PATTERN_DISABLE, ++ IMX708_TEST_PATTERN_COLOR_BARS, ++ IMX708_TEST_PATTERN_SOLID_COLOR, ++ IMX708_TEST_PATTERN_GREY_COLOR, ++ IMX708_TEST_PATTERN_PN9, ++}; ++ ++/* regulator supplies */ ++static const char * const imx708_supply_name = { ++ /* Supplies can be enabled in any order */ ++ "vana1", /* Analog1 (2.8V) supply */ ++ "vana2", /* Analog2 (1.8V) supply */ ++ "vdig", /* Digital Core (1.1V) supply */ ++ "vddl", /* IF (1.8V) supply */ ++}; ++ ++/* ++ * 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 IMX708_XCLR_MIN_DELAY_US 8000 ++#define IMX708_XCLR_DELAY_RANGE_US 1000 ++ ++struct imx708 { ++ struct v4l2_subdev sd; ++ struct media_pad padNUM_PADS; ++ ++ struct v4l2_mbus_framefmt fmt; ++ ++ struct clk *inclk; ++ u32 inclk_freq; ++ ++ struct gpio_desc *reset_gpio; ++ struct regulator_bulk_data suppliesARRAY_SIZE(imx708_supply_name); ++ ++ struct v4l2_ctrl_handler ctrl_handler; ++ /* V4L2 Controls */ ++ struct v4l2_ctrl *pixel_rate; ++ struct v4l2_ctrl *exposure; ++ struct v4l2_ctrl *vblank; ++ struct v4l2_ctrl *hblank; ++ struct v4l2_ctrl *hdr_mode; ++ struct v4l2_ctrl *link_freq; ++ struct { ++ struct v4l2_ctrl *hflip; ++ struct v4l2_ctrl *vflip; ++ }; ++ ++ /* Current mode */ ++ const struct imx708_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; ++ ++ unsigned int link_freq_idx; ++}; ++ ++static inline struct imx708 *to_imx708(struct v4l2_subdev *_sd) ++{ ++ return container_of(_sd, struct imx708, sd); ++} ++ ++static inline void get_mode_table(unsigned int code, ++ const struct imx708_mode **mode_list, ++ unsigned int *num_modes, ++ bool hdr_enable) ++{ ++ switch (code) { ++ /* 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: ++ if (hdr_enable) { ++ *mode_list = supported_modes_10bit_hdr; ++ *num_modes = ARRAY_SIZE(supported_modes_10bit_hdr); ++ } else { ++ *mode_list = supported_modes_10bit_no_hdr; ++ *num_modes = ARRAY_SIZE(supported_modes_10bit_no_hdr); ++ } ++ break; ++ default: ++ *mode_list = NULL; ++ *num_modes = 0; ++ } ++} ++ ++/* Read registers up to 2 at a time */ ++static int imx708_read_reg(struct imx708 *imx708, u16 reg, u32 len, u32 *val) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd); ++ struct i2c_msg msgs2; ++ u8 addr_buf2 = { reg >> 8, reg & 0xff }; ++ u8 data_buf4 = { 0, }; ++ int ret; ++ ++ if (len > 4) ++ return -EINVAL; ++ ++ /* Write register address */ ++ msgs0.addr = client->addr; ++ msgs0.flags = 0; ++ msgs0.len = ARRAY_SIZE(addr_buf); ++ msgs0.buf = addr_buf; ++ ++ /* Read data from register */ ++ msgs1.addr = client->addr; ++ msgs1.flags = I2C_M_RD; ++ msgs1.len = len; ++ msgs1.buf = &data_buf4 - 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 imx708_write_reg(struct imx708 *imx708, u16 reg, u32 len, u32 val) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd); ++ u8 buf6; ++ ++ 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 imx708_write_regs(struct imx708 *imx708, ++ const struct imx708_reg *regs, u32 len) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd); ++ unsigned int i; ++ ++ for (i = 0; i < len; i++) { ++ int ret; ++ ++ ret = imx708_write_reg(imx708, regsi.address, 1, regsi.val); ++ if (ret) { ++ dev_err_ratelimited(&client->dev, ++ "Failed to write reg 0x%4.4x. error = %d\n", ++ regsi.address, ret); ++ ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++/* Get bayer order based on flip setting. */ ++static u32 imx708_get_format_code(struct imx708 *imx708) ++{ ++ unsigned int i; ++ ++ lockdep_assert_held(&imx708->mutex); ++ ++ i = (imx708->vflip->val ? 2 : 0) | ++ (imx708->hflip->val ? 1 : 0); ++ ++ return codesi; ++} ++ ++static void imx708_set_default_format(struct imx708 *imx708) ++{ ++ struct v4l2_mbus_framefmt *fmt = &imx708->fmt; ++ ++ /* Set default mode to max resolution */ ++ imx708->mode = &supported_modes_10bit_no_hdr0; ++ ++ /* fmt->code not set as it will always be computed based on flips */ ++ fmt->colorspace = V4L2_COLORSPACE_RAW; ++ 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); ++ fmt->width = imx708->mode->width; ++ fmt->height = imx708->mode->height; ++ fmt->field = V4L2_FIELD_NONE; ++} ++ ++static int imx708_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) ++{ ++ struct imx708 *imx708 = to_imx708(sd); ++ struct v4l2_mbus_framefmt *try_fmt_img = ++ v4l2_subdev_get_try_format(sd, fh->state, IMAGE_PAD); ++ struct v4l2_mbus_framefmt *try_fmt_meta = ++ v4l2_subdev_get_try_format(sd, fh->state, METADATA_PAD); ++ struct v4l2_rect *try_crop; ++ ++ mutex_lock(&imx708->mutex); ++ ++ /* Initialize try_fmt for the image pad */ ++ if (imx708->hdr_mode->val) { ++ try_fmt_img->width = supported_modes_10bit_hdr0.width; ++ try_fmt_img->height = supported_modes_10bit_hdr0.height; ++ } else { ++ try_fmt_img->width = supported_modes_10bit_no_hdr0.width; ++ try_fmt_img->height = supported_modes_10bit_no_hdr0.height; ++ } ++ try_fmt_img->code = imx708_get_format_code(imx708); ++ try_fmt_img->field = V4L2_FIELD_NONE; ++ ++ /* Initialize try_fmt for the embedded metadata pad */ ++ try_fmt_meta->width = IMX708_EMBEDDED_LINE_WIDTH; ++ try_fmt_meta->height = IMX708_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->state, IMAGE_PAD); ++ try_crop->left = IMX708_PIXEL_ARRAY_LEFT; ++ try_crop->top = IMX708_PIXEL_ARRAY_TOP; ++ try_crop->width = IMX708_PIXEL_ARRAY_WIDTH; ++ try_crop->height = IMX708_PIXEL_ARRAY_HEIGHT; ++ ++ mutex_unlock(&imx708->mutex); ++ ++ return 0; ++} ++ ++static int imx708_set_exposure(struct imx708 *imx708, unsigned int val) ++{ ++ val = max(val, imx708->mode->exposure_lines_min); ++ val -= val % imx708->mode->exposure_lines_step; ++ ++ /* ++ * In HDR mode this will set the longest exposure. The sensor ++ * will automatically divide the medium and short ones by 4,16. ++ */ ++ return imx708_write_reg(imx708, IMX708_REG_EXPOSURE, ++ IMX708_REG_VALUE_16BIT, ++ val >> imx708->long_exp_shift); ++} ++ ++static void imx708_adjust_exposure_range(struct imx708 *imx708, ++ struct v4l2_ctrl *ctrl) ++{ ++ int exposure_max, exposure_def; ++ ++ /* Honour the VBLANK limits when setting exposure. */ ++ exposure_max = imx708->mode->height + imx708->vblank->val - ++ IMX708_EXPOSURE_OFFSET; ++ exposure_def = min(exposure_max, imx708->exposure->val); ++ __v4l2_ctrl_modify_range(imx708->exposure, imx708->exposure->minimum, ++ exposure_max, imx708->exposure->step, ++ exposure_def); ++} ++ ++static int imx708_set_analogue_gain(struct imx708 *imx708, unsigned int val) ++{ ++ int ret; ++ ++ /* ++ * In HDR mode this will set the gain for the longest exposure, ++ * and by default the sensor uses the same gain for all of them. ++ */ ++ ret = imx708_write_reg(imx708, IMX708_REG_ANALOG_GAIN, ++ IMX708_REG_VALUE_16BIT, val); ++ ++ return ret; ++} ++ ++static int imx708_set_frame_length(struct imx708 *imx708, unsigned int val) ++{ ++ int ret; ++ ++ imx708->long_exp_shift = 0; ++ ++ while (val > IMX708_FRAME_LENGTH_MAX) { ++ imx708->long_exp_shift++; ++ val >>= 1; ++ } ++ ++ ret = imx708_write_reg(imx708, IMX708_REG_FRAME_LENGTH, ++ IMX708_REG_VALUE_16BIT, val); ++ if (ret) ++ return ret; ++ ++ return imx708_write_reg(imx708, IMX708_LONG_EXP_SHIFT_REG, ++ IMX708_REG_VALUE_08BIT, imx708->long_exp_shift); ++} ++ ++static void imx708_set_framing_limits(struct imx708 *imx708) ++{ ++ const struct imx708_mode *mode = imx708->mode; ++ unsigned int hblank; ++ ++ __v4l2_ctrl_modify_range(imx708->pixel_rate, ++ mode->pixel_rate, mode->pixel_rate, ++ 1, mode->pixel_rate); ++ ++ /* Update limits and set FPS to default */ ++ __v4l2_ctrl_modify_range(imx708->vblank, mode->vblank_min, ++ ((1 << IMX708_LONG_EXP_SHIFT_MAX) * ++ IMX708_FRAME_LENGTH_MAX) - mode->height, ++ 1, mode->vblank_default); ++ ++ /* ++ * 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(imx708->hblank, hblank, hblank, 1, hblank); ++} ++ ++static int imx708_set_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct imx708 *imx708 = ++ container_of(ctrl->handler, struct imx708, ctrl_handler); ++ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd); ++ const struct imx708_mode *mode_list; ++ unsigned int code, num_modes; ++ int ret = 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_VBLANK: ++ /* ++ * The VBLANK control may change the limits of usable exposure, ++ * so check and adjust if necessary. ++ */ ++ imx708_adjust_exposure_range(imx708, ctrl); ++ break; ++ ++ case V4L2_CID_WIDE_DYNAMIC_RANGE: ++ /* ++ * The WIDE_DYNAMIC_RANGE control can also be applied immediately ++ * as it doesn't set any registers. Don't do anything if the mode ++ * already matches. ++ */ ++ if (imx708->mode && imx708->mode->hdr != ctrl->val) { ++ code = imx708_get_format_code(imx708); ++ get_mode_table(code, &mode_list, &num_modes, ctrl->val); ++ imx708->mode = v4l2_find_nearest_size(mode_list, ++ num_modes, ++ width, height, ++ imx708->mode->width, ++ imx708->mode->height); ++ imx708_set_framing_limits(imx708); ++ } ++ break; ++ } ++ ++ /* ++ * 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: ++ imx708_set_analogue_gain(imx708, ctrl->val); ++ break; ++ case V4L2_CID_EXPOSURE: ++ ret = imx708_set_exposure(imx708, ctrl->val); ++ break; ++ case V4L2_CID_DIGITAL_GAIN: ++ ret = imx708_write_reg(imx708, IMX708_REG_DIGITAL_GAIN, ++ IMX708_REG_VALUE_16BIT, ctrl->val); ++ break; ++ case V4L2_CID_TEST_PATTERN: ++ ret = imx708_write_reg(imx708, IMX708_REG_TEST_PATTERN, ++ IMX708_REG_VALUE_16BIT, ++ imx708_test_pattern_valctrl->val); ++ break; ++ case V4L2_CID_TEST_PATTERN_RED: ++ ret = imx708_write_reg(imx708, IMX708_REG_TEST_PATTERN_R, ++ IMX708_REG_VALUE_16BIT, ctrl->val); ++ break; ++ case V4L2_CID_TEST_PATTERN_GREENR: ++ ret = imx708_write_reg(imx708, IMX708_REG_TEST_PATTERN_GR, ++ IMX708_REG_VALUE_16BIT, ctrl->val); ++ break; ++ case V4L2_CID_TEST_PATTERN_BLUE: ++ ret = imx708_write_reg(imx708, IMX708_REG_TEST_PATTERN_B, ++ IMX708_REG_VALUE_16BIT, ctrl->val); ++ break; ++ case V4L2_CID_TEST_PATTERN_GREENB: ++ ret = imx708_write_reg(imx708, IMX708_REG_TEST_PATTERN_GB, ++ IMX708_REG_VALUE_16BIT, ctrl->val); ++ break; ++ case V4L2_CID_HFLIP: ++ case V4L2_CID_VFLIP: ++ ret = imx708_write_reg(imx708, IMX708_REG_ORIENTATION, 1, ++ imx708->hflip->val | ++ imx708->vflip->val << 1); ++ break; ++ case V4L2_CID_VBLANK: ++ ret = imx708_set_frame_length(imx708, ++ imx708->mode->height + ctrl->val); ++ break; ++ case V4L2_CID_NOTIFY_GAINS: ++ ret = imx708_write_reg(imx708, IMX708_REG_COLOUR_BALANCE_BLUE, ++ IMX708_REG_VALUE_16BIT, ++ ctrl->p_new.p_u320); ++ if (ret) ++ break; ++ ret = imx708_write_reg(imx708, IMX708_REG_COLOUR_BALANCE_RED, ++ IMX708_REG_VALUE_16BIT, ++ ctrl->p_new.p_u323); ++ break; ++ case V4L2_CID_WIDE_DYNAMIC_RANGE: ++ /* Already handled above. */ ++ 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 imx708_ctrl_ops = { ++ .s_ctrl = imx708_set_ctrl, ++}; ++ ++static int imx708_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ struct imx708 *imx708 = to_imx708(sd); ++ ++ if (code->pad >= NUM_PADS) ++ return -EINVAL; ++ ++ if (code->pad == IMAGE_PAD) { ++ if (code->index >= (ARRAY_SIZE(codes) / 4)) ++ return -EINVAL; ++ ++ code->code = imx708_get_format_code(imx708); ++ } else { ++ if (code->index > 0) ++ return -EINVAL; ++ ++ code->code = MEDIA_BUS_FMT_SENSOR_DATA; ++ } ++ ++ return 0; ++} ++ ++static int imx708_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ struct imx708 *imx708 = to_imx708(sd); ++ ++ if (fse->pad >= NUM_PADS) ++ return -EINVAL; ++ ++ if (fse->pad == IMAGE_PAD) { ++ const struct imx708_mode *mode_list; ++ unsigned int num_modes; ++ ++ get_mode_table(fse->code, &mode_list, &num_modes, ++ imx708->hdr_mode->val); ++ ++ if (fse->index >= num_modes) ++ return -EINVAL; ++ ++ if (fse->code != imx708_get_format_code(imx708)) ++ return -EINVAL; ++ ++ fse->min_width = mode_listfse->index.width; ++ fse->max_width = fse->min_width; ++ fse->min_height = mode_listfse->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 = IMX708_EMBEDDED_LINE_WIDTH; ++ fse->max_width = fse->min_width; ++ fse->min_height = IMX708_NUM_EMBEDDED_LINES; ++ fse->max_height = fse->min_height; ++ } ++ ++ return 0; ++} ++ ++static void imx708_reset_colorspace(struct v4l2_mbus_framefmt *fmt) ++{ ++ fmt->colorspace = V4L2_COLORSPACE_RAW; ++ 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 imx708_update_image_pad_format(struct imx708 *imx708, ++ const struct imx708_mode *mode, ++ struct v4l2_subdev_format *fmt) ++{ ++ fmt->format.width = mode->width; ++ fmt->format.height = mode->height; ++ fmt->format.field = V4L2_FIELD_NONE; ++ imx708_reset_colorspace(&fmt->format); ++} ++ ++static void imx708_update_metadata_pad_format(struct v4l2_subdev_format *fmt) ++{ ++ fmt->format.width = IMX708_EMBEDDED_LINE_WIDTH; ++ fmt->format.height = IMX708_NUM_EMBEDDED_LINES; ++ fmt->format.code = MEDIA_BUS_FMT_SENSOR_DATA; ++ fmt->format.field = V4L2_FIELD_NONE; ++} ++ ++static int imx708_get_pad_format(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct imx708 *imx708 = to_imx708(sd); ++ ++ if (fmt->pad >= NUM_PADS) ++ return -EINVAL; ++ ++ mutex_lock(&imx708->mutex); ++ ++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { ++ struct v4l2_mbus_framefmt *try_fmt = ++ v4l2_subdev_get_try_format(&imx708->sd, sd_state, ++ fmt->pad); ++ /* update the code which could change due to vflip or hflip */ ++ try_fmt->code = fmt->pad == IMAGE_PAD ? ++ imx708_get_format_code(imx708) : ++ MEDIA_BUS_FMT_SENSOR_DATA; ++ fmt->format = *try_fmt; ++ } else { ++ if (fmt->pad == IMAGE_PAD) { ++ imx708_update_image_pad_format(imx708, imx708->mode, ++ fmt); ++ fmt->format.code = imx708_get_format_code(imx708); ++ } else { ++ imx708_update_metadata_pad_format(fmt); ++ } ++ } ++ ++ mutex_unlock(&imx708->mutex); ++ return 0; ++} ++ ++static int imx708_set_pad_format(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct v4l2_mbus_framefmt *framefmt; ++ const struct imx708_mode *mode; ++ struct imx708 *imx708 = to_imx708(sd); ++ ++ if (fmt->pad >= NUM_PADS) ++ return -EINVAL; ++ ++ mutex_lock(&imx708->mutex); ++ ++ if (fmt->pad == IMAGE_PAD) { ++ const struct imx708_mode *mode_list; ++ unsigned int num_modes; ++ ++ /* Bayer order varies with flips */ ++ fmt->format.code = imx708_get_format_code(imx708); ++ ++ get_mode_table(fmt->format.code, &mode_list, &num_modes, ++ imx708->hdr_mode->val); ++ ++ mode = v4l2_find_nearest_size(mode_list, ++ num_modes, ++ width, height, ++ fmt->format.width, ++ fmt->format.height); ++ imx708_update_image_pad_format(imx708, mode, fmt); ++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { ++ framefmt = v4l2_subdev_get_try_format(sd, sd_state, ++ fmt->pad); ++ *framefmt = fmt->format; ++ } else { ++ imx708->mode = mode; ++ imx708_set_framing_limits(imx708); ++ } ++ } else { ++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { ++ framefmt = v4l2_subdev_get_try_format(sd, sd_state, ++ fmt->pad); ++ *framefmt = fmt->format; ++ } else { ++ /* Only one embedded data mode is supported */ ++ imx708_update_metadata_pad_format(fmt); ++ } ++ } ++ ++ mutex_unlock(&imx708->mutex); ++ ++ return 0; ++} ++ ++static const struct v4l2_rect * ++__imx708_get_pad_crop(struct imx708 *imx708, struct v4l2_subdev_state *sd_state, ++ unsigned int pad, enum v4l2_subdev_format_whence which) ++{ ++ switch (which) { ++ case V4L2_SUBDEV_FORMAT_TRY: ++ return v4l2_subdev_get_try_crop(&imx708->sd, sd_state, pad); ++ case V4L2_SUBDEV_FORMAT_ACTIVE: ++ return &imx708->mode->crop; ++ } ++ ++ return NULL; ++} ++ ++static int imx708_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_selection *sel) ++{ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP: { ++ struct imx708 *imx708 = to_imx708(sd); ++ ++ mutex_lock(&imx708->mutex); ++ sel->r = *__imx708_get_pad_crop(imx708, sd_state, sel->pad, ++ sel->which); ++ mutex_unlock(&imx708->mutex); ++ ++ return 0; ++ } ++ ++ case V4L2_SEL_TGT_NATIVE_SIZE: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = IMX708_NATIVE_WIDTH; ++ sel->r.height = IMX708_NATIVE_HEIGHT; ++ ++ return 0; ++ ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = IMX708_PIXEL_ARRAY_LEFT; ++ sel->r.top = IMX708_PIXEL_ARRAY_TOP; ++ sel->r.width = IMX708_PIXEL_ARRAY_WIDTH; ++ sel->r.height = IMX708_PIXEL_ARRAY_HEIGHT; ++ ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++/* Start streaming */ ++static int imx708_start_streaming(struct imx708 *imx708) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd); ++ const struct imx708_reg_list *reg_list, *freq_regs; ++ int i, ret; ++ u32 val; ++ ++ if (!imx708->common_regs_written) { ++ ret = imx708_write_regs(imx708, mode_common_regs, ++ ARRAY_SIZE(mode_common_regs)); ++ if (ret) { ++ dev_err(&client->dev, "%s failed to set common settings\n", ++ __func__); ++ return ret; ++ } ++ ++ ret = imx708_read_reg(imx708, IMX708_REG_BASE_SPC_GAINS_L, ++ IMX708_REG_VALUE_08BIT, &val); ++ if (ret == 0 && val == 0x40) { ++ for (i = 0; i < 54 && ret == 0; i++) { ++ ret = imx708_write_reg(imx708, ++ IMX708_REG_BASE_SPC_GAINS_L + i, ++ IMX708_REG_VALUE_08BIT, ++ pdaf_gains0i % 9); ++ } ++ for (i = 0; i < 54 && ret == 0; i++) { ++ ret = imx708_write_reg(imx708, ++ IMX708_REG_BASE_SPC_GAINS_R + i, ++ IMX708_REG_VALUE_08BIT, ++ pdaf_gains1i % 9); ++ } ++ } ++ if (ret) { ++ dev_err(&client->dev, "%s failed to set PDAF gains\n", ++ __func__); ++ return ret; ++ } ++ ++ imx708->common_regs_written = true; ++ } ++ ++ /* Apply default values of current mode */ ++ reg_list = &imx708->mode->reg_list; ++ ret = imx708_write_regs(imx708, reg_list->regs, reg_list->num_of_regs); ++ if (ret) { ++ dev_err(&client->dev, "%s failed to set mode\n", __func__); ++ return ret; ++ } ++ ++ /* Update the link frequency registers */ ++ freq_regs = &link_freq_regsimx708->link_freq_idx; ++ ret = imx708_write_regs(imx708, freq_regs->regs, ++ freq_regs->num_of_regs); ++ if (ret) { ++ dev_err(&client->dev, "%s failed to set link frequency registers\n", ++ __func__); ++ return ret; ++ } ++ ++ /* Quad Bayer re-mosaic adjustments (for full-resolution mode only) */ ++ if (imx708->mode->remosaic && qbc_adjust > 0) { ++ imx708_write_reg(imx708, IMX708_LPF_INTENSITY, ++ IMX708_REG_VALUE_08BIT, qbc_adjust); ++ imx708_write_reg(imx708, ++ IMX708_LPF_INTENSITY_EN, ++ IMX708_REG_VALUE_08BIT, ++ IMX708_LPF_INTENSITY_ENABLED); ++ } else { ++ imx708_write_reg(imx708, ++ IMX708_LPF_INTENSITY_EN, ++ IMX708_REG_VALUE_08BIT, ++ IMX708_LPF_INTENSITY_DISABLED); ++ } ++ ++ /* Apply customized values from user */ ++ ret = __v4l2_ctrl_handler_setup(imx708->sd.ctrl_handler); ++ if (ret) ++ return ret; ++ ++ /* set stream on register */ ++ return imx708_write_reg(imx708, IMX708_REG_MODE_SELECT, ++ IMX708_REG_VALUE_08BIT, IMX708_MODE_STREAMING); ++} ++ ++/* Stop streaming */ ++static void imx708_stop_streaming(struct imx708 *imx708) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd); ++ int ret; ++ ++ /* set stream off register */ ++ ret = imx708_write_reg(imx708, IMX708_REG_MODE_SELECT, ++ IMX708_REG_VALUE_08BIT, IMX708_MODE_STANDBY); ++ if (ret) ++ dev_err(&client->dev, "%s failed to set stream\n", __func__); ++} ++ ++static int imx708_set_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct imx708 *imx708 = to_imx708(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret = 0; ++ ++ mutex_lock(&imx708->mutex); ++ if (imx708->streaming == enable) { ++ mutex_unlock(&imx708->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 = imx708_start_streaming(imx708); ++ if (ret) ++ goto err_rpm_put; ++ } else { ++ imx708_stop_streaming(imx708); ++ pm_runtime_put(&client->dev); ++ } ++ ++ imx708->streaming = enable; ++ ++ /* vflip/hflip and hdr mode cannot change during streaming */ ++ __v4l2_ctrl_grab(imx708->vflip, enable); ++ __v4l2_ctrl_grab(imx708->hflip, enable); ++ __v4l2_ctrl_grab(imx708->hdr_mode, enable); ++ ++ mutex_unlock(&imx708->mutex); ++ ++ return ret; ++ ++err_rpm_put: ++ pm_runtime_put(&client->dev); ++err_unlock: ++ mutex_unlock(&imx708->mutex); ++ ++ return ret; ++} ++ ++/* Power/clock management functions */ ++static int imx708_power_on(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct imx708 *imx708 = to_imx708(sd); ++ int ret; ++ ++ ret = regulator_bulk_enable(ARRAY_SIZE(imx708_supply_name), ++ imx708->supplies); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to enable regulators\n", ++ __func__); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(imx708->inclk); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to enable clock\n", ++ __func__); ++ goto reg_off; ++ } ++ ++ gpiod_set_value_cansleep(imx708->reset_gpio, 1); ++ usleep_range(IMX708_XCLR_MIN_DELAY_US, ++ IMX708_XCLR_MIN_DELAY_US + IMX708_XCLR_DELAY_RANGE_US); ++ ++ return 0; ++ ++reg_off: ++ regulator_bulk_disable(ARRAY_SIZE(imx708_supply_name), ++ imx708->supplies); ++ return ret; ++} ++ ++static int imx708_power_off(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct imx708 *imx708 = to_imx708(sd); ++ ++ gpiod_set_value_cansleep(imx708->reset_gpio, 0); ++ regulator_bulk_disable(ARRAY_SIZE(imx708_supply_name), ++ imx708->supplies); ++ clk_disable_unprepare(imx708->inclk); ++ ++ /* Force reprogramming of the common registers when powered up again. */ ++ imx708->common_regs_written = false; ++ ++ return 0; ++} ++ ++static int __maybe_unused imx708_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct imx708 *imx708 = to_imx708(sd); ++ ++ if (imx708->streaming) ++ imx708_stop_streaming(imx708); ++ ++ return 0; ++} ++ ++static int __maybe_unused imx708_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct imx708 *imx708 = to_imx708(sd); ++ int ret; ++ ++ if (imx708->streaming) { ++ ret = imx708_start_streaming(imx708); ++ if (ret) ++ goto error; ++ } ++ ++ return 0; ++ ++error: ++ imx708_stop_streaming(imx708); ++ imx708->streaming = 0; ++ return ret; ++} ++ ++static int imx708_get_regulators(struct imx708 *imx708) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd); ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(imx708_supply_name); i++) ++ imx708->suppliesi.supply = imx708_supply_namei; ++ ++ return devm_regulator_bulk_get(&client->dev, ++ ARRAY_SIZE(imx708_supply_name), ++ imx708->supplies); ++} ++ ++/* Verify chip ID */ ++static int imx708_identify_module(struct imx708 *imx708) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd); ++ int ret; ++ u32 val; ++ ++ ret = imx708_read_reg(imx708, IMX708_REG_CHIP_ID, ++ IMX708_REG_VALUE_16BIT, &val); ++ if (ret) { ++ dev_err(&client->dev, "failed to read chip id %x, with error %d\n", ++ IMX708_CHIP_ID, ret); ++ return ret; ++ } ++ ++ if (val != IMX708_CHIP_ID) { ++ dev_err(&client->dev, "chip id mismatch: %x!=%x\n", ++ IMX708_CHIP_ID, val); ++ return -EIO; ++ } ++ ++ ret = imx708_read_reg(imx708, 0x0000, IMX708_REG_VALUE_16BIT, &val); ++ if (!ret) { ++ dev_info(&client->dev, "camera module ID 0x%04x\n", val); ++ snprintf(imx708->sd.name, sizeof(imx708->sd.name), "imx708%s%s", ++ val & 0x02 ? "_wide" : "", ++ val & 0x80 ? "_noir" : ""); ++ } ++ ++ return 0; ++} ++ ++static const struct v4l2_subdev_core_ops imx708_core_ops = { ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++}; ++ ++static const struct v4l2_subdev_video_ops imx708_video_ops = { ++ .s_stream = imx708_set_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops imx708_pad_ops = { ++ .enum_mbus_code = imx708_enum_mbus_code, ++ .get_fmt = imx708_get_pad_format, ++ .set_fmt = imx708_set_pad_format, ++ .get_selection = imx708_get_selection, ++ .enum_frame_size = imx708_enum_frame_size, ++}; ++ ++static const struct v4l2_subdev_ops imx708_subdev_ops = { ++ .core = &imx708_core_ops, ++ .video = &imx708_video_ops, ++ .pad = &imx708_pad_ops, ++}; ++ ++static const struct v4l2_subdev_internal_ops imx708_internal_ops = { ++ .open = imx708_open, ++}; ++ ++static const struct v4l2_ctrl_config imx708_notify_gains_ctrl = { ++ .ops = &imx708_ctrl_ops, ++ .id = V4L2_CID_NOTIFY_GAINS, ++ .type = V4L2_CTRL_TYPE_U32, ++ .min = IMX708_COLOUR_BALANCE_MIN, ++ .max = IMX708_COLOUR_BALANCE_MAX, ++ .step = IMX708_COLOUR_BALANCE_STEP, ++ .def = IMX708_COLOUR_BALANCE_DEFAULT, ++ .dims = { 4 }, ++ .elem_size = sizeof(u32), ++}; ++ ++/* Initialize control handlers */ ++static int imx708_init_controls(struct imx708 *imx708) ++{ ++ struct v4l2_ctrl_handler *ctrl_hdlr; ++ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd); ++ struct v4l2_fwnode_device_properties props; ++ struct v4l2_ctrl *ctrl; ++ unsigned int i; ++ int ret; ++ ++ ctrl_hdlr = &imx708->ctrl_handler; ++ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 16); ++ if (ret) ++ return ret; ++ ++ mutex_init(&imx708->mutex); ++ ctrl_hdlr->lock = &imx708->mutex; ++ ++ /* By default, PIXEL_RATE is read only */ ++ imx708->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops, ++ V4L2_CID_PIXEL_RATE, ++ IMX708_INITIAL_PIXEL_RATE, ++ IMX708_INITIAL_PIXEL_RATE, 1, ++ IMX708_INITIAL_PIXEL_RATE); ++ ++ ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx708_ctrl_ops, ++ V4L2_CID_LINK_FREQ, 0, 0, ++ &link_freqsimx708->link_freq_idx); ++ if (ctrl) ++ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ ++ /* ++ * Create the controls here, but mode specific limits are setup ++ * in the imx708_set_framing_limits() call below. ++ */ ++ imx708->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops, ++ V4L2_CID_VBLANK, 0, 0xffff, 1, 0); ++ imx708->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops, ++ V4L2_CID_HBLANK, 0, 0xffff, 1, 0); ++ ++ imx708->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops, ++ V4L2_CID_EXPOSURE, ++ IMX708_EXPOSURE_MIN, ++ IMX708_EXPOSURE_MAX, ++ IMX708_EXPOSURE_STEP, ++ IMX708_EXPOSURE_DEFAULT); ++ ++ v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, ++ IMX708_ANA_GAIN_MIN, IMX708_ANA_GAIN_MAX, ++ IMX708_ANA_GAIN_STEP, IMX708_ANA_GAIN_DEFAULT); ++ ++ v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops, V4L2_CID_DIGITAL_GAIN, ++ IMX708_DGTL_GAIN_MIN, IMX708_DGTL_GAIN_MAX, ++ IMX708_DGTL_GAIN_STEP, IMX708_DGTL_GAIN_DEFAULT); ++ ++ imx708->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ ++ imx708->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_cluster(2, &imx708->hflip); ++ ++ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx708_ctrl_ops, ++ V4L2_CID_TEST_PATTERN, ++ ARRAY_SIZE(imx708_test_pattern_menu) - 1, ++ 0, 0, imx708_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, &imx708_ctrl_ops, ++ V4L2_CID_TEST_PATTERN_RED + i, ++ IMX708_TEST_PATTERN_COLOUR_MIN, ++ IMX708_TEST_PATTERN_COLOUR_MAX, ++ IMX708_TEST_PATTERN_COLOUR_STEP, ++ IMX708_TEST_PATTERN_COLOUR_MAX); ++ /* The "Solid color" pattern is white by default */ ++ } ++ ++ v4l2_ctrl_new_custom(ctrl_hdlr, &imx708_notify_gains_ctrl, NULL); ++ ++ imx708->hdr_mode = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops, ++ V4L2_CID_WIDE_DYNAMIC_RANGE, ++ 0, 1, 1, 0); ++ ++ ret = v4l2_fwnode_device_parse(&client->dev, &props); ++ if (ret) ++ goto error; ++ ++ v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx708_ctrl_ops, &props); ++ ++ if (ctrl_hdlr->error) { ++ ret = ctrl_hdlr->error; ++ dev_err(&client->dev, "%s control init failed (%d)\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ imx708->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ imx708->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ imx708->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ imx708->hdr_mode->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ imx708->sd.ctrl_handler = ctrl_hdlr; ++ ++ /* Setup exposure and frame/line length limits. */ ++ imx708_set_framing_limits(imx708); ++ ++ return 0; ++ ++error: ++ v4l2_ctrl_handler_free(ctrl_hdlr); ++ mutex_destroy(&imx708->mutex); ++ ++ return ret; ++} ++ ++static void imx708_free_controls(struct imx708 *imx708) ++{ ++ v4l2_ctrl_handler_free(imx708->sd.ctrl_handler); ++ mutex_destroy(&imx708->mutex); ++} ++ ++static int imx708_check_hwcfg(struct device *dev, struct imx708 *imx708) ++{ ++ struct fwnode_handle *endpoint; ++ struct v4l2_fwnode_endpoint ep_cfg = { ++ .bus_type = V4L2_MBUS_CSI2_DPHY ++ }; ++ int ret = -EINVAL; ++ int i; ++ ++ 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; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(link_freqs); i++) { ++ if (link_freqsi == ep_cfg.link_frequencies0) { ++ imx708->link_freq_idx = i; ++ break; ++ } ++ } ++ ++ if (i == ARRAY_SIZE(link_freqs)) { ++ dev_err(dev, "Link frequency not supported: %lld\n", ++ ep_cfg.link_frequencies0); ++ ret = -EINVAL; ++ goto error_out; ++ } ++ ++ ret = 0; ++ ++error_out: ++ v4l2_fwnode_endpoint_free(&ep_cfg); ++ fwnode_handle_put(endpoint); ++ ++ return ret; ++} ++ ++static int imx708_probe(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ struct imx708 *imx708; ++ int ret; ++ ++ imx708 = devm_kzalloc(&client->dev, sizeof(*imx708), GFP_KERNEL); ++ if (!imx708) ++ return -ENOMEM; ++ ++ v4l2_i2c_subdev_init(&imx708->sd, client, &imx708_subdev_ops); ++ ++ /* Check the hardware configuration in device tree */ ++ if (imx708_check_hwcfg(dev, imx708)) ++ return -EINVAL; ++ ++ /* Get system clock (inclk) */ ++ imx708->inclk = devm_clk_get(dev, "inclk"); ++ if (IS_ERR(imx708->inclk)) ++ return dev_err_probe(dev, PTR_ERR(imx708->inclk), ++ "failed to get inclk\n"); ++ ++ imx708->inclk_freq = clk_get_rate(imx708->inclk); ++ if (imx708->inclk_freq != IMX708_INCLK_FREQ) ++ return dev_err_probe(dev, -EINVAL, ++ "inclk frequency not supported: %d Hz\n", ++ imx708->inclk_freq); ++ ++ ret = imx708_get_regulators(imx708); ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to get regulators\n"); ++ ++ /* Request optional enable pin */ ++ imx708->reset_gpio = devm_gpiod_get_optional(dev, "reset", ++ GPIOD_OUT_HIGH); ++ ++ /* ++ * The sensor must be powered for imx708_identify_module() ++ * to be able to read the CHIP_ID register ++ */ ++ ret = imx708_power_on(dev); ++ if (ret) ++ return ret; ++ ++ ret = imx708_identify_module(imx708); ++ if (ret) ++ goto error_power_off; ++ ++ /* Initialize default format */ ++ imx708_set_default_format(imx708); ++ ++ /* 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 = imx708_init_controls(imx708); ++ if (ret) ++ goto error_pm_runtime; ++ ++ /* Initialize subdev */ ++ imx708->sd.internal_ops = &imx708_internal_ops; ++ imx708->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | ++ V4L2_SUBDEV_FL_HAS_EVENTS; ++ imx708->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ++ /* Initialize source pads */ ++ imx708->padIMAGE_PAD.flags = MEDIA_PAD_FL_SOURCE; ++ imx708->padMETADATA_PAD.flags = MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&imx708->sd.entity, NUM_PADS, imx708->pad); ++ if (ret) { ++ dev_err(dev, "failed to init entity pads: %d\n", ret); ++ goto error_handler_free; ++ } ++ ++ ret = v4l2_async_register_subdev_sensor(&imx708->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(&imx708->sd.entity); ++ ++error_handler_free: ++ imx708_free_controls(imx708); ++ ++error_pm_runtime: ++ pm_runtime_disable(&client->dev); ++ pm_runtime_set_suspended(&client->dev); ++ ++error_power_off: ++ imx708_power_off(&client->dev); ++ ++ return ret; ++} ++ ++static void imx708_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct imx708 *imx708 = to_imx708(sd); ++ ++ v4l2_async_unregister_subdev(sd); ++ media_entity_cleanup(&sd->entity); ++ imx708_free_controls(imx708); ++ ++ pm_runtime_disable(&client->dev); ++ if (!pm_runtime_status_suspended(&client->dev)) ++ imx708_power_off(&client->dev); ++ pm_runtime_set_suspended(&client->dev); ++} ++ ++static const struct of_device_id imx708_dt_ids = { ++ { .compatible = "sony,imx708" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, imx708_dt_ids); ++ ++static const struct dev_pm_ops imx708_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(imx708_suspend, imx708_resume) ++ SET_RUNTIME_PM_OPS(imx708_power_off, imx708_power_on, NULL) ++}; ++ ++static struct i2c_driver imx708_i2c_driver = { ++ .driver = { ++ .name = "imx708", ++ .of_match_table = imx708_dt_ids, ++ .pm = &imx708_pm_ops, ++ }, ++ .probe = imx708_probe, ++ .remove = imx708_remove, ++}; ++ ++module_i2c_driver(imx708_i2c_driver); ++ ++MODULE_AUTHOR("David Plowman <david.plowman@raspberrypi.com>"); ++MODULE_DESCRIPTION("Sony IMX708 sensor driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/irs1125.c b/drivers/media/i2c/irs1125.c new file mode 100644 -index 000000000000..30c3d2640386 +index 000000000000..eac03e13aeb5 --- /dev/null +++ b/drivers/media/i2c/irs1125.c -@@ -0,0 +1,1200 @@ +@@ -0,0 +1,1197 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * A V4L2 driver for Infineon IRS1125 TOF cameras. @@ -77366,8 +117093,8 @@ +}; + +static int irs1125_enum_mbus_code(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_mbus_code_enum *code) ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; @@ -77378,7 +117105,7 @@ +} + +static int irs1125_set_get_fmt(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; @@ -77734,7 +117461,7 @@ +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); ++ v4l2_subdev_get_try_format(sd, fh->state, 0); + + format->code = MEDIA_BUS_FMT_Y12_1X12; + format->width = IRS1125_WINDOW_WIDTH_DEF; @@ -77865,8 +117592,7 @@ + return 0; +} + -+static int irs1125_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) ++static int irs1125_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct irs1125 *sensor; @@ -77965,7 +117691,7 @@ + return ret; +} + -+static int irs1125_remove(struct i2c_client *client) ++static void irs1125_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct irs1125 *irs1125 = to_state(sd); @@ -77975,8 +117701,6 @@ + v4l2_device_unregister_subdev(sd); + mutex_destroy(&irs1125->lock); + v4l2_ctrl_handler_free(&irs1125->ctrl_handler); -+ -+ return 0; +} + +#if IS_ENABLED(CONFIG_OF) @@ -78103,981 +117827,630 @@ + +#endif /* IRS1125 */ + -diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c -index e7d2e5b4ad4b..3b7a15852c5d 100644 ---- a/drivers/media/i2c/ov5647.c -+++ b/drivers/media/i2c/ov5647.c -@@ -21,21 +21,34 @@ - - #include <linux/clk.h> - #include <linux/delay.h> +diff --git a/drivers/media/i2c/ov2311.c b/drivers/media/i2c/ov2311.c +new file mode 100644 +index 000000000000..fa5bb797d3d6 +--- /dev/null ++++ b/drivers/media/i2c/ov2311.c +@@ -0,0 +1,1178 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Omnivision OV2311 1600x1300 global shutter image sensor driver ++ * Copyright (C) 2022, Raspberry Pi (Trading) Ltd ++ * ++ * This driver is based on the OV9281 driver. ++ * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. ++ * Register configuration from ++ * https://github.com/ArduCAM/ArduCAM_USB_Camera_Shield/tree/master/Config/USB3.0_UC-425_Rev.C%2BUC-628_Rev.B/OV2311 ++ * with additional exposure and gain register information from ++ * https://github.com/renesas-rcar/linux-bsp/tree/0cf6e36f5bf49e1c2aab87139ec5b588623c56f8/drivers/media/i2c/imagers ++ */ ++ ++#include <linux/clk.h> ++#include <linux/device.h> ++#include <linux/delay.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/i2c.h> ++#include <linux/module.h> ++#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> - #include <linux/slab.h> - #include <linux/videodev2.h> ++#include <media/media-entity.h> ++#include <media/v4l2-async.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> - ++#include <media/v4l2-fwnode.h> ++#include <media/v4l2-subdev.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) - -@@ -44,48 +57,89 @@ - #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_VFLIP 0x3820 -+#define OV5647_REG_HFLIP 0x3821 - #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 -+/* OV5647 native and active pixel array size */ -+#define OV5647_NATIVE_WIDTH 2624U -+#define OV5647_NATIVE_HEIGHT 1956U - --#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_PIXEL_ARRAY_LEFT 16U -+#define OV5647_PIXEL_ARRAY_TOP 6U -+#define OV5647_PIXEL_ARRAY_WIDTH 2592U -+#define OV5647_PIXEL_ARRAY_HEIGHT 1944U - --#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_VBLANK_MIN 24 -+#define OV5647_VTS_MAX 32767 - --#define OV5647_WINDOW_WIDTH 0x04 --#define OV5647_WINDOW_WIDTH_MIN 2 --#define OV5647_WINDOW_WIDTH_MAX 2752 --#define OV5647_WINDOW_WIDTH_DEF 2592 -+#define OV5647_EXPOSURE_MIN 4 -+#define OV5647_EXPOSURE_STEP 1 -+#define OV5647_EXPOSURE_DEFAULT 1000 -+#define OV5647_EXPOSURE_MAX 65535 ++#define OV2311_LINK_FREQ 400000000 ++#define OV2311_LANES 2 + -+/* regulator supplies */ -+static const char * const ov5647_supply_names = { ++/* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */ ++#define OV2311_PIXEL_RATE_10BIT (OV2311_LINK_FREQ * 2 * \ ++ OV2311_LANES / 10) ++#define OV2311_PIXEL_RATE_8BIT (OV2311_LINK_FREQ * 2 * \ ++ OV2311_LANES / 8) ++#define OV2311_XVCLK_FREQ 24000000 ++ ++#define CHIP_ID 0x2311 ++#define OV2311_REG_CHIP_ID 0x300a ++ ++#define OV2311_REG_CTRL_MODE 0x0100 ++#define OV2311_MODE_SW_STANDBY 0x0 ++#define OV2311_MODE_STREAMING BIT(0) ++ ++#define OV2311_REG_V_FLIP 0x3820 ++#define OV2311_REG_H_FLIP 0x3821 ++#define OV2311_FLIP_BIT BIT(2) ++ ++#define OV2311_REG_EXPOSURE 0x3501 ++#define OV2311_EXPOSURE_MIN 4 ++#define OV2311_EXPOSURE_STEP 1 ++#define OV2311_VTS_MAX 0xffff ++ ++#define OV2311_REG_GAIN_H 0x3508 ++#define OV2311_REG_GAIN_L 0x3509 ++#define OV2311_GAIN_H_MASK 0x07 ++#define OV2311_GAIN_H_SHIFT 8 ++#define OV2311_GAIN_L_MASK 0xff ++#define OV2311_GAIN_MIN 0x100 ++#define OV2311_GAIN_MAX 0x780 ++#define OV2311_GAIN_STEP 1 ++#define OV2311_GAIN_DEFAULT OV2311_GAIN_MIN ++ ++#define OV2311_REG_TEST_PATTERN 0x5e00 ++#define OV2311_TEST_PATTERN_ENABLE 0x80 ++#define OV2311_TEST_PATTERN_DISABLE 0x0 ++ ++#define OV2311_REG_VTS 0x380e ++ ++/* ++ * OV2311 native and active pixel array size. ++ * Datasheet not available to confirm these values. renesas-rcar linux-bsp tree ++ * has these values. ++ */ ++#define OV2311_NATIVE_WIDTH 1616U ++#define OV2311_NATIVE_HEIGHT 1316U ++#define OV2311_PIXEL_ARRAY_LEFT 8U ++#define OV2311_PIXEL_ARRAY_TOP 8U ++#define OV2311_PIXEL_ARRAY_WIDTH 1600U ++#define OV2311_PIXEL_ARRAY_HEIGHT 1300U ++ ++#define REG_NULL 0xFFFF ++ ++#define OV2311_REG_VALUE_08BIT 1 ++#define OV2311_REG_VALUE_16BIT 2 ++#define OV2311_REG_VALUE_24BIT 3 ++ ++#define OV2311_NAME "ov2311" ++ ++static const char * const ov2311_supply_names = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital core power */ +}; + -+#define OV5647_NUM_SUPPLIES ARRAY_SIZE(ov5647_supply_names) - - struct regval_list { - u16 addr; - u8 data; - }; - -+struct ov5647_mode { -+ struct v4l2_mbus_framefmt format; -+ /* Analog crop rectangle. */ ++#define OV2311_NUM_SUPPLIES ARRAY_SIZE(ov2311_supply_names) ++ ++struct regval { ++ u16 addr; ++ u8 val; ++}; ++ ++struct ov2311_mode { ++ u32 width; ++ u32 height; ++ u32 hts_def; ++ u32 vts_def; ++ u32 exp_def; + struct v4l2_rect crop; ++ const struct regval *reg_list; ++}; + -+ 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 ov2311 { ++ struct i2c_client *client; ++ struct clk *xvclk; ++ struct gpio_desc *reset_gpio; ++ struct gpio_desc *pwdn_gpio; ++ struct regulator_bulk_data suppliesOV2311_NUM_SUPPLIES; ++ ++ struct v4l2_subdev subdev; ++ struct media_pad pad; ++ struct v4l2_ctrl_handler ctrl_handler; ++ struct v4l2_ctrl *exposure; ++ struct v4l2_ctrl *hblank; ++ struct v4l2_ctrl *vblank; ++ struct v4l2_ctrl *pixel_rate; ++ /* ++ * Mutex for serialized access: ++ * Protect sensor module set pad format and start/stop streaming safely. ++ */ ++ struct mutex mutex; ++ ++ /* Streaming on/off */ ++ bool streaming; ++ ++ const struct ov2311_mode *cur_mode; ++ u32 code; +}; + - 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; -+ struct regulator_bulk_data suppliesOV5647_NUM_SUPPLIES; -+ 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; -+ struct v4l2_ctrl *hflip; -+ struct v4l2_ctrl *vflip; -+ bool write_mode_regs; - }; - - static inline struct ov5647 *to_state(struct v4l2_subdev *sd) -@@ -105,7 +159,7 @@ static struct regval_list sensor_oe_enable_regs = { - {0x3002, 0xe4}, - }; - --static struct regval_list ov5647_640x480 = { -+static struct regval_list ov5647_640x480_8bit = { - {0x0100, 0x00}, - {0x0103, 0x01}, - {0x3034, 0x08}, -@@ -113,14 +167,13 @@ static struct regval_list ov5647_640x480 = { - {0x3036, 0x46}, - {0x303c, 0x11}, - {0x3106, 0xf5}, -- {0x3821, 0x07}, -+ {0x3821, 0x01}, - {0x3820, 0x41}, - {0x3827, 0xec}, - {0x370c, 0x0f}, - {0x3612, 0x59}, - {0x3618, 0x00}, - {0x5000, 0x06}, -- {0x5001, 0x01}, - {0x5002, 0x41}, - {0x5003, 0x08}, - {0x5a00, 0x08}, -@@ -138,8 +191,6 @@ static struct regval_list ov5647_640x480 = { - {0x3b07, 0x0c}, - {0x380c, 0x07}, - {0x380d, 0x68}, -- {0x380e, 0x03}, -- {0x380f, 0xd8}, - {0x3814, 0x31}, - {0x3815, 0x31}, - {0x3708, 0x64}, -@@ -196,6 +247,517 @@ static struct regval_list ov5647_640x480 = { - {0x0100, 0x01}, - }; - -+static struct regval_list ov5647_2592x1944_10bit = { -+ {0x0100, 0x00}, -+ {0x0103, 0x01}, -+ {0x3034, 0x1a}, -+ {0x3035, 0x21}, -+ {0x3036, 0x69}, -+ {0x303c, 0x11}, -+ {0x3106, 0xf5}, -+ {0x3821, 0x00}, -+ {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}, ++#define to_ov2311(sd) container_of(sd, struct ov2311, subdev) ++ ++/* ++ * Xclk 24Mhz ++ * max_framerate 60fps for 10 bit, 74.6fps for 8 bit. ++ */ ++static const struct regval ov2311_common_regs = { ++ { 0x0103, 0x01 }, ++ { 0x0100, 0x00 }, ++ { 0x0300, 0x01 }, ++ { 0x0302, 0x32 }, ++ { 0x0303, 0x00 }, ++ { 0x0304, 0x03 }, ++ { 0x0305, 0x02 }, ++ { 0x0306, 0x01 }, ++ { 0x030e, 0x04 }, ++ { 0x3001, 0x02 }, ++ { 0x3004, 0x00 }, ++ { 0x3005, 0x00 }, ++ { 0x3006, 0x00 }, ++ { 0x3011, 0x0d }, ++ { 0x3014, 0x04 }, ++ { 0x301c, 0xf0 }, ++ { 0x3020, 0x00 }, ++ { 0x302c, 0x00 }, ++ { 0x302d, 0x12 }, ++ { 0x302e, 0x4c }, ++ { 0x302f, 0x8c }, ++ { 0x3030, 0x10 }, ++ { 0x303f, 0x03 }, ++ { 0x3103, 0x00 }, ++ { 0x3106, 0x08 }, ++ { 0x31ff, 0x01 }, ++ { 0x3501, 0x05 }, ++ { 0x3502, 0xba }, ++ { 0x3506, 0x00 }, ++ { 0x3507, 0x00 }, ++ { 0x3620, 0x67 }, ++ { 0x3633, 0x78 }, ++ { 0x3666, 0x00 }, ++ { 0x3670, 0x68 }, ++ { 0x3674, 0x10 }, ++ { 0x3675, 0x00 }, ++ { 0x3680, 0x84 }, ++ { 0x36a2, 0x04 }, ++ { 0x36a3, 0x80 }, ++ { 0x36b0, 0x00 }, ++ { 0x3700, 0x35 }, ++ { 0x3704, 0x59 }, ++ { 0x3712, 0x00 }, ++ { 0x3713, 0x02 }, ++ { 0x379b, 0x01 }, ++ { 0x379c, 0x10 }, ++ { 0x3800, 0x00 }, ++ { 0x3801, 0x00 }, ++ { 0x3804, 0x06 }, ++ { 0x3805, 0x4f }, ++ { 0x3810, 0x00 }, ++ { 0x3811, 0x08 }, ++ { 0x3812, 0x00 }, ++ { 0x3813, 0x08 }, ++ { 0x3814, 0x11 }, ++ { 0x3815, 0x11 }, ++ { 0x3816, 0x00 }, ++ { 0x3817, 0x00 }, ++ { 0x3818, 0x04 }, ++ { 0x3819, 0x00 }, ++ { 0x382b, 0x5a }, ++ { 0x382c, 0x09 }, ++ { 0x382d, 0x9a }, ++ { 0x3882, 0x02 }, ++ { 0x3883, 0x6c }, ++ { 0x3885, 0x07 }, ++ { 0x389d, 0x03 }, ++ { 0x38a6, 0x00 }, ++ { 0x38a7, 0x01 }, ++ { 0x38b3, 0x07 }, ++ { 0x38b1, 0x00 }, ++ { 0x38e5, 0x02 }, ++ { 0x38e7, 0x00 }, ++ { 0x38e8, 0x00 }, ++ { 0x3910, 0xff }, ++ { 0x3911, 0xff }, ++ { 0x3912, 0x08 }, ++ { 0x3913, 0x00 }, ++ { 0x3914, 0x00 }, ++ { 0x3915, 0x00 }, ++ { 0x391c, 0x00 }, ++ { 0x3920, 0xa5 }, ++ { 0x3921, 0x00 }, ++ { 0x3922, 0x00 }, ++ { 0x3923, 0x00 }, ++ { 0x3924, 0x05 }, ++ { 0x3925, 0x00 }, ++ { 0x3926, 0x00 }, ++ { 0x3927, 0x00 }, ++ { 0x3928, 0x1a }, ++ { 0x392d, 0x05 }, ++ { 0x392e, 0xf2 }, ++ { 0x392f, 0x40 }, ++ { 0x4001, 0x00 }, ++ { 0x4003, 0x40 }, ++ { 0x4008, 0x12 }, ++ { 0x4009, 0x1b }, ++ { 0x400c, 0x0c }, ++ { 0x400d, 0x13 }, ++ { 0x4010, 0xf0 }, ++ { 0x4011, 0x00 }, ++ { 0x4016, 0x00 }, ++ { 0x4017, 0x04 }, ++ { 0x4042, 0x11 }, ++ { 0x4043, 0x70 }, ++ { 0x4045, 0x00 }, ++ { 0x4409, 0x5f }, ++ { 0x450b, 0x00 }, ++ { 0x4600, 0x00 }, ++ { 0x4601, 0xa0 }, ++ { 0x4708, 0x09 }, ++ { 0x470c, 0x81 }, ++ { 0x4710, 0x06 }, ++ { 0x4711, 0x00 }, ++ { 0x4800, 0x00 }, ++ { 0x481f, 0x30 }, ++ { 0x4837, 0x14 }, ++ { 0x4f00, 0x00 }, ++ { 0x4f07, 0x00 }, ++ { 0x4f08, 0x03 }, ++ { 0x4f09, 0x08 }, ++ { 0x4f0c, 0x06 }, ++ { 0x4f0d, 0x02 }, ++ { 0x4f10, 0x00 }, ++ { 0x4f11, 0x00 }, ++ { 0x4f12, 0x07 }, ++ { 0x4f13, 0xe2 }, ++ { 0x5000, 0x9f }, ++ { 0x5001, 0x20 }, ++ { 0x5026, 0x00 }, ++ { 0x5c00, 0x00 }, ++ { 0x5c01, 0x2c }, ++ { 0x5c02, 0x00 }, ++ { 0x5c03, 0x7f }, ++ { 0x5e00, 0x00 }, ++ { 0x5e01, 0x41 }, ++ {REG_NULL, 0x00}, +}; + -+static struct regval_list ov5647_1080p30_10bit = { -+ {0x0100, 0x00}, -+ {0x0103, 0x01}, -+ {0x3034, 0x1a}, -+ {0x3035, 0x21}, -+ {0x3036, 0x62}, -+ {0x303c, 0x11}, -+ {0x3106, 0xf5}, -+ {0x3821, 0x00}, -+ {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 const struct regval ov2311_1600x1300_regs = { ++ { 0x3802, 0x00 }, ++ { 0x3803, 0x00 }, ++ { 0x3806, 0x05 }, ++ { 0x3807, 0x23 }, ++ { 0x3808, 0x06 }, ++ { 0x3809, 0x40 }, ++ { 0x380a, 0x05 }, ++ { 0x380b, 0x14 }, ++ { 0x380c, 0x03 }, ++ { 0x380d, 0x88 }, ++ {REG_NULL, 0x00}, +}; + -+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, 0x01}, -+ {0x350A, 0x00}, -+ {0x350B, 0x10}, -+ {0x3500, 0x00}, -+ {0x3501, 0x1A}, -+ {0x3502, 0xF0}, -+ {0x3212, 0xA0}, -+ {0x0100, 0x01}, ++static const struct regval ov2311_1600x1080_regs = { ++ { 0x3802, 0x00 }, ++ { 0x3803, 0x6e }, ++ { 0x3806, 0x04 }, ++ { 0x3807, 0xae }, ++ { 0x3808, 0x06 }, ++ { 0x3809, 0x40 }, ++ { 0x380a, 0x04 }, ++ { 0x380b, 0x38 }, ++ { 0x380c, 0x03 }, ++ { 0x380d, 0x88 }, ++ ++ { 0x5d01, 0x00 }, ++ { 0x5d02, 0x04 }, ++ { 0x5d03, 0x00 }, ++ { 0x5d04, 0x04 }, ++ { 0x5d05, 0x00 }, ++ {REG_NULL, 0x00}, +}; + -+static struct regval_list ov5647_640x480_10bit = { -+ {0x0100, 0x00}, -+ {0x0103, 0x01}, -+ {0x3035, 0x11}, -+ {0x3036, 0x46}, -+ {0x303c, 0x11}, -+ {0x3821, 0x01}, -+ {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_RAW, -+ .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 const struct regval op_10bit = { ++ { 0x030d, 0x5a }, ++ { 0x3662, 0x65 }, ++ {REG_NULL, 0x00}, +}; + -+static struct ov5647_mode supported_modes_10bit = { -+ /* -+ * MODE 0: 2592x1944 full resolution full FOV 10-bit mode. -+ */ ++static const struct regval op_8bit = { ++ { 0x030d, 0x70 }, ++ { 0x3662, 0x67 }, ++ {REG_NULL, 0x00}, ++}; ++ ++static const struct ov2311_mode supported_modes = { + { -+ .format = { -+ .code = MEDIA_BUS_FMT_SBGGR10_1X10, -+ .colorspace = V4L2_COLORSPACE_RAW, -+ .field = V4L2_FIELD_NONE, -+ .width = 2592, -+ .height = 1944 -+ }, ++ .width = 1600, ++ .height = 1300, ++ .exp_def = 0x0320, ++ .hts_def = (0x0388 * 2),/* Registers 0x380c / 0x380d * 2 */ ++ .vts_def = 0x5c2, /* Registers 0x380e / 0x380f ++ * 60fps for 10bpp ++ */ + .crop = { -+ .left = OV5647_PIXEL_ARRAY_LEFT, -+ .top = OV5647_PIXEL_ARRAY_TOP, -+ .width = 2592, -+ .height = 1944 ++ .left = OV2311_PIXEL_ARRAY_LEFT, ++ .top = OV2311_PIXEL_ARRAY_TOP, ++ .width = 1600, ++ .height = 1300 + }, -+ .pixel_rate = 87500000, -+ .hts = 2844, -+ .vts_def = 0x7b0, -+ .reg_list = ov5647_2592x1944_10bit, -+ .num_regs = ARRAY_SIZE(ov5647_2592x1944_10bit) ++ .reg_list = ov2311_1600x1300_regs, + }, -+ /* -+ * MODE 1: 1080p30 10-bit mode. -+ * Full resolution centre-cropped down to 1080p. -+ */ + { -+ .format = { -+ .code = MEDIA_BUS_FMT_SBGGR10_1X10, -+ .colorspace = V4L2_COLORSPACE_RAW, -+ .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_RAW, -+ .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_RAW, -+ .field = V4L2_FIELD_NONE, -+ .width = 640, -+ .height = 480 -+ }, ++ .width = 1600, ++ .height = 1080, ++ .exp_def = 0x0320, ++ .hts_def = (0x0388 * 2),/* Registers 0x380c / 0x380d * 2 */ ++ .vts_def = 0x5c2, /* Registers 0x380e / 0x380f ++ * 60fps for 10bpp ++ */ + .crop = { -+ .left = OV5647_PIXEL_ARRAY_LEFT, -+ .top = OV5647_PIXEL_ARRAY_TOP, -+ .width = 2560, -+ .height = 1920, ++ .left = OV2311_PIXEL_ARRAY_LEFT, ++ .top = 110 + OV2311_PIXEL_ARRAY_TOP, ++ .width = 1600, ++ .height = 1080 + }, -+ .pixel_rate = 55000000, -+ .hts = 1852, -+ .vts_def = 0x1f8, -+ .reg_list = ov5647_640x480_10bit, -+ .num_regs = ARRAY_SIZE(ov5647_640x480_10bit) ++ .reg_list = ov2311_1600x1080_regs, + }, +}; + -+/* Use 2x2 binned 10-bit mode as default. */ -+#define OV5647_DEFAULT_MODE (&supported_modes_10bit2) ++static const s64 link_freq_menu_items = { ++ OV2311_LINK_FREQ ++}; ++ ++static const char * const ov2311_test_pattern_menu = { ++ "Disabled", ++ "Vertical Color Bar Type 1", ++ "Vertical Color Bar Type 2", ++ "Vertical Color Bar Type 3", ++ "Vertical Color Bar Type 4" ++}; + -+static int ov5647_write16(struct v4l2_subdev *sd, u16 reg, u16 val) ++/* Write registers up to 4 at a time */ ++static int ov2311_write_reg(struct i2c_client *client, u16 reg, ++ u32 len, u32 val) +{ -+ int ret; -+ unsigned char data4 = { reg >> 8, reg & 0xff, val >> 8, val & 0xff}; -+ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 buf_i, val_i; ++ u8 buf6; ++ u8 *val_p; ++ __be32 val_be; + -+ 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; -+ } ++ if (len > 4) ++ return -EINVAL; ++ ++ buf0 = reg >> 8; ++ buf1 = reg & 0xff; ++ ++ val_be = cpu_to_be32(val); ++ val_p = (u8 *)&val_be; ++ buf_i = 2; ++ val_i = 4 - len; ++ ++ while (val_i < 4) ++ bufbuf_i++ = val_pval_i++; ++ ++ if (i2c_master_send(client, buf, len + 2) != len + 2) ++ return -EIO; ++ ++ return 0; ++} ++ ++static int ov2311_write_array(struct i2c_client *client, ++ const struct regval *regs) ++{ ++ u32 i; ++ int ret = 0; ++ ++ for (i = 0; ret == 0 && regsi.addr != REG_NULL; i++) ++ ret = ov2311_write_reg(client, regsi.addr, ++ OV2311_REG_VALUE_08BIT, regsi.val); + + return ret; +} + - static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val) - { - int ret; -@@ -203,9 +765,18 @@ static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val) - 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; - } -@@ -217,16 +788,31 @@ static int ov5647_read(struct v4l2_subdev *sd, u16 reg, u8 *val) - 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; - } -@@ -258,11 +844,68 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel) - return ov5647_write(sd, OV5647_REG_MIPI_CTRL14, channel_id | (channel << 6)); - } - -+static int __sensor_init(struct v4l2_subdev *sd) ++/* Read registers up to 4 at a time */ ++static int ov2311_read_reg(struct i2c_client *client, u16 reg, unsigned int len, ++ u32 *val) +{ ++ struct i2c_msg msgs2; ++ u8 *data_be_p; ++ __be32 data_be = 0; ++ __be16 reg_addr_be = cpu_to_be16(reg); + 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 (len > 4 || !len) ++ return -EINVAL; + -+ 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; ++ data_be_p = (u8 *)&data_be; ++ /* Write register address */ ++ msgs0.addr = client->addr; ++ msgs0.flags = 0; ++ msgs0.len = 2; ++ msgs0.buf = (u8 *)®_addr_be; ++ ++ /* Read data from register */ ++ msgs1.addr = client->addr; ++ msgs1.flags = I2C_M_RD; ++ msgs1.len = len; ++ msgs1.buf = &data_be_p4 - 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 ov2311_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct ov2311 *ov2311 = to_ov2311(sd); ++ const struct ov2311_mode *mode; ++ s64 h_blank, vblank_def, pixel_rate; ++ ++ mutex_lock(&ov2311->mutex); ++ ++ mode = v4l2_find_nearest_size(supported_modes, ++ ARRAY_SIZE(supported_modes), ++ width, height, ++ fmt->format.width, ++ fmt->format.height); ++ 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_RAW; ++ 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, sd_state, fmt->pad) = ++ fmt->format; ++ } else { ++ ov2311->cur_mode = mode; ++ ov2311->code = fmt->format.code; ++ h_blank = mode->hts_def - mode->width; ++ __v4l2_ctrl_modify_range(ov2311->hblank, h_blank, ++ h_blank, 1, h_blank); ++ __v4l2_ctrl_s_ctrl(ov2311->hblank, h_blank); ++ vblank_def = mode->vts_def - mode->height; ++ __v4l2_ctrl_modify_range(ov2311->vblank, vblank_def, ++ OV2311_VTS_MAX - mode->height, ++ 1, vblank_def); ++ __v4l2_ctrl_s_ctrl(ov2311->vblank, vblank_def); ++ ++ pixel_rate = (fmt->format.code == MEDIA_BUS_FMT_Y10_1X10) ? ++ OV2311_PIXEL_RATE_10BIT : OV2311_PIXEL_RATE_8BIT; ++ __v4l2_ctrl_modify_range(ov2311->pixel_rate, pixel_rate, ++ pixel_rate, 1, pixel_rate); + } + -+ ret = ov5647_set_virtual_channel(sd, 0); -+ if (ret < 0) -+ return ret; ++ mutex_unlock(&ov2311->mutex); + -+ ret = ov5647_read(sd, OV5647_SW_STANDBY, &resetval); -+ if (ret < 0) -+ return ret; ++ return 0; ++} + -+ 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; ++static int ov2311_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct ov2311 *ov2311 = to_ov2311(sd); ++ const struct ov2311_mode *mode = ov2311->cur_mode; ++ ++ mutex_lock(&ov2311->mutex); ++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { ++ fmt->format = *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); ++ } else { ++ fmt->format.width = mode->width; ++ fmt->format.height = mode->height; ++ fmt->format.code = ov2311->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(&ov2311->mutex); + + 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; ++static int ov2311_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ 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; + } + -+ /* Apply customized values from user when stream starts */ -+ ret = __v4l2_ctrl_handler_setup(sd->ctrl_handler); -+ if (ret) -+ return ret; ++ return 0; ++} + -+ if (ov5647->flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK) -+ val |= MIPI_CTRL00_CLOCK_LANE_GATE | -+ MIPI_CTRL00_LINE_SYNC_ENABLE; ++static int ov2311_enum_frame_sizes(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ if (fse->index >= ARRAY_SIZE(supported_modes)) ++ return -EINVAL; + -+ ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, val); - if (ret < 0) - return ret; - -@@ -306,44 +949,6 @@ static int set_sw_standby(struct v4l2_subdev *sd, bool standby) - 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; -@@ -355,33 +960,57 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on) - if (on && !ov5647->power_count) { - dev_dbg(&client->dev, "OV5647 power on\n"); - -+ ret = regulator_bulk_enable(OV5647_NUM_SUPPLIES, -+ ov5647->supplies); -+ if (ret < 0) { -+ dev_err(&client->dev, "Failed to enable regulators\n"); -+ goto out; -+ } ++ if (fse->code != MEDIA_BUS_FMT_Y10_1X10 && ++ fse->code != MEDIA_BUS_FMT_Y8_1X8) ++ return -EINVAL; + -+ if (ov5647->pwdn) { -+ gpiod_set_value_cansleep(ov5647->pwdn, 0); -+ msleep(PWDN_ACTIVE_DELAY_MS); -+ } ++ fse->min_width = supported_modesfse->index.width; ++ fse->max_width = supported_modesfse->index.width; ++ fse->max_height = supported_modesfse->index.height; ++ fse->min_height = supported_modesfse->index.height; + - ret = clk_prepare_enable(ov5647->xclk); - if (ret < 0) { -+ regulator_bulk_disable(OV5647_NUM_SUPPLIES, -+ ov5647->supplies); - dev_err(&client->dev, "clk prepare enable failed\n"); - goto out; - } - - 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); -+ regulator_bulk_disable(OV5647_NUM_SUPPLIES, -+ ov5647->supplies); - dev_err(&client->dev, - "write sensor_oe_enable_regs error\n"); - 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); -+ regulator_bulk_disable(OV5647_NUM_SUPPLIES, -+ ov5647->supplies); - dev_err(&client->dev, - "Camera not available, check Power\n"); - goto out; - } ++ return 0; ++} + -+ /* 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"); -@@ -392,6 +1021,10 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on) - dev_dbg(&client->dev, "soft stby failed\n"); - - clk_disable_unprepare(ov5647->xclk); ++static int ov2311_enable_test_pattern(struct ov2311 *ov2311, u32 pattern) ++{ ++ u32 val; + -+ gpiod_set_value_cansleep(ov5647->pwdn, 1); ++ if (pattern) ++ val = (pattern - 1) | OV2311_TEST_PATTERN_ENABLE; ++ else ++ val = OV2311_TEST_PATTERN_DISABLE; ++ ++ return ov2311_write_reg(ov2311->client, OV2311_REG_TEST_PATTERN, ++ OV2311_REG_VALUE_08BIT, val); ++} + -+ regulator_bulk_disable(OV5647_NUM_SUPPLIES, ov5647->supplies); - } - - /* Update the power count. */ -@@ -437,34 +1070,274 @@ static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = { - .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, ++__ov2311_get_pad_crop(struct ov2311 *ov2311, struct v4l2_subdev_state *sd_state, + 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); ++ return v4l2_subdev_get_try_crop(&ov2311->subdev, sd_state, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: -+ return &ov5647->mode->crop; ++ return &ov2311->cur_mode->crop; + } + + return NULL; +} + -+static int ov5647_get_selection(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, ++static int ov2311_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: { -+ struct ov5647 *state = to_state(sd); ++ struct ov2311 *ov2311 = to_ov2311(sd); + -+ mutex_lock(&state->lock); -+ sel->r = *__ov5647_get_pad_crop(state, cfg, sel->pad, ++ mutex_lock(&ov2311->mutex); ++ sel->r = *__ov2311_get_pad_crop(ov2311, sd_state, sel->pad, + sel->which); -+ mutex_unlock(&state->lock); ++ mutex_unlock(&ov2311->mutex); + + return 0; + } @@ -79085,17 +118458,17 @@ + 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; ++ sel->r.width = OV2311_NATIVE_WIDTH; ++ sel->r.height = OV2311_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; ++ sel->r.top = OV2311_PIXEL_ARRAY_TOP; ++ sel->r.left = OV2311_PIXEL_ARRAY_LEFT; ++ sel->r.width = OV2311_PIXEL_ARRAY_WIDTH; ++ sel->r.height = OV2311_PIXEL_ARRAY_HEIGHT; + + return 0; + } @@ -79103,1977 +118476,4800 @@ + 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); ++static int ov2311_start_stream(struct ov2311 *ov2311) ++{ ++ int ret; + -+ mutex_unlock(&state->lock); ++ ret = ov2311_write_array(ov2311->client, ov2311_common_regs); ++ if (ret) ++ return ret; + -+ return ret; - } - - static const struct v4l2_subdev_video_ops ov5647_subdev_video_ops = { - .s_stream = ov5647_s_stream, - }; - -+/* This function returns the mbus code for the current settings of the -+ HFLIP and VFLIP controls. */ ++ ret = ov2311_write_array(ov2311->client, ov2311->cur_mode->reg_list); ++ if (ret) ++ return ret; + -+static u32 ov5647_get_mbus_code(struct v4l2_subdev *sd, int mode_8bit) -+{ -+ struct ov5647 *state = to_state(sd); -+ /* The control values are only 0 or 1. */ -+ int index = state->hflip->val | (state->vflip->val << 1); ++ if (ov2311->code == MEDIA_BUS_FMT_Y10_1X10) ++ ret = ov2311_write_array(ov2311->client, op_10bit); ++ else ++ ret = ov2311_write_array(ov2311->client, op_8bit); ++ if (ret) ++ return ret; + -+ static const u32 codes24 = { -+ { -+ MEDIA_BUS_FMT_SGBRG10_1X10, -+ MEDIA_BUS_FMT_SBGGR10_1X10, -+ MEDIA_BUS_FMT_SRGGB10_1X10, -+ MEDIA_BUS_FMT_SGRBG10_1X10 -+ }, -+ { -+ MEDIA_BUS_FMT_SGBRG8_1X8, -+ MEDIA_BUS_FMT_SBGGR8_1X8, -+ MEDIA_BUS_FMT_SRGGB8_1X8, -+ MEDIA_BUS_FMT_SGRBG8_1X8 -+ } -+ }; ++ /* In case these controls are set before streaming */ ++ mutex_unlock(&ov2311->mutex); ++ ret = v4l2_ctrl_handler_setup(&ov2311->ctrl_handler); ++ mutex_lock(&ov2311->mutex); ++ if (ret) ++ return ret; + -+ return codesmode_8bitindex; ++ return ov2311_write_reg(ov2311->client, OV2311_REG_CTRL_MODE, ++ OV2311_REG_VALUE_08BIT, OV2311_MODE_STREAMING); +} + - static int ov5647_enum_mbus_code(struct v4l2_subdev *sd, - 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 = ov5647_get_mbus_code(sd, 1); -+ else if (code->index == 0 && ARRAY_SIZE(supported_modes_8bit) == 0 && -+ ARRAY_SIZE(supported_modes_10bit)) -+ code->code = ov5647_get_mbus_code(sd, 0); -+ else if (code->index == 1 && ARRAY_SIZE(supported_modes_8bit) && -+ ARRAY_SIZE(supported_modes_10bit)) -+ code->code = ov5647_get_mbus_code(sd, 0); -+ else -+ return -EINVAL; -+ -+ return 0; ++static int ov2311_stop_stream(struct ov2311 *ov2311) ++{ ++ return ov2311_write_reg(ov2311->client, OV2311_REG_CTRL_MODE, ++ OV2311_REG_VALUE_08BIT, OV2311_MODE_SW_STANDBY); +} + -+static int ov5647_enum_frame_size(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_frame_size_enum *fse) ++static int ov2311_s_stream(struct v4l2_subdev *sd, int enable) +{ -+ struct ov5647_mode *mode = NULL; ++ struct ov2311 *ov2311 = to_ov2311(sd); ++ struct i2c_client *client = ov2311->client; ++ int ret = 0; + -+ if (fse->code == ov5647_get_mbus_code(sd, 1)) { -+ if (fse->index >= ARRAY_SIZE(supported_modes_8bit)) -+ return -EINVAL; -+ mode = &supported_modes_8bitfse->index; -+ } else if (fse->code == ov5647_get_mbus_code(sd, 0)) { -+ if (fse->index >= ARRAY_SIZE(supported_modes_10bit)) -+ return -EINVAL; -+ mode = &supported_modes_10bitfse->index; ++ mutex_lock(&ov2311->mutex); ++ if (ov2311->streaming == enable) { ++ mutex_unlock(&ov2311->mutex); ++ return 0; ++ } ++ ++ if (enable) { ++ ret = pm_runtime_resume_and_get(&client->dev); ++ if (ret < 0) ++ goto unlock_and_return; ++ ++ ret = ov2311_start_stream(ov2311); ++ if (ret) { ++ v4l2_err(sd, "start stream failed while write regs\n"); ++ pm_runtime_put(&client->dev); ++ goto unlock_and_return; ++ } + } else { -+ return -EINVAL; ++ ov2311_stop_stream(ov2311); ++ pm_runtime_put(&client->dev); + } + -+ fse->min_width = mode->format.width; -+ fse->max_width = fse->min_width; -+ fse->min_height = mode->format.height; -+ fse->max_height = fse->min_height; ++ ov2311->streaming = enable; + -+ return 0; ++unlock_and_return: ++ mutex_unlock(&ov2311->mutex); ++ ++ return ret; +} + -+static int ov5647_set_fmt(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_format *format) ++static int ov2311_power_on(struct device *dev) +{ -+ 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); ++ struct v4l2_subdev *sd = dev_get_drvdata(dev); ++ struct ov2311 *ov2311 = to_ov2311(sd); ++ int ret; + -+ /* -+ * 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 == ov5647_get_mbus_code(sd, 1) && mode_8bit) -+ mode = mode_8bit; -+ else if (format->format.code == ov5647_get_mbus_code(sd, 0) && -+ mode_10bit) -+ mode = mode_10bit; -+ else if (mode_10bit) -+ mode = mode_10bit; -+ else -+ mode = mode_8bit; ++ ret = clk_set_rate(ov2311->xvclk, OV2311_XVCLK_FREQ); ++ if (ret < 0) ++ dev_warn(dev, "Failed to set xvclk rate (24MHz)\n"); ++ if (clk_get_rate(ov2311->xvclk) != OV2311_XVCLK_FREQ) ++ dev_warn(dev, "xvclk mismatched, modes are based on 24MHz - rate is %lu\n", ++ clk_get_rate(ov2311->xvclk)); + -+ if (!mode) { -+ mutex_unlock(&state->lock); -+ return -EINVAL; ++ ret = clk_prepare_enable(ov2311->xvclk); ++ if (ret < 0) { ++ dev_err(dev, "Failed to enable xvclk\n"); ++ return ret; + } + -+ *fmt = mode->format; -+ /* The mbus code we pass back must reflect the current H/VFLIP settings. */ -+ fmt->code = ov5647_get_mbus_code(sd, mode == mode_8bit); -+ 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); ++ gpiod_set_value_cansleep(ov2311->reset_gpio, 0); + -+ __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); ++ ret = regulator_bulk_enable(OV2311_NUM_SUPPLIES, ov2311->supplies); ++ if (ret < 0) { ++ dev_err(dev, "Failed to enable regulators\n"); ++ goto disable_clk; + } + -+ mutex_unlock(&state->lock); -+ -+ return 0; -+} ++ gpiod_set_value_cansleep(ov2311->reset_gpio, 1); + -+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); ++ usleep_range(500, 1000); ++ gpiod_set_value_cansleep(ov2311->pwdn_gpio, 1); + -+ if (format->pad != 0) - return -EINVAL; - -- code->code = MEDIA_BUS_FMT_SBGGR8_1X8; -+ mutex_lock(&state->lock); ++ usleep_range(1000, 2000); + -+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) -+ *fmt = *v4l2_subdev_get_try_format(sd, cfg, format->pad); -+ else -+ *fmt = state->mode->format; -+ /* The mbus code we pass back must reflect the current H/VFLIP settings. */ -+ fmt->code = ov5647_get_mbus_code(sd, fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8); ++ return 0; + -+ 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 = { -@@ -510,18 +1383,15 @@ static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) - 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_COLUMN_START_DEF; -- crop->top = OV5647_ROW_START_DEF; -- crop->width = OV5647_WINDOW_WIDTH_DEF; -- crop->height = OV5647_WINDOW_HEIGHT_DEF; -+ crop->left = OV5647_PIXEL_ARRAY_LEFT; -+ crop->top = OV5647_PIXEL_ARRAY_TOP; -+ crop->width = OV5647_PIXEL_ARRAY_WIDTH; -+ crop->height = OV5647_PIXEL_ARRAY_HEIGHT; - -- 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; - } -@@ -530,7 +1400,7 @@ static const struct v4l2_subdev_internal_ops ov5647_subdev_internal_ops = { - .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; -@@ -543,10 +1413,188 @@ static int ov5647_parse_dt(struct device_node *np) - - ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg); - -+ if (!ret) -+ sensor->flags = bus_cfg.bus.mipi_csi2.flags; ++disable_clk: ++ clk_disable_unprepare(ov2311->xvclk); + - 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); ++ return ret; +} + -+static int ov5647_s_autogain(struct v4l2_subdev *sd, u32 val) ++static int ov2311_power_off(struct device *dev) +{ -+ int ret; -+ u8 reg; ++ struct v4l2_subdev *sd = dev_get_drvdata(dev); ++ struct ov2311 *ov2311 = to_ov2311(sd); + -+ /* 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); ++ gpiod_set_value_cansleep(ov2311->pwdn_gpio, 0); ++ clk_disable_unprepare(ov2311->xvclk); ++ gpiod_set_value_cansleep(ov2311->reset_gpio, 0); ++ regulator_bulk_disable(OV2311_NUM_SUPPLIES, ov2311->supplies); + -+ return ret; ++ return 0; +} + -+static int ov5647_s_exposure_auto(struct v4l2_subdev *sd, u32 val) ++static int ov2311_runtime_resume(struct device *dev) +{ ++ struct v4l2_subdev *sd = dev_get_drvdata(dev); ++ struct ov2311 *ov2311 = to_ov2311(sd); + 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); ++ if (ov2311->streaming) { ++ ret = ov2311_start_stream(ov2311); ++ if (ret) ++ goto error; ++ } ++ return 0; + ++error: ++ ov2311_stop_stream(ov2311); ++ ov2311->streaming = 0; + return ret; +} + -+static int ov5647_s_analogue_gain(struct v4l2_subdev *sd, u32 val) ++static int ov2311_runtime_suspend(struct device *dev) +{ -+ int ret; ++ struct v4l2_subdev *sd = dev_get_drvdata(dev); ++ struct ov2311 *ov2311 = to_ov2311(sd); + -+ /* 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); ++ if (ov2311->streaming) ++ ov2311_stop_stream(ov2311); + -+ return ret; ++ return 0; +} + -+static int ov5647_s_exposure(struct v4l2_subdev *sd, u32 val) ++static int ov2311_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ -+ int ret; ++ struct ov2311 *ov2311 = to_ov2311(sd); ++ struct v4l2_mbus_framefmt *try_fmt = ++ v4l2_subdev_get_try_format(sd, fh->state, 0); ++ const struct ov2311_mode *def_mode = &supported_modes0; + -+ /* 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); ++ mutex_lock(&ov2311->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_RAW; ++ 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); + -+ return ret; ++ mutex_unlock(&ov2311->mutex); ++ /* No crop or compose */ ++ ++ return 0; +} + -+static int ov5647_s_flip( struct v4l2_subdev *sd, u16 reg, u32 ctrl_val) -+{ -+ int ret; -+ u8 reg_val; ++static const struct dev_pm_ops ov2311_pm_ops = { ++ SET_RUNTIME_PM_OPS(ov2311_runtime_suspend, ov2311_runtime_resume, NULL) ++ SET_RUNTIME_PM_OPS(ov2311_power_off, ov2311_power_on, NULL) ++}; + -+ /* Set or clear bit 1 and leave everything else alone. */ -+ ret = ov5647_read(sd, reg, ®_val); -+ if (ret == 0) { -+ if (ctrl_val) -+ reg_val |= 2; -+ else -+ reg_val &= ~2; ++static const struct v4l2_subdev_internal_ops ov2311_internal_ops = { ++ .open = ov2311_open, ++}; + -+ ret = ov5647_write(sd, reg, reg_val); -+ } ++static const struct v4l2_subdev_core_ops ov2311_core_ops = { ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++}; + -+ return ret; -+} ++static const struct v4l2_subdev_video_ops ov2311_video_ops = { ++ .s_stream = ov2311_s_stream, ++}; + -+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; ++static const struct v4l2_subdev_pad_ops ov2311_pad_ops = { ++ .enum_mbus_code = ov2311_enum_mbus_code, ++ .enum_frame_size = ov2311_enum_frame_sizes, ++ .get_fmt = ov2311_get_fmt, ++ .set_fmt = ov2311_set_fmt, ++ .get_selection = ov2311_get_selection, ++}; + -+ /* v4l2_ctrl_lock() locks our own mutex */ ++static const struct v4l2_subdev_ops ov2311_subdev_ops = { ++ .core = &ov2311_core_ops, ++ .video = &ov2311_video_ops, ++ .pad = &ov2311_pad_ops, ++}; + -+ if (ctrl->id == V4L2_CID_VBLANK) { -+ int exposure_max, exposure_def; ++static int ov2311_set_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct ov2311 *ov2311 = container_of(ctrl->handler, ++ struct ov2311, ctrl_handler); ++ struct i2c_client *client = ov2311->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 */ -+ 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); ++ max = ov2311->cur_mode->height + ctrl->val - 4; ++ __v4l2_ctrl_modify_range(ov2311->exposure, ++ ov2311->exposure->minimum, max, ++ ov2311->exposure->step, ++ ov2311->exposure->default_value); ++ break; + } + -+ /* -+ * 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) ++ if (pm_runtime_get(&client->dev) <= 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); ++ ret = ov2311_write_reg(ov2311->client, OV2311_REG_EXPOSURE, ++ OV2311_REG_VALUE_16BIT, 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. */ ++ case V4L2_CID_ANALOGUE_GAIN: ++ ret = ov2311_write_reg(ov2311->client, OV2311_REG_GAIN_H, ++ OV2311_REG_VALUE_08BIT, ++ (ctrl->val >> OV2311_GAIN_H_SHIFT) & ++ OV2311_GAIN_H_MASK); ++ ret |= ov2311_write_reg(ov2311->client, OV2311_REG_GAIN_L, ++ OV2311_REG_VALUE_08BIT, ++ ctrl->val & OV2311_GAIN_L_MASK); + break; + case V4L2_CID_VBLANK: -+ ret = ov5647_write16(sd, OV5647_REG_VTS_HI, -+ state->mode->format.height + ctrl->val); ++ ret = ov2311_write_reg(ov2311->client, OV2311_REG_VTS, ++ OV2311_REG_VALUE_16BIT, ++ ctrl->val + ov2311->cur_mode->height); ++ break; ++ case V4L2_CID_TEST_PATTERN: ++ ret = ov2311_enable_test_pattern(ov2311, ctrl->val); + break; + case V4L2_CID_HFLIP: -+ /* There's an in-built hflip in the sensor, so account for that here. */ -+ ov5647_s_flip(sd, OV5647_REG_HFLIP, !ctrl->val); ++ ret = ov2311_write_reg(ov2311->client, OV2311_REG_H_FLIP, ++ OV2311_REG_VALUE_08BIT, ++ ctrl->val ? OV2311_FLIP_BIT : 0); + break; + case V4L2_CID_VFLIP: -+ ov5647_s_flip(sd, OV5647_REG_VFLIP, ctrl->val); ++ ret = ov2311_write_reg(ov2311->client, OV2311_REG_V_FLIP, ++ OV2311_REG_VALUE_08BIT, ++ ctrl->val ? OV2311_FLIP_BIT : 0); + break; + default: -+ dev_info(&client->dev, -+ "ctrl(id:0x%x,val:0x%x) is not handled\n", -+ ctrl->id, ctrl->val); -+ ret = -EINVAL; ++ 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 ov5647_ctrl_ops = { -+ .s_ctrl = ov5647_s_ctrl, ++static const struct v4l2_ctrl_ops ov2311_ctrl_ops = { ++ .s_ctrl = ov2311_set_ctrl, +}; + -+static int ov5647_configure_regulators(struct device *dev, -+ struct ov5647 *ov5647) ++static int ov2311_initialize_controls(struct ov2311 *ov2311) ++{ ++ struct v4l2_fwnode_device_properties props; ++ const struct ov2311_mode *mode; ++ struct v4l2_ctrl_handler *handler; ++ struct v4l2_ctrl *ctrl; ++ s64 exposure_max, vblank_def; ++ u32 h_blank; ++ int ret; ++ ++ handler = &ov2311->ctrl_handler; ++ mode = ov2311->cur_mode; ++ ret = v4l2_ctrl_handler_init(handler, 11); ++ if (ret) ++ return ret; ++ handler->lock = &ov2311->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; ++ ++ ov2311->pixel_rate = v4l2_ctrl_new_std(handler, NULL, ++ V4L2_CID_PIXEL_RATE, ++ OV2311_PIXEL_RATE_10BIT, ++ OV2311_PIXEL_RATE_10BIT, 1, ++ OV2311_PIXEL_RATE_10BIT); ++ ++ h_blank = mode->hts_def - mode->width; ++ ov2311->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, ++ h_blank, h_blank, 1, h_blank); ++ if (ov2311->hblank) ++ ov2311->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ ++ vblank_def = mode->vts_def - mode->height; ++ ov2311->vblank = v4l2_ctrl_new_std(handler, &ov2311_ctrl_ops, ++ V4L2_CID_VBLANK, vblank_def, ++ OV2311_VTS_MAX - mode->height, 1, ++ vblank_def); ++ ++ exposure_max = mode->vts_def - 4; ++ ov2311->exposure = v4l2_ctrl_new_std(handler, &ov2311_ctrl_ops, ++ V4L2_CID_EXPOSURE, ++ OV2311_EXPOSURE_MIN, exposure_max, ++ OV2311_EXPOSURE_STEP, ++ mode->exp_def); ++ ++ v4l2_ctrl_new_std(handler, &ov2311_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, ++ OV2311_GAIN_MIN, OV2311_GAIN_MAX, OV2311_GAIN_STEP, ++ OV2311_GAIN_DEFAULT); ++ ++ v4l2_ctrl_new_std_menu_items(handler, &ov2311_ctrl_ops, ++ V4L2_CID_TEST_PATTERN, ++ ARRAY_SIZE(ov2311_test_pattern_menu) - 1, ++ 0, 0, ov2311_test_pattern_menu); ++ ++ v4l2_ctrl_new_std(handler, &ov2311_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ ++ v4l2_ctrl_new_std(handler, &ov2311_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ ++ ret = v4l2_fwnode_device_parse(&ov2311->client->dev, &props); ++ if (ret) ++ goto err_free_handler; ++ ++ ret = v4l2_ctrl_new_fwnode_properties(handler, &ov2311_ctrl_ops, ++ &props); ++ if (ret) ++ goto err_free_handler; ++ ++ if (handler->error) { ++ ret = handler->error; ++ dev_err(&ov2311->client->dev, ++ "Failed to init controls(%d)\n", ret); ++ goto err_free_handler; ++ } ++ ++ ov2311->subdev.ctrl_handler = handler; ++ ++ return 0; ++ ++err_free_handler: ++ v4l2_ctrl_handler_free(handler); ++ ++ return ret; ++} ++ ++static int ov2311_check_sensor_id(struct ov2311 *ov2311, ++ struct i2c_client *client) ++{ ++ struct device *dev = &ov2311->client->dev; ++ u32 id = 0, id_msb = 0; ++ int ret; ++ ++ ret = ov2311_read_reg(client, OV2311_REG_CHIP_ID + 1, ++ OV2311_REG_VALUE_08BIT, &id); ++ if (!ret) ++ ret = ov2311_read_reg(client, OV2311_REG_CHIP_ID, ++ OV2311_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 ov2311_configure_regulators(struct ov2311 *ov2311) +{ + unsigned int i; + -+ for (i = 0; i < OV5647_NUM_SUPPLIES; i++) -+ ov5647->suppliesi.supply = ov5647_supply_namesi; ++ for (i = 0; i < OV2311_NUM_SUPPLIES; i++) ++ ov2311->suppliesi.supply = ov2311_supply_namesi; + -+ return devm_regulator_bulk_get(dev, OV5647_NUM_SUPPLIES, -+ ov5647->supplies); ++ return devm_regulator_bulk_get(&ov2311->client->dev, ++ OV2311_NUM_SUPPLIES, ++ ov2311->supplies); +} + - static int ov5647_probe(struct i2c_client *client) - { - struct device *dev = &client->dev; -@@ -555,13 +1603,15 @@ static int ov5647_probe(struct i2c_client *client) - 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; -@@ -581,12 +1631,113 @@ static int ov5647_probe(struct i2c_client *client) - return -EINVAL; - } - -+ /* Request the power down GPIO asserted */ -+ sensor->pwdn = devm_gpiod_get_optional(&client->dev, "pwdn", -+ GPIOD_OUT_HIGH); ++static int ov2311_probe(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ struct ov2311 *ov2311; ++ struct v4l2_subdev *sd; ++ int ret; + -+ ret = ov5647_configure_regulators(dev, sensor); ++ ov2311 = devm_kzalloc(dev, sizeof(*ov2311), GFP_KERNEL); ++ if (!ov2311) ++ return -ENOMEM; ++ ++ ov2311->client = client; ++ ov2311->cur_mode = &supported_modes0; ++ ++ ov2311->xvclk = devm_clk_get(dev, "xvclk"); ++ if (IS_ERR(ov2311->xvclk)) { ++ dev_err(dev, "Failed to get xvclk\n"); ++ return -EINVAL; ++ } ++ ++ ov2311->reset_gpio = devm_gpiod_get_optional(dev, "reset", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(ov2311->reset_gpio)) ++ dev_warn(dev, "Failed to get reset-gpios\n"); ++ ++ ov2311->pwdn_gpio = devm_gpiod_get_optional(dev, "pwdn", GPIOD_OUT_LOW); ++ if (IS_ERR(ov2311->pwdn_gpio)) ++ dev_warn(dev, "Failed to get pwdn-gpios\n"); ++ ++ ret = ov2311_configure_regulators(ov2311); + if (ret) { + dev_err(dev, "Failed to get power regulators\n"); + return ret; + } + - mutex_init(&sensor->lock); - -+ /* Initialise controls. */ -+ v4l2_ctrl_handler_init(&sensor->ctrls, 11); -+ 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); ++ mutex_init(&ov2311->mutex); + -+ /* 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); ++ sd = &ov2311->subdev; ++ v4l2_i2c_subdev_init(sd, client, &ov2311_subdev_ops); ++ ret = ov2311_initialize_controls(ov2311); ++ if (ret) ++ goto err_destroy_mutex; + -+ sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, -+ V4L2_CID_HFLIP, 0, 1, 1, 0); -+ if (sensor->hflip) -+ sensor->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ret = ov2311_power_on(&client->dev); ++ if (ret) ++ goto err_free_handler; + -+ sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, -+ V4L2_CID_VFLIP, 0, 1, 1, 0); -+ if (sensor->vflip) -+ sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ret = ov2311_check_sensor_id(ov2311, client); ++ if (ret) ++ goto err_power_off; + -+ if (sensor->ctrls.error) { -+ ret = sensor->ctrls.error; -+ dev_err(&client->dev, "%s control init failed (%d)\n", -+ __func__, ret); -+ goto error; ++ sd->internal_ops = &ov2311_internal_ops; ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ ov2311->pad.flags = MEDIA_PAD_FL_SOURCE; ++ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = media_entity_pads_init(&sd->entity, 1, &ov2311->pad); ++ if (ret < 0) ++ goto err_power_off; ++ ++ ret = v4l2_async_register_subdev(sd); ++ if (ret) { ++ dev_err(dev, "v4l2 async register subdev failed\n"); ++ goto err_clean_entity; + } + -+ ret = v4l2_fwnode_device_parse(&client->dev, &props); -+ if (ret) -+ goto error; ++ pm_runtime_set_active(dev); ++ pm_runtime_enable(dev); ++ pm_runtime_idle(dev); + -+ ret = v4l2_ctrl_new_fwnode_properties(&sensor->ctrls, &ov5647_ctrl_ops, -+ &props); -+ if (ret) -+ goto error; ++ return 0; + -+ sensor->sd.ctrl_handler = &sensor->ctrls; ++err_clean_entity: ++ media_entity_cleanup(&sd->entity); ++err_power_off: ++ ov2311_power_off(&client->dev); ++err_free_handler: ++ v4l2_ctrl_handler_free(&ov2311->ctrl_handler); ++err_destroy_mutex: ++ mutex_destroy(&ov2311->mutex); + -+ /* Write out the register set over I2C on stream-on. */ -+ sensor->write_mode_regs = true; ++ return ret; ++} + - 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; ++static void ov2311_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov2311 *ov2311 = to_ov2311(sd); ++ ++ v4l2_async_unregister_subdev(sd); ++ media_entity_cleanup(&sd->entity); ++ v4l2_ctrl_handler_free(&ov2311->ctrl_handler); ++ mutex_destroy(&ov2311->mutex); ++ ++ pm_runtime_disable(&client->dev); ++ if (!pm_runtime_status_suspended(&client->dev)) ++ ov2311_power_off(&client->dev); ++ pm_runtime_set_suspended(&client->dev); ++} ++ ++static const struct of_device_id ov2311_of_match = { ++ { .compatible = "ovti,ov2311" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov2311_of_match); ++ ++static const struct i2c_device_id ov2311_match_id = { ++ { "ovti,ov2311", 0 }, ++ { }, ++}; ++ ++static struct i2c_driver ov2311_i2c_driver = { ++ .driver = { ++ .name = OV2311_NAME, ++ .pm = &ov2311_pm_ops, ++ .of_match_table = of_match_ptr(ov2311_of_match), ++ }, ++ .probe = &ov2311_probe, ++ .remove = &ov2311_remove, ++ .id_table = ov2311_match_id, ++}; ++ ++module_i2c_driver(ov2311_i2c_driver); ++ ++MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com"); ++MODULE_DESCRIPTION("OmniVision OV2311 sensor driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c +index 8de398423b7c..3f89974963e0 100644 +--- a/drivers/media/i2c/ov5647.c ++++ b/drivers/media/i2c/ov5647.c +@@ -20,6 +20,7 @@ + #include <linux/module.h> + #include <linux/of_graph.h> + #include <linux/pm_runtime.h> ++#include <linux/regulator/consumer.h> + #include <linux/slab.h> + #include <linux/videodev2.h> + #include <media/v4l2-ctrls.h> +@@ -54,6 +55,8 @@ + #define OV5647_REG_GAIN_LO 0x350b + #define OV5647_REG_VTS_HI 0x380e + #define OV5647_REG_VTS_LO 0x380f ++#define OV5647_REG_VFLIP 0x3820 ++#define OV5647_REG_HFLIP 0x3821 + #define OV5647_REG_FRAME_OFF_NUMBER 0x4202 + #define OV5647_REG_MIPI_CTRL00 0x4800 + #define OV5647_REG_MIPI_CTRL14 0x4814 +@@ -69,11 +72,11 @@ + #define OV5647_NATIVE_HEIGHT 1956U - sensor->pad.flags = MEDIA_PAD_FL_SOURCE; - sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; -@@ -594,9 +1745,23 @@ static int ov5647_probe(struct i2c_client *client) - if (ret < 0) - goto mutex_remove; + #define OV5647_PIXEL_ARRAY_LEFT 16U +-#define OV5647_PIXEL_ARRAY_TOP 16U ++#define OV5647_PIXEL_ARRAY_TOP 6U + #define OV5647_PIXEL_ARRAY_WIDTH 2592U + #define OV5647_PIXEL_ARRAY_HEIGHT 1944U + +-#define OV5647_VBLANK_MIN 4 ++#define OV5647_VBLANK_MIN 24 + #define OV5647_VTS_MAX 32767 + + #define OV5647_EXPOSURE_MIN 4 +@@ -81,6 +84,15 @@ + #define OV5647_EXPOSURE_DEFAULT 1000 + #define OV5647_EXPOSURE_MAX 65535 + ++/* regulator supplies */ ++static const char * const ov5647_supply_names = { ++ "avdd", /* Analog power */ ++ "dovdd", /* Digital I/O power */ ++ "dvdd", /* Digital core power */ ++}; ++ ++#define OV5647_NUM_SUPPLIES ARRAY_SIZE(ov5647_supply_names) ++ + struct regval_list { + u16 addr; + u8 data; +@@ -102,6 +114,7 @@ struct ov5647 { + struct mutex lock; + struct clk *xclk; + struct gpio_desc *pwdn; ++ struct regulator_bulk_data suppliesOV5647_NUM_SUPPLIES; + bool clock_ncont; + struct v4l2_ctrl_handler ctrls; + const struct ov5647_mode *mode; +@@ -109,6 +122,8 @@ struct ov5647 { + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *exposure; ++ struct v4l2_ctrl *hflip; ++ struct v4l2_ctrl *vflip; + bool streaming; + }; + +@@ -151,7 +166,7 @@ static struct regval_list ov5647_2592x1944_10bpp = { + {0x3036, 0x69}, + {0x303c, 0x11}, + {0x3106, 0xf5}, +- {0x3821, 0x06}, ++ {0x3821, 0x00}, + {0x3820, 0x00}, + {0x3827, 0xec}, + {0x370c, 0x03}, +@@ -240,7 +255,7 @@ static struct regval_list ov5647_1080p30_10bpp = { + {0x3036, 0x62}, + {0x303c, 0x11}, + {0x3106, 0xf5}, +- {0x3821, 0x06}, ++ {0x3821, 0x00}, + {0x3820, 0x00}, + {0x3827, 0xec}, + {0x370c, 0x03}, +@@ -404,7 +419,7 @@ static struct regval_list ov5647_2x2binned_10bpp = { + {0x4800, 0x24}, + {0x3503, 0x03}, + {0x3820, 0x41}, +- {0x3821, 0x07}, ++ {0x3821, 0x01}, + {0x350a, 0x00}, + {0x350b, 0x10}, + {0x3500, 0x00}, +@@ -420,7 +435,7 @@ static struct regval_list ov5647_640x480_10bpp = { + {0x3035, 0x11}, + {0x3036, 0x46}, + {0x303c, 0x11}, +- {0x3821, 0x07}, ++ {0x3821, 0x01}, + {0x3820, 0x41}, + {0x370c, 0x03}, + {0x3612, 0x59}, +@@ -509,7 +524,7 @@ static const struct ov5647_mode ov5647_modes = { + { + .format = { + .code = MEDIA_BUS_FMT_SBGGR10_1X10, +- .colorspace = V4L2_COLORSPACE_SRGB, ++ .colorspace = V4L2_COLORSPACE_RAW, + .field = V4L2_FIELD_NONE, + .width = 2592, + .height = 1944 +@@ -530,7 +545,7 @@ static const struct ov5647_mode ov5647_modes = { + { + .format = { + .code = MEDIA_BUS_FMT_SBGGR10_1X10, +- .colorspace = V4L2_COLORSPACE_SRGB, ++ .colorspace = V4L2_COLORSPACE_RAW, + .field = V4L2_FIELD_NONE, + .width = 1920, + .height = 1080 +@@ -551,7 +566,7 @@ static const struct ov5647_mode ov5647_modes = { + { + .format = { + .code = MEDIA_BUS_FMT_SBGGR10_1X10, +- .colorspace = V4L2_COLORSPACE_SRGB, ++ .colorspace = V4L2_COLORSPACE_RAW, + .field = V4L2_FIELD_NONE, + .width = 1296, + .height = 972 +@@ -572,7 +587,7 @@ static const struct ov5647_mode ov5647_modes = { + { + .format = { + .code = MEDIA_BUS_FMT_SBGGR10_1X10, +- .colorspace = V4L2_COLORSPACE_SRGB, ++ .colorspace = V4L2_COLORSPACE_RAW, + .field = V4L2_FIELD_NONE, + .width = 640, + .height = 480 +@@ -602,7 +617,13 @@ static int ov5647_write16(struct v4l2_subdev *sd, u16 reg, u16 val) + int ret; + + ret = i2c_master_send(client, data, 4); +- 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 == 4) { ++ ret = 0; ++ } else { + dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n", + __func__, reg); + return ret; +@@ -618,10 +639,17 @@ static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val) + int ret; + + 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); +- return ret; ++ if (ret >= 0) ++ ret = -EINVAL; + } + + return 0; +@@ -778,6 +806,12 @@ static int ov5647_power_on(struct device *dev) + + dev_dbg(dev, "OV5647 power on\n"); + ret = regulator_bulk_enable(OV5647_NUM_SUPPLIES, sensor->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators\n"); -+ goto error; ++ return ret; + } + -+ if (sensor->pwdn) { -+ gpiod_set_value_cansleep(sensor->pwdn, 0); -+ msleep(PWDN_ACTIVE_DELAY_MS); -+ } + if (sensor->pwdn) { + gpiod_set_value_cansleep(sensor->pwdn, 0); + msleep(PWDN_ACTIVE_DELAY_MS); +@@ -809,6 +843,7 @@ static int ov5647_power_on(struct device *dev) + clk_disable_unprepare(sensor->xclk); + error_pwdn: + gpiod_set_value_cansleep(sensor->pwdn, 1); ++ regulator_bulk_disable(OV5647_NUM_SUPPLIES, sensor->supplies); + + return ret; + } +@@ -838,6 +873,7 @@ static int ov5647_power_off(struct device *dev) + + clk_disable_unprepare(sensor->xclk); + gpiod_set_value_cansleep(sensor->pwdn, 1); ++ regulator_bulk_disable(OV5647_NUM_SUPPLIES, sensor->supplies); + + return 0; + } +@@ -874,6 +910,8 @@ static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = { + .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 * +@@ -939,6 +977,25 @@ static const struct v4l2_subdev_video_ops ov5647_subdev_video_ops = { + .s_stream = ov5647_s_stream, + }; + ++/* This function returns the mbus code for the current settings of the ++ HFLIP and VFLIP controls. */ + - ret = ov5647_detect(sd); ++static u32 ov5647_get_mbus_code(struct v4l2_subdev *sd) ++{ ++ struct ov5647 *sensor = to_sensor(sd); ++ /* The control values are only 0 or 1. */ ++ int index = sensor->hflip->val | (sensor->vflip->val << 1); + -+ gpiod_set_value_cansleep(sensor->pwdn, 1); ++ static const u32 codes4 = { ++ MEDIA_BUS_FMT_SGBRG10_1X10, ++ MEDIA_BUS_FMT_SBGGR10_1X10, ++ MEDIA_BUS_FMT_SRGGB10_1X10, ++ MEDIA_BUS_FMT_SGRBG10_1X10 ++ }; + - if (ret < 0) -- goto error; -+ goto power_down; ++ return codesindex; ++} ++ + static int ov5647_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +@@ -946,7 +1003,7 @@ static int ov5647_enum_mbus_code(struct v4l2_subdev *sd, + if (code->index > 0) + return -EINVAL; - ret = v4l2_async_register_subdev(sd); - if (ret < 0) -@@ -604,9 +1769,12 @@ static int ov5647_probe(struct i2c_client *client) +- code->code = MEDIA_BUS_FMT_SBGGR10_1X10; ++ code->code = ov5647_get_mbus_code(sd); - dev_dbg(dev, "OmniVision OV5647 camera driver probed\n"); return 0; -+power_down: -+ regulator_bulk_disable(OV5647_NUM_SUPPLIES, sensor->supplies); - error: - media_entity_cleanup(&sd->entity); - mutex_remove: -+ v4l2_ctrl_handler_free(&sensor->ctrls); - mutex_destroy(&sensor->lock); - return ret; } -@@ -618,6 +1786,7 @@ static int ov5647_remove(struct i2c_client *client) +@@ -957,7 +1014,7 @@ static int ov5647_enum_frame_size(struct v4l2_subdev *sd, + { + const struct v4l2_mbus_framefmt *fmt; - 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); +- if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10 || ++ if (fse->code != ov5647_get_mbus_code(sd) || + fse->index >= ARRAY_SIZE(ov5647_modes)) + return -EINVAL; -diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c -index 0c10203f822b..f2d77aaed798 100644 ---- a/drivers/media/i2c/ov7251.c -+++ b/drivers/media/i2c/ov7251.c -@@ -1253,6 +1253,7 @@ static const struct v4l2_subdev_ops ov7251_subdev_ops = { +@@ -990,6 +1047,8 @@ static int ov5647_get_pad_fmt(struct v4l2_subdev *sd, + } - static int ov7251_probe(struct i2c_client *client) + *fmt = *sensor_format; ++ /* The code we pass back must reflect the current h/vflips. */ ++ fmt->code = ov5647_get_mbus_code(sd); + mutex_unlock(&sensor->lock); + + return 0; +@@ -1037,6 +1096,8 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd, + exposure_def); + } + *fmt = mode->format; ++ /* The code we pass back must reflect the current h/vflips. */ ++ fmt->code = ov5647_get_mbus_code(sd); + mutex_unlock(&sensor->lock); + + return 0; +@@ -1212,6 +1273,25 @@ static int ov5647_s_exposure(struct v4l2_subdev *sd, u32 val) + return ov5647_write(sd, OV5647_REG_EXP_LO, (val & 0xf) << 4); + } + ++static int ov5647_s_flip( struct v4l2_subdev *sd, u16 reg, u32 ctrl_val) ++{ ++ int ret; ++ u8 reg_val; ++ ++ /* Set or clear bit 1 and leave everything else alone. */ ++ ret = ov5647_read(sd, reg, ®_val); ++ if (ret == 0) { ++ if (ctrl_val) ++ reg_val |= 2; ++ else ++ reg_val &= ~2; ++ ++ ret = ov5647_write(sd, reg, reg_val); ++ } ++ ++ return ret; ++} ++ + static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl) + { + struct ov5647 *sensor = container_of(ctrl->handler, +@@ -1274,6 +1354,14 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl) + /* Read-only, but we adjust it based on mode. */ + break; + ++ case V4L2_CID_HFLIP: ++ /* There's an in-built hflip in the sensor, so account for that here. */ ++ ov5647_s_flip(sd, OV5647_REG_HFLIP, !ctrl->val); ++ break; ++ case V4L2_CID_VFLIP: ++ ov5647_s_flip(sd, OV5647_REG_VFLIP, ctrl->val); ++ break; ++ + default: + dev_info(&client->dev, + "Control (id:0x%x, val:0x%x) not supported\n", +@@ -1290,10 +1378,23 @@ static const struct v4l2_ctrl_ops ov5647_ctrl_ops = { + .s_ctrl = ov5647_s_ctrl, + }; + +-static int ov5647_init_controls(struct ov5647 *sensor) ++static int ov5647_configure_regulators(struct device *dev, ++ struct ov5647 *sensor) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < OV5647_NUM_SUPPLIES; i++) ++ sensor->suppliesi.supply = ov5647_supply_namesi; ++ ++ return devm_regulator_bulk_get(dev, OV5647_NUM_SUPPLIES, ++ sensor->supplies); ++} ++ ++static int ov5647_init_controls(struct ov5647 *sensor, struct device *dev) { + struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); + int hblank, exposure_max, exposure_def; + struct v4l2_fwnode_device_properties props; - struct device *dev = &client->dev; - struct fwnode_handle *endpoint; - struct ov7251 *ov7251; -@@ -1330,7 +1331,8 @@ static int ov7251_probe(struct i2c_client *client) - return PTR_ERR(ov7251->analog_regulator); - } -- ov7251->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); -+ ov7251->enable_gpio = devm_gpiod_get_optional(dev, "enable", -+ GPIOD_OUT_HIGH); - if (IS_ERR(ov7251->enable_gpio)) { - dev_err(dev, "cannot get enable gpio\n"); - return PTR_ERR(ov7251->enable_gpio); -@@ -1338,7 +1340,7 @@ static int ov7251_probe(struct i2c_client *client) + v4l2_ctrl_handler_init(&sensor->ctrls, 9); - mutex_init(&ov7251->lock); +@@ -1344,6 +1445,21 @@ static int ov5647_init_controls(struct ov5647 *sensor) + ARRAY_SIZE(ov5647_test_pattern_menu) - 1, + 0, 0, ov5647_test_pattern_menu); -- v4l2_ctrl_handler_init(&ov7251->ctrls, 7); -+ v4l2_ctrl_handler_init(&ov7251->ctrls, 9); - ov7251->ctrls.lock = &ov7251->lock; ++ sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ if (sensor->hflip) ++ sensor->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ if (sensor->vflip) ++ sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ v4l2_fwnode_device_parse(dev, &props); ++ ++ v4l2_ctrl_new_fwnode_properties(&sensor->ctrls, &ov5647_ctrl_ops, ++ &props); ++ + if (sensor->ctrls.error) + goto handler_free; - v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, -@@ -1374,6 +1376,15 @@ static int ov7251_probe(struct i2c_client *client) - goto free_ctrl; +@@ -1426,11 +1542,17 @@ static int ov5647_probe(struct i2c_client *client) + return -EINVAL; } -+ ret = v4l2_fwnode_device_parse(&client->dev, &props); -+ if (ret) -+ goto free_ctrl; -+ -+ ret = v4l2_ctrl_new_fwnode_properties(&ov7251->ctrls, &ov7251_ctrl_ops, -+ &props); -+ if (ret) -+ goto free_ctrl; ++ ret = ov5647_configure_regulators(dev, sensor); ++ if (ret) { ++ dev_err(dev, "Failed to get power regulators\n"); ++ return ret; ++ } + - v4l2_i2c_subdev_init(&ov7251->sd, client, &ov7251_subdev_ops); - ov7251->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - ov7251->pad.flags = MEDIA_PAD_FL_SOURCE; -diff --git a/drivers/media/i2c/ov9281.c b/drivers/media/i2c/ov9281.c + mutex_init(&sensor->lock); + + sensor->mode = OV5647_DEFAULT_MODE; + +- ret = ov5647_init_controls(sensor); ++ ret = ov5647_init_controls(sensor, dev); + if (ret) + goto mutex_destroy; + +@@ -1453,7 +1575,7 @@ static int ov5647_probe(struct i2c_client *client) + if (ret < 0) + goto power_off; + +- ret = v4l2_async_register_subdev(sd); ++ ret = v4l2_async_register_subdev_sensor(sd); + if (ret < 0) + goto power_off; + +diff --git a/drivers/media/i2c/ov64a40.c b/drivers/media/i2c/ov64a40.c new file mode 100644 -index 000000000000..ff1b99e26a20 +index 000000000000..ee75bbf8d8bf --- /dev/null -+++ b/drivers/media/i2c/ov9281.c -@@ -0,0 +1,1294 @@ ++++ b/drivers/media/i2c/ov64a40.c +@@ -0,0 +1,3686 @@ +// 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. ++ * V4L2 sensor driver for OmniVision OV64A40 + * -+ * 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. ++ * Copyright (C) 2023 Ideas On Board Oy ++ * Copyright (C) 2023 Arducam + */ + +#include <linux/clk.h> -+#include <linux/device.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> ++#include <linux/mod_devicetable.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-cci.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> +#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 -+/* -+ * Number of lines less than frame length (VTS) that exposure must be. -+ * Datasheet states 25, although empirically 5 appears to work. -+ */ -+#define OV9281_EXPOSURE_OFFSET 25 -+ -+#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 -+#define OV9281_VTS_MAX 0x7fff -+ -+/* -+ * 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 suppliesOV9281_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) ++#define OV64A40_XCLK_FREQ 24000000 + -+/* -+ * 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}, ++#define OV64A40_NATIVE_WIDTH 9286 ++#define OV64A40_NATIVE_HEIGHT 6976 ++#define OV64A40_PIXEL_ARRAY_TOP 0 ++#define OV64A40_PIXEL_ARRAY_LEFT 0 ++#define OV64A40_PIXEL_ARRAY_WIDTH 9248 ++#define OV64A40_PIXEL_ARRAY_HEIGHT 6944 ++ ++#define OV64A40_PIXEL_RATE 300000000 ++ ++#define OV64A40_LINK_FREQ_360M 360000000 ++#define OV64A40_LINK_FREQ_456M 456000000 ++ ++#define OV64A40_PLL1_PRE_DIV0 CCI_REG8(0x0301) ++#define OV64A40_PLL1_PRE_DIV CCI_REG8(0x0303) ++#define OV64A40_PLL1_MULTIPLIER CCI_REG16(0x0304) ++#define OV64A40_PLL1_M_DIV CCI_REG8(0x0307) ++#define OV64A40_PLL2_SEL_BAK_SA1 CCI_REG8(0x0320) ++#define OV64A40_PLL2_PRE_DIV CCI_REG8(0x0323) ++#define OV64A40_PLL2_MULTIPLIER CCI_REG16(0x0324) ++#define OV64A40_PLL2_PRE_DIV0 CCI_REG8(0x0326) ++#define OV64A40_PLL2_DIVDAC CCI_REG8(0x0329) ++#define OV64A40_PLL2_DIVSP CCI_REG8(0x032d) ++#define OV64A40_PLL2_DACPREDIV CCI_REG8(0x032e) ++ ++/* TODO: validate vblank_min, it's not characterized in the datasheet. */ ++#define OV64A40_VBLANK_MIN 128 ++#define OV64A40_VTS_MAX 0xffffff ++ ++#define OV64A40_REG_MEC_LONG_EXPO CCI_REG24(0x3500) ++#define OV64A40_EXPOSURE_MIN 16 ++#define OV64A40_EXPOSURE_MARGIN 32 ++ ++#define OV64A40_REG_MEC_LONG_GAIN CCI_REG16(0x3508) ++#define OV64A40_ANA_GAIN_MIN 0x80 ++#define OV64A40_ANA_GAIN_MAX 0x7ff ++#define OV64A40_ANA_GAIN_DEFAULT 0x80 ++ ++#define OV64A40_REG_TIMING_CTRL0 CCI_REG16(0x3800) ++#define OV64A40_REG_TIMING_CTRL2 CCI_REG16(0x3802) ++#define OV64A40_REG_TIMING_CTRL4 CCI_REG16(0x3804) ++#define OV64A40_REG_TIMING_CTRL6 CCI_REG16(0x3806) ++#define OV64A40_REG_TIMING_CTRL8 CCI_REG16(0x3808) ++#define OV64A40_REG_TIMING_CTRLA CCI_REG16(0x380a) ++#define OV64A40_REG_TIMING_CTRLC CCI_REG16(0x380c) ++#define OV64A40_REG_TIMING_CTRLE CCI_REG16(0x380e) ++#define OV64A40_REG_TIMING_CTRL10 CCI_REG16(0x3810) ++#define OV64A40_REG_TIMING_CTRL12 CCI_REG16(0x3812) ++ ++/* ++ * Careful: a typo in the datasheet calls this register ++ * OV64A40_REG_TIMING_CTRL20. ++ */ ++#define OV64A40_REG_TIMING_CTRL14 CCI_REG8(0x3814) ++#define OV64A40_REG_TIMING_CTRL15 CCI_REG8(0x3815) ++#define OV64A40_ODD_INC_SHIFT 4 ++#define OV64A40_SKIPPING_CONFIG(_odd, _even) \ ++ (((_odd) << OV64A40_ODD_INC_SHIFT) | (_even)) ++ ++#define OV64A40_REG_TIMING_CTRL_20 CCI_REG8(0x3820) ++#define OV64A40_TIMING_CTRL_20_VFLIP BIT(2) ++#define OV64A40_TIMING_CTRL_20_VBIN BIT(1) ++ ++#define OV64A40_REG_TIMING_CTRL_21 CCI_REG8(0x3821) ++#define OV64A40_TIMING_CTRL_21_HBIN BIT(4) ++#define OV64A40_TIMING_CTRL_21_HFLIP BIT(2) ++#define OV64A40_TIMING_CTRL_21_DSPEED BIT(0) ++#define OV64A40_TIMING_CTRL_21_HBIN_CONF \ ++ (OV64A40_TIMING_CTRL_21_HBIN | \ ++ OV64A40_TIMING_CTRL_21_DSPEED) ++ ++#define OV64A40_REG_TIMINGS_VTS_HIGH CCI_REG8(0x3840) ++#define OV64A40_REG_TIMINGS_VTS_MID CCI_REG8(0x380e) ++#define OV64A40_REG_TIMINGS_VTS_LOW CCI_REG8(0x380f) ++ ++/* The test pattern control is weirdly named PRE_ISP_2325_D2V2_TOP_1 in TRM. */ ++#define OV64A40_REG_TEST_PATTERN CCI_REG8(0x50c1) ++#define OV64A40_TEST_PATTERN_DISABLED 0x00 ++#define OV64A40_TEST_PATTERN_TYPE1 BIT(0) ++#define OV64A40_TEST_PATTERN_TYPE2 (BIT(4) | BIT(0)) ++#define OV64A40_TEST_PATTERN_TYPE3 (BIT(5) | BIT(0)) ++#define OV64A40_TEST_PATTERN_TYPE4 (BIT(5) | BIT(4) | BIT(0)) ++ ++#define OV64A40_REG_CHIP_ID CCI_REG24(0x300a) ++#define OV64A40_CHIP_ID 0x566441 ++ ++#define OV64A40_REG_SMIA CCI_REG8(0x0100) ++#define OV64A40_REG_SMIA_STREAMING BIT(0) ++ ++enum ov64a40_link_freq_ids { ++ OV64A40_LINK_FREQ_456M_ID, ++ OV64A40_LINK_FREQ_360M_ID, ++ OV64A40_NUM_LINK_FREQ, +}; + -+static const 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 char * const ov64a40_supply_names = { ++ /* Supplies can be enabled in any order */ ++ "avdd", /* Analog (2.8V) supply */ ++ "dovdd", /* Digital Core (1.8V) supply */ ++ "dvdd", /* IF (1.1V) supply */ +}; + -+static const 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 char * const ov64a40_test_pattern_menu = { ++ "Disabled", ++ "Type1", ++ "Type2", ++ "Type3", ++ "Type4", +}; + -+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 int ov64a40_test_pattern_val = { ++ OV64A40_TEST_PATTERN_DISABLED, ++ OV64A40_TEST_PATTERN_TYPE1, ++ OV64A40_TEST_PATTERN_TYPE2, ++ OV64A40_TEST_PATTERN_TYPE3, ++ OV64A40_TEST_PATTERN_TYPE4, +}; + -+static const struct regval op_10bit = { -+ {0x030d, 0x50}, -+ {0x3662, 0x05}, -+ {REG_NULL, 0x00}, ++static const unsigned int ov64a40_mbus_codes = { ++ MEDIA_BUS_FMT_SBGGR10_1X10, ++ MEDIA_BUS_FMT_SGRBG10_1X10, ++ MEDIA_BUS_FMT_SGBRG10_1X10, ++ MEDIA_BUS_FMT_SRGGB10_1X10, +}; + -+static const struct regval op_8bit = { -+ {0x030d, 0x60}, -+ {0x3662, 0x07}, -+ {REG_NULL, 0x00}, ++static const struct cci_reg_sequence ov64a40_init = { ++ { CCI_REG8(0x0103), 0x01 }, { CCI_REG8(0x0301), 0x88 }, ++ { CCI_REG8(0x0304), 0x00 }, { CCI_REG8(0x0305), 0x96 }, ++ { CCI_REG8(0x0306), 0x03 }, { CCI_REG8(0x0307), 0x00 }, ++ { CCI_REG8(0x0345), 0x2c }, { CCI_REG8(0x034a), 0x02 }, ++ { CCI_REG8(0x034b), 0x02 }, { CCI_REG8(0x0350), 0xc0 }, ++ { CCI_REG8(0x0360), 0x09 }, { CCI_REG8(0x3012), 0x31 }, ++ { CCI_REG8(0x3015), 0xf0 }, { CCI_REG8(0x3017), 0xf0 }, ++ { CCI_REG8(0x301d), 0xf6 }, { CCI_REG8(0x301e), 0xf1 }, ++ { CCI_REG8(0x3022), 0xf0 }, { CCI_REG8(0x3400), 0x08 }, ++ { CCI_REG8(0x3608), 0x41 }, { CCI_REG8(0x3421), 0x02 }, ++ { CCI_REG8(0x3500), 0x00 }, { CCI_REG8(0x3501), 0x00 }, ++ { CCI_REG8(0x3502), 0x18 }, { CCI_REG8(0x3504), 0x0c }, ++ { CCI_REG8(0x3508), 0x01 }, { CCI_REG8(0x3509), 0x00 }, ++ { CCI_REG8(0x350a), 0x01 }, { CCI_REG8(0x350b), 0x00 }, ++ { CCI_REG8(0x350b), 0x00 }, { CCI_REG8(0x3540), 0x00 }, ++ { CCI_REG8(0x3541), 0x00 }, { CCI_REG8(0x3542), 0x08 }, ++ { CCI_REG8(0x3548), 0x01 }, { CCI_REG8(0x3549), 0xa0 }, ++ { CCI_REG8(0x3549), 0x00 }, { CCI_REG8(0x3549), 0x00 }, ++ { CCI_REG8(0x3549), 0x00 }, { CCI_REG8(0x3580), 0x00 }, ++ { CCI_REG8(0x3581), 0x00 }, { CCI_REG8(0x3582), 0x04 }, ++ { CCI_REG8(0x3588), 0x01 }, { CCI_REG8(0x3589), 0xf0 }, ++ { CCI_REG8(0x3589), 0x00 }, { CCI_REG8(0x3589), 0x00 }, ++ { CCI_REG8(0x3589), 0x00 }, { CCI_REG8(0x360d), 0x83 }, ++ { CCI_REG8(0x3616), 0xa0 }, { CCI_REG8(0x3617), 0x31 }, ++ { CCI_REG8(0x3623), 0x10 }, { CCI_REG8(0x3633), 0x03 }, ++ { CCI_REG8(0x3634), 0x03 }, { CCI_REG8(0x3635), 0x77 }, ++ { CCI_REG8(0x3640), 0x19 }, { CCI_REG8(0x3641), 0x80 }, ++ { CCI_REG8(0x364d), 0x0f }, { CCI_REG8(0x3680), 0x80 }, ++ { CCI_REG8(0x3682), 0x00 }, { CCI_REG8(0x3683), 0x00 }, ++ { CCI_REG8(0x3684), 0x07 }, { CCI_REG8(0x3688), 0x01 }, ++ { CCI_REG8(0x3689), 0x08 }, { CCI_REG8(0x368a), 0x26 }, ++ { CCI_REG8(0x368b), 0xc8 }, { CCI_REG8(0x368e), 0x70 }, ++ { CCI_REG8(0x368f), 0x00 }, { CCI_REG8(0x3692), 0x04 }, ++ { CCI_REG8(0x3693), 0x00 }, { CCI_REG8(0x3696), 0xd1 }, ++ { CCI_REG8(0x3697), 0xe0 }, { CCI_REG8(0x3698), 0x80 }, ++ { CCI_REG8(0x3699), 0x2b }, { CCI_REG8(0x369a), 0x00 }, ++ { CCI_REG8(0x369d), 0x00 }, { CCI_REG8(0x369e), 0x14 }, ++ { CCI_REG8(0x369f), 0x20 }, { CCI_REG8(0x36a5), 0x80 }, ++ { CCI_REG8(0x36a6), 0x00 }, { CCI_REG8(0x36a7), 0x00 }, ++ { CCI_REG8(0x36a8), 0x00 }, { CCI_REG8(0x36b5), 0x17 }, ++ { CCI_REG8(0x3701), 0x30 }, { CCI_REG8(0x3706), 0x2b }, ++ { CCI_REG8(0x3709), 0x8d }, { CCI_REG8(0x370b), 0x4f }, ++ { CCI_REG8(0x3711), 0x00 }, { CCI_REG8(0x3712), 0x01 }, ++ { CCI_REG8(0x3713), 0x00 }, { CCI_REG8(0x3720), 0x08 }, ++ { CCI_REG8(0x3727), 0x22 }, { CCI_REG8(0x3728), 0x01 }, ++ { CCI_REG8(0x375e), 0x00 }, { CCI_REG8(0x3760), 0x08 }, ++ { CCI_REG8(0x3761), 0x10 }, { CCI_REG8(0x3762), 0x08 }, ++ { CCI_REG8(0x3765), 0x10 }, { CCI_REG8(0x3766), 0x18 }, ++ { CCI_REG8(0x376a), 0x08 }, { CCI_REG8(0x376b), 0x00 }, ++ { CCI_REG8(0x376d), 0x1b }, { CCI_REG8(0x3791), 0x2b }, ++ { CCI_REG8(0x3793), 0x2b }, { CCI_REG8(0x3795), 0x2b }, ++ { CCI_REG8(0x3797), 0x4f }, { CCI_REG8(0x3799), 0x4f }, ++ { CCI_REG8(0x379b), 0x4f }, { CCI_REG8(0x37a0), 0x22 }, ++ { CCI_REG8(0x37da), 0x04 }, { CCI_REG8(0x37f9), 0x02 }, ++ { CCI_REG8(0x37fa), 0x02 }, { CCI_REG8(0x37fb), 0x02 }, ++ { CCI_REG8(0x3814), 0x11 }, { CCI_REG8(0x3815), 0x11 }, ++ { CCI_REG8(0x3820), 0x40 }, { CCI_REG8(0x3821), 0x04 }, ++ { CCI_REG8(0x3822), 0x00 }, { CCI_REG8(0x3823), 0x04 }, ++ { CCI_REG8(0x3827), 0x08 }, { CCI_REG8(0x3828), 0x00 }, ++ { CCI_REG8(0x382a), 0x81 }, { CCI_REG8(0x382e), 0x70 }, ++ { CCI_REG8(0x3837), 0x10 }, { CCI_REG8(0x3839), 0x00 }, ++ { CCI_REG8(0x383b), 0x00 }, { CCI_REG8(0x383c), 0x00 }, ++ { CCI_REG8(0x383d), 0x10 }, { CCI_REG8(0x383f), 0x00 }, ++ { CCI_REG8(0x384c), 0x02 }, { CCI_REG8(0x384d), 0x8c }, ++ { CCI_REG8(0x3852), 0x00 }, { CCI_REG8(0x3856), 0x10 }, ++ { CCI_REG8(0x3857), 0x10 }, { CCI_REG8(0x3858), 0x20 }, ++ { CCI_REG8(0x3859), 0x20 }, { CCI_REG8(0x3894), 0x00 }, ++ { CCI_REG8(0x3895), 0x00 }, { CCI_REG8(0x3896), 0x00 }, ++ { CCI_REG8(0x3897), 0x00 }, { CCI_REG8(0x3900), 0x40 }, ++ { CCI_REG8(0x3aed), 0x6e }, { CCI_REG8(0x3af1), 0x73 }, ++ { CCI_REG8(0x3d86), 0x12 }, { CCI_REG8(0x3d87), 0x30 }, ++ { CCI_REG8(0x3d8c), 0xab }, { CCI_REG8(0x3d8d), 0xb0 }, ++ { CCI_REG8(0x3f00), 0x12 }, { CCI_REG8(0x3f00), 0x12 }, ++ { CCI_REG8(0x3f00), 0x12 }, { CCI_REG8(0x3f01), 0x03 }, ++ { CCI_REG8(0x4009), 0x01 }, { CCI_REG8(0x400e), 0xc6 }, ++ { CCI_REG8(0x400f), 0x00 }, { CCI_REG8(0x4010), 0x28 }, ++ { CCI_REG8(0x4011), 0x01 }, { CCI_REG8(0x4012), 0x0c }, ++ { CCI_REG8(0x4015), 0x00 }, { CCI_REG8(0x4016), 0x1f }, ++ { CCI_REG8(0x4017), 0x00 }, { CCI_REG8(0x4018), 0x07 }, ++ { CCI_REG8(0x401a), 0x40 }, { CCI_REG8(0x4028), 0x01 }, ++ { CCI_REG8(0x4504), 0x00 }, { CCI_REG8(0x4506), 0x01 }, ++ { CCI_REG8(0x4508), 0x00 }, { CCI_REG8(0x4509), 0x35 }, ++ { CCI_REG8(0x450a), 0x08 }, { CCI_REG8(0x450c), 0x00 }, ++ { CCI_REG8(0x450d), 0x20 }, { CCI_REG8(0x450e), 0x00 }, ++ { CCI_REG8(0x450f), 0x20 }, { CCI_REG8(0x451e), 0x00 }, ++ { CCI_REG8(0x451f), 0x00 }, { CCI_REG8(0x4523), 0x00 }, ++ { CCI_REG8(0x4526), 0x00 }, { CCI_REG8(0x4527), 0x18 }, ++ { CCI_REG8(0x4580), 0x01 }, { CCI_REG8(0x4583), 0x00 }, ++ { CCI_REG8(0x4584), 0x00 }, { CCI_REG8(0x45c0), 0xa1 }, ++ { CCI_REG8(0x4602), 0x08 }, { CCI_REG8(0x4603), 0x05 }, ++ { CCI_REG8(0x4606), 0x12 }, { CCI_REG8(0x4607), 0x30 }, ++ { CCI_REG8(0x460b), 0x00 }, { CCI_REG8(0x460d), 0x00 }, ++ { CCI_REG8(0x4640), 0x00 }, { CCI_REG8(0x4641), 0x24 }, ++ { CCI_REG8(0x4643), 0x08 }, { CCI_REG8(0x4645), 0x14 }, ++ { CCI_REG8(0x4648), 0x0a }, { CCI_REG8(0x4649), 0x06 }, ++ { CCI_REG8(0x464a), 0x00 }, { CCI_REG8(0x464b), 0x30 }, ++ { CCI_REG8(0x4800), 0x04 }, { CCI_REG8(0x4802), 0x02 }, ++ { CCI_REG8(0x480b), 0x10 }, { CCI_REG8(0x480c), 0x80 }, ++ { CCI_REG8(0x480e), 0x04 }, { CCI_REG8(0x480f), 0x32 }, ++ { CCI_REG8(0x481b), 0x12 }, { CCI_REG8(0x4833), 0x30 }, ++ { CCI_REG8(0x4837), 0x08 }, { CCI_REG8(0x484b), 0x27 }, ++ { CCI_REG8(0x4850), 0x42 }, { CCI_REG8(0x4851), 0xaa }, ++ { CCI_REG8(0x4860), 0x01 }, { CCI_REG8(0x4861), 0xec }, ++ { CCI_REG8(0x4862), 0x25 }, { CCI_REG8(0x4888), 0x00 }, ++ { CCI_REG8(0x4889), 0x03 }, { CCI_REG8(0x488c), 0x60 }, ++ { CCI_REG8(0x4910), 0x28 }, { CCI_REG8(0x4911), 0x01 }, ++ { CCI_REG8(0x4912), 0x0c }, { CCI_REG8(0x491a), 0x40 }, ++ { CCI_REG8(0x4915), 0x00 }, { CCI_REG8(0x4916), 0x0f }, ++ { CCI_REG8(0x4917), 0x00 }, { CCI_REG8(0x4918), 0x07 }, ++ { CCI_REG8(0x4a10), 0x28 }, { CCI_REG8(0x4a11), 0x01 }, ++ { CCI_REG8(0x4a12), 0x0c }, { CCI_REG8(0x4a1a), 0x40 }, ++ { CCI_REG8(0x4a15), 0x00 }, { CCI_REG8(0x4a16), 0x0f }, ++ { CCI_REG8(0x4a17), 0x00 }, { CCI_REG8(0x4a18), 0x07 }, ++ { CCI_REG8(0x4d00), 0x04 }, { CCI_REG8(0x4d01), 0x5a }, ++ { CCI_REG8(0x4d02), 0xbb }, { CCI_REG8(0x4d03), 0x84 }, ++ { CCI_REG8(0x4d04), 0xd1 }, { CCI_REG8(0x4d05), 0x68 }, ++ { CCI_REG8(0xc4fa), 0x10 }, { CCI_REG8(0x3b56), 0x0a }, ++ { CCI_REG8(0x3b57), 0x0a }, { CCI_REG8(0x3b58), 0x0c }, ++ { CCI_REG8(0x3b59), 0x10 }, { CCI_REG8(0x3a1d), 0x30 }, ++ { CCI_REG8(0x3a1e), 0x30 }, { CCI_REG8(0x3a21), 0x30 }, ++ { CCI_REG8(0x3a22), 0x30 }, { CCI_REG8(0x3992), 0x02 }, ++ { CCI_REG8(0x399e), 0x02 }, { CCI_REG8(0x39fb), 0x30 }, ++ { CCI_REG8(0x39fc), 0x30 }, { CCI_REG8(0x39fd), 0x30 }, ++ { CCI_REG8(0x39fe), 0x30 }, { CCI_REG8(0x3a6d), 0x83 }, ++ { CCI_REG8(0x3a5e), 0x83 }, { CCI_REG8(0xc500), 0x12 }, ++ { CCI_REG8(0xc501), 0x12 }, { CCI_REG8(0xc502), 0x12 }, ++ { CCI_REG8(0xc503), 0x12 }, { CCI_REG8(0xc505), 0x12 }, ++ { CCI_REG8(0xc506), 0x12 }, { CCI_REG8(0xc507), 0x12 }, ++ { CCI_REG8(0xc508), 0x12 }, { CCI_REG8(0x3a77), 0x12 }, ++ { CCI_REG8(0x3a73), 0x12 }, { CCI_REG8(0x3a7b), 0x12 }, ++ { CCI_REG8(0x3a7f), 0x12 }, { CCI_REG8(0x3b2e), 0x13 }, ++ { CCI_REG8(0x3b29), 0x13 }, { CCI_REG8(0xc439), 0x13 }, ++ { CCI_REG8(0xc469), 0x13 }, { CCI_REG8(0xc41c), 0x89 }, ++ { CCI_REG8(0x3618), 0x80 }, { CCI_REG8(0xc514), 0x51 }, ++ { CCI_REG8(0xc515), 0x2c }, { CCI_REG8(0xc516), 0x16 }, ++ { CCI_REG8(0xc517), 0x0d }, { CCI_REG8(0x3615), 0x7f }, ++ { CCI_REG8(0x3632), 0x99 }, { CCI_REG8(0x3642), 0x00 }, ++ { CCI_REG8(0x3645), 0x80 }, { CCI_REG8(0x3702), 0x2a }, ++ { CCI_REG8(0x3703), 0x2a }, { CCI_REG8(0x3708), 0x2f }, ++ { CCI_REG8(0x3721), 0x15 }, { CCI_REG8(0x3744), 0x28 }, ++ { CCI_REG8(0x3991), 0x0c }, { CCI_REG8(0x371d), 0x24 }, ++ { CCI_REG8(0x371f), 0x0c }, { CCI_REG8(0x374b), 0x03 }, ++ { CCI_REG8(0x37d0), 0x00 }, { CCI_REG8(0x391d), 0x55 }, ++ { CCI_REG8(0x391e), 0x52 }, { CCI_REG8(0x399d), 0x0c }, ++ { CCI_REG8(0x3a2f), 0x01 }, { CCI_REG8(0x3a30), 0x01 }, ++ { CCI_REG8(0x3a31), 0x01 }, { CCI_REG8(0x3a32), 0x01 }, ++ { CCI_REG8(0x3a34), 0x01 }, { CCI_REG8(0x3a35), 0x01 }, ++ { CCI_REG8(0x3a36), 0x01 }, { CCI_REG8(0x3a37), 0x01 }, ++ { CCI_REG8(0x3a43), 0x01 }, { CCI_REG8(0x3a44), 0x01 }, ++ { CCI_REG8(0x3a45), 0x01 }, { CCI_REG8(0x3a46), 0x01 }, ++ { CCI_REG8(0x3a48), 0x01 }, { CCI_REG8(0x3a49), 0x01 }, ++ { CCI_REG8(0x3a4a), 0x01 }, { CCI_REG8(0x3a4b), 0x01 }, ++ { CCI_REG8(0x3a50), 0x14 }, { CCI_REG8(0x3a54), 0x14 }, ++ { CCI_REG8(0x3a60), 0x20 }, { CCI_REG8(0x3a6f), 0x20 }, ++ { CCI_REG8(0x3ac5), 0x01 }, { CCI_REG8(0x3ac6), 0x01 }, ++ { CCI_REG8(0x3ac7), 0x01 }, { CCI_REG8(0x3ac8), 0x01 }, ++ { CCI_REG8(0x3ac9), 0x01 }, { CCI_REG8(0x3aca), 0x01 }, ++ { CCI_REG8(0x3acb), 0x01 }, { CCI_REG8(0x3acc), 0x01 }, ++ { CCI_REG8(0x3acd), 0x01 }, { CCI_REG8(0x3ace), 0x01 }, ++ { CCI_REG8(0x3acf), 0x01 }, { CCI_REG8(0x3ad0), 0x01 }, ++ { CCI_REG8(0x3ad1), 0x01 }, { CCI_REG8(0x3ad2), 0x01 }, ++ { CCI_REG8(0x3ad3), 0x01 }, { CCI_REG8(0x3ad4), 0x01 }, ++ { CCI_REG8(0x3add), 0x1f }, { CCI_REG8(0x3adf), 0x24 }, ++ { CCI_REG8(0x3aef), 0x1f }, { CCI_REG8(0x3af0), 0x24 }, ++ { CCI_REG8(0x3b92), 0x08 }, { CCI_REG8(0x3b93), 0x08 }, ++ { CCI_REG8(0x3b94), 0x08 }, { CCI_REG8(0x3b95), 0x08 }, ++ { CCI_REG8(0x3be7), 0x1e }, { CCI_REG8(0x3be8), 0x26 }, ++ { CCI_REG8(0xc44a), 0x20 }, { CCI_REG8(0xc44c), 0x20 }, ++ { CCI_REG8(0xc483), 0x00 }, { CCI_REG8(0xc484), 0x00 }, ++ { CCI_REG8(0xc485), 0x00 }, { CCI_REG8(0xc486), 0x00 }, ++ { CCI_REG8(0xc487), 0x01 }, { CCI_REG8(0xc488), 0x01 }, ++ { CCI_REG8(0xc489), 0x01 }, { CCI_REG8(0xc48a), 0x01 }, ++ { CCI_REG8(0xc4c1), 0x00 }, { CCI_REG8(0xc4c2), 0x00 }, ++ { CCI_REG8(0xc4c3), 0x00 }, { CCI_REG8(0xc4c4), 0x00 }, ++ { CCI_REG8(0xc4c6), 0x10 }, { CCI_REG8(0xc4c7), 0x10 }, ++ { CCI_REG8(0xc4c8), 0x10 }, { CCI_REG8(0xc4c9), 0x10 }, ++ { CCI_REG8(0xc4ca), 0x10 }, { CCI_REG8(0xc4cb), 0x10 }, ++ { CCI_REG8(0xc4cc), 0x10 }, { CCI_REG8(0xc4cd), 0x10 }, ++ { CCI_REG8(0xc4ea), 0x07 }, { CCI_REG8(0xc4eb), 0x07 }, ++ { CCI_REG8(0xc4ec), 0x07 }, { CCI_REG8(0xc4ed), 0x07 }, ++ { CCI_REG8(0xc4ee), 0x07 }, { CCI_REG8(0xc4f6), 0x10 }, ++ { CCI_REG8(0xc4f7), 0x10 }, { CCI_REG8(0xc4f8), 0x10 }, ++ { CCI_REG8(0xc4f9), 0x10 }, { CCI_REG8(0xc518), 0x0e }, ++ { CCI_REG8(0xc519), 0x0e }, { CCI_REG8(0xc51a), 0x0e }, ++ { CCI_REG8(0xc51b), 0x0e }, { CCI_REG8(0xc51c), 0x0e }, ++ { CCI_REG8(0xc51d), 0x0e }, { CCI_REG8(0xc51e), 0x0e }, ++ { CCI_REG8(0xc51f), 0x0e }, { CCI_REG8(0xc520), 0x0e }, ++ { CCI_REG8(0xc521), 0x0e }, { CCI_REG8(0xc522), 0x0e }, ++ { CCI_REG8(0xc523), 0x0e }, { CCI_REG8(0xc524), 0x0e }, ++ { CCI_REG8(0xc525), 0x0e }, { CCI_REG8(0xc526), 0x0e }, ++ { CCI_REG8(0xc527), 0x0e }, { CCI_REG8(0xc528), 0x0e }, ++ { CCI_REG8(0xc529), 0x0e }, { CCI_REG8(0xc52a), 0x0e }, ++ { CCI_REG8(0xc52b), 0x0e }, { CCI_REG8(0xc52c), 0x0e }, ++ { CCI_REG8(0xc52d), 0x0e }, { CCI_REG8(0xc52e), 0x0e }, ++ { CCI_REG8(0xc52f), 0x0e }, { CCI_REG8(0xc530), 0x0e }, ++ { CCI_REG8(0xc531), 0x0e }, { CCI_REG8(0xc532), 0x0e }, ++ { CCI_REG8(0xc533), 0x0e }, { CCI_REG8(0xc534), 0x0e }, ++ { CCI_REG8(0xc535), 0x0e }, { CCI_REG8(0xc536), 0x0e }, ++ { CCI_REG8(0xc537), 0x0e }, { CCI_REG8(0xc538), 0x0e }, ++ { CCI_REG8(0xc539), 0x0e }, { CCI_REG8(0xc53a), 0x0e }, ++ { CCI_REG8(0xc53b), 0x0e }, { CCI_REG8(0xc53c), 0x0e }, ++ { CCI_REG8(0xc53d), 0x0e }, { CCI_REG8(0xc53e), 0x0e }, ++ { CCI_REG8(0xc53f), 0x0e }, { CCI_REG8(0xc540), 0x0e }, ++ { CCI_REG8(0xc541), 0x0e }, { CCI_REG8(0xc542), 0x0e }, ++ { CCI_REG8(0xc543), 0x0e }, { CCI_REG8(0xc544), 0x0e }, ++ { CCI_REG8(0xc545), 0x0e }, { CCI_REG8(0xc546), 0x0e }, ++ { CCI_REG8(0xc547), 0x0e }, { CCI_REG8(0xc548), 0x0e }, ++ { CCI_REG8(0xc549), 0x0e }, { CCI_REG8(0xc57f), 0x22 }, ++ { CCI_REG8(0xc580), 0x22 }, { CCI_REG8(0xc581), 0x22 }, ++ { CCI_REG8(0xc582), 0x22 }, { CCI_REG8(0xc583), 0x22 }, ++ { CCI_REG8(0xc584), 0x22 }, { CCI_REG8(0xc585), 0x22 }, ++ { CCI_REG8(0xc586), 0x22 }, { CCI_REG8(0xc587), 0x22 }, ++ { CCI_REG8(0xc588), 0x22 }, { CCI_REG8(0xc589), 0x22 }, ++ { CCI_REG8(0xc58a), 0x22 }, { CCI_REG8(0xc58b), 0x22 }, ++ { CCI_REG8(0xc58c), 0x22 }, { CCI_REG8(0xc58d), 0x22 }, ++ { CCI_REG8(0xc58e), 0x22 }, { CCI_REG8(0xc58f), 0x22 }, ++ { CCI_REG8(0xc590), 0x22 }, { CCI_REG8(0xc591), 0x22 }, ++ { CCI_REG8(0xc592), 0x22 }, { CCI_REG8(0xc598), 0x22 }, ++ { CCI_REG8(0xc599), 0x22 }, { CCI_REG8(0xc59a), 0x22 }, ++ { CCI_REG8(0xc59b), 0x22 }, { CCI_REG8(0xc59c), 0x22 }, ++ { CCI_REG8(0xc59d), 0x22 }, { CCI_REG8(0xc59e), 0x22 }, ++ { CCI_REG8(0xc59f), 0x22 }, { CCI_REG8(0xc5a0), 0x22 }, ++ { CCI_REG8(0xc5a1), 0x22 }, { CCI_REG8(0xc5a2), 0x22 }, ++ { CCI_REG8(0xc5a3), 0x22 }, { CCI_REG8(0xc5a4), 0x22 }, ++ { CCI_REG8(0xc5a5), 0x22 }, { CCI_REG8(0xc5a6), 0x22 }, ++ { CCI_REG8(0xc5a7), 0x22 }, { CCI_REG8(0xc5a8), 0x22 }, ++ { CCI_REG8(0xc5a9), 0x22 }, { CCI_REG8(0xc5aa), 0x22 }, ++ { CCI_REG8(0xc5ab), 0x22 }, { CCI_REG8(0xc5b1), 0x2a }, ++ { CCI_REG8(0xc5b2), 0x2a }, { CCI_REG8(0xc5b3), 0x2a }, ++ { CCI_REG8(0xc5b4), 0x2a }, { CCI_REG8(0xc5b5), 0x2a }, ++ { CCI_REG8(0xc5b6), 0x2a }, { CCI_REG8(0xc5b7), 0x2a }, ++ { CCI_REG8(0xc5b8), 0x2a }, { CCI_REG8(0xc5b9), 0x2a }, ++ { CCI_REG8(0xc5ba), 0x2a }, { CCI_REG8(0xc5bb), 0x2a }, ++ { CCI_REG8(0xc5bc), 0x2a }, { CCI_REG8(0xc5bd), 0x2a }, ++ { CCI_REG8(0xc5be), 0x2a }, { CCI_REG8(0xc5bf), 0x2a }, ++ { CCI_REG8(0xc5c0), 0x2a }, { CCI_REG8(0xc5c1), 0x2a }, ++ { CCI_REG8(0xc5c2), 0x2a }, { CCI_REG8(0xc5c3), 0x2a }, ++ { CCI_REG8(0xc5c4), 0x2a }, { CCI_REG8(0xc5ca), 0x2a }, ++ { CCI_REG8(0xc5cb), 0x2a }, { CCI_REG8(0xc5cc), 0x2a }, ++ { CCI_REG8(0xc5cd), 0x2a }, { CCI_REG8(0xc5ce), 0x2a }, ++ { CCI_REG8(0xc5cf), 0x2a }, { CCI_REG8(0xc5d0), 0x2a }, ++ { CCI_REG8(0xc5d1), 0x2a }, { CCI_REG8(0xc5d2), 0x2a }, ++ { CCI_REG8(0xc5d3), 0x2a }, { CCI_REG8(0xc5d4), 0x2a }, ++ { CCI_REG8(0xc5d5), 0x2a }, { CCI_REG8(0xc5d6), 0x2a }, ++ { CCI_REG8(0xc5d7), 0x2a }, { CCI_REG8(0xc5d8), 0x2a }, ++ { CCI_REG8(0xc5d9), 0x2a }, { CCI_REG8(0xc5da), 0x2a }, ++ { CCI_REG8(0xc5db), 0x2a }, { CCI_REG8(0xc5dc), 0x2a }, ++ { CCI_REG8(0xc5dd), 0x2a }, { CCI_REG8(0xc5e8), 0x22 }, ++ { CCI_REG8(0xc5ea), 0x22 }, { CCI_REG8(0x4540), 0x12 }, ++ { CCI_REG8(0x4541), 0x30 }, { CCI_REG8(0x3d86), 0x12 }, ++ { CCI_REG8(0x3d87), 0x30 }, { CCI_REG8(0x4606), 0x12 }, ++ { CCI_REG8(0x4607), 0x30 }, { CCI_REG8(0x4648), 0x0a }, ++ { CCI_REG8(0x4649), 0x06 }, { CCI_REG8(0x3220), 0x12 }, ++ { CCI_REG8(0x3221), 0x30 }, { CCI_REG8(0x40c2), 0x12 }, ++ { CCI_REG8(0x49c2), 0x12 }, { CCI_REG8(0x4ac2), 0x12 }, ++ { CCI_REG8(0x40c3), 0x30 }, { CCI_REG8(0x49c3), 0x30 }, ++ { CCI_REG8(0x4ac3), 0x30 }, { CCI_REG8(0x36b0), 0x12 }, ++ { CCI_REG8(0x36b1), 0x30 }, { CCI_REG8(0x45cb), 0x12 }, ++ { CCI_REG8(0x45cc), 0x30 }, { CCI_REG8(0x4585), 0x12 }, ++ { CCI_REG8(0x4586), 0x30 }, { CCI_REG8(0x36b2), 0x12 }, ++ { CCI_REG8(0x36b3), 0x30 }, { CCI_REG8(0x5a40), 0x75 }, ++ { CCI_REG8(0x5a41), 0x75 }, { CCI_REG8(0x5a42), 0x75 }, ++ { CCI_REG8(0x5a43), 0x75 }, { CCI_REG8(0x5a44), 0x75 }, ++ { CCI_REG8(0x5a45), 0x75 }, { CCI_REG8(0x5a46), 0x75 }, ++ { CCI_REG8(0x5a47), 0x75 }, { CCI_REG8(0x5a48), 0x75 }, ++ { CCI_REG8(0x5a49), 0x75 }, { CCI_REG8(0x5a4a), 0x75 }, ++ { CCI_REG8(0x5a4b), 0x75 }, { CCI_REG8(0x5a4c), 0x75 }, ++ { CCI_REG8(0x5a4d), 0x75 }, { CCI_REG8(0x5a4e), 0x75 }, ++ { CCI_REG8(0x5a4f), 0x75 }, { CCI_REG8(0x5a50), 0x75 }, ++ { CCI_REG8(0x5a51), 0x75 }, { CCI_REG8(0x5a52), 0x75 }, ++ { CCI_REG8(0x5a53), 0x75 }, { CCI_REG8(0x5a54), 0x75 }, ++ { CCI_REG8(0x5a55), 0x75 }, { CCI_REG8(0x5a56), 0x75 }, ++ { CCI_REG8(0x5a57), 0x75 }, { CCI_REG8(0x5a58), 0x75 }, ++ { CCI_REG8(0x5a59), 0x75 }, { CCI_REG8(0x5a5a), 0x75 }, ++ { CCI_REG8(0x5a5b), 0x75 }, { CCI_REG8(0x5a5c), 0x75 }, ++ { CCI_REG8(0x5a5d), 0x75 }, { CCI_REG8(0x5a5e), 0x75 }, ++ { CCI_REG8(0x5a5f), 0x75 }, { CCI_REG8(0x5a60), 0x75 }, ++ { CCI_REG8(0x5a61), 0x75 }, { CCI_REG8(0x5a62), 0x75 }, ++ { CCI_REG8(0x5a63), 0x75 }, { CCI_REG8(0x5a64), 0x75 }, ++ { CCI_REG8(0x5a65), 0x75 }, { CCI_REG8(0x5a66), 0x75 }, ++ { CCI_REG8(0x5a67), 0x75 }, { CCI_REG8(0x5a68), 0x75 }, ++ { CCI_REG8(0x5a69), 0x75 }, { CCI_REG8(0x5a6a), 0x75 }, ++ { CCI_REG8(0x5a6b), 0x75 }, { CCI_REG8(0x5a6c), 0x75 }, ++ { CCI_REG8(0x5a6d), 0x75 }, { CCI_REG8(0x5a6e), 0x75 }, ++ { CCI_REG8(0x5a6f), 0x75 }, { CCI_REG8(0x5a70), 0x75 }, ++ { CCI_REG8(0x5a71), 0x75 }, { CCI_REG8(0x5a72), 0x75 }, ++ { CCI_REG8(0x5a73), 0x75 }, { CCI_REG8(0x5a74), 0x75 }, ++ { CCI_REG8(0x5a75), 0x75 }, { CCI_REG8(0x5a76), 0x75 }, ++ { CCI_REG8(0x5a77), 0x75 }, { CCI_REG8(0x5a78), 0x75 }, ++ { CCI_REG8(0x5a79), 0x75 }, { CCI_REG8(0x5a7a), 0x75 }, ++ { CCI_REG8(0x5a7b), 0x75 }, { CCI_REG8(0x5a7c), 0x75 }, ++ { CCI_REG8(0x5a7d), 0x75 }, { CCI_REG8(0x5a7e), 0x75 }, ++ { CCI_REG8(0x5a7f), 0x75 }, { CCI_REG8(0x5a80), 0x75 }, ++ { CCI_REG8(0x5a81), 0x75 }, { CCI_REG8(0x5a82), 0x75 }, ++ { CCI_REG8(0x5a83), 0x75 }, { CCI_REG8(0x5a84), 0x75 }, ++ { CCI_REG8(0x5a85), 0x75 }, { CCI_REG8(0x5a86), 0x75 }, ++ { CCI_REG8(0x5a87), 0x75 }, { CCI_REG8(0x5a88), 0x75 }, ++ { CCI_REG8(0x5a89), 0x75 }, { CCI_REG8(0x5a8a), 0x75 }, ++ { CCI_REG8(0x5a8b), 0x75 }, { CCI_REG8(0x5a8c), 0x75 }, ++ { CCI_REG8(0x5a8d), 0x75 }, { CCI_REG8(0x5a8e), 0x75 }, ++ { CCI_REG8(0x5a8f), 0x75 }, { CCI_REG8(0x5a90), 0x75 }, ++ { CCI_REG8(0x5a91), 0x75 }, { CCI_REG8(0x5a92), 0x75 }, ++ { CCI_REG8(0x5a93), 0x75 }, { CCI_REG8(0x5a94), 0x75 }, ++ { CCI_REG8(0x5a95), 0x75 }, { CCI_REG8(0x5a96), 0x75 }, ++ { CCI_REG8(0x5a97), 0x75 }, { CCI_REG8(0x5a98), 0x75 }, ++ { CCI_REG8(0x5a99), 0x75 }, { CCI_REG8(0x5a9a), 0x75 }, ++ { CCI_REG8(0x5a9b), 0x75 }, { CCI_REG8(0x5a9c), 0x75 }, ++ { CCI_REG8(0x5a9d), 0x75 }, { CCI_REG8(0x5a9e), 0x75 }, ++ { CCI_REG8(0x5a9f), 0x75 }, { CCI_REG8(0x5aa0), 0x75 }, ++ { CCI_REG8(0x5aa1), 0x75 }, { CCI_REG8(0x5aa2), 0x75 }, ++ { CCI_REG8(0x5aa3), 0x75 }, { CCI_REG8(0x5aa4), 0x75 }, ++ { CCI_REG8(0x5aa5), 0x75 }, { CCI_REG8(0x5aa6), 0x75 }, ++ { CCI_REG8(0x5aa7), 0x75 }, { CCI_REG8(0x5aa8), 0x75 }, ++ { CCI_REG8(0x5aa9), 0x75 }, { CCI_REG8(0x5aaa), 0x75 }, ++ { CCI_REG8(0x5aab), 0x75 }, { CCI_REG8(0x5aac), 0x75 }, ++ { CCI_REG8(0x5aad), 0x75 }, { CCI_REG8(0x5aae), 0x75 }, ++ { CCI_REG8(0x5aaf), 0x75 }, { CCI_REG8(0x5ab0), 0x75 }, ++ { CCI_REG8(0x5ab1), 0x75 }, { CCI_REG8(0x5ab2), 0x75 }, ++ { CCI_REG8(0x5ab3), 0x75 }, { CCI_REG8(0x5ab4), 0x75 }, ++ { CCI_REG8(0x5ab5), 0x75 }, { CCI_REG8(0x5ab6), 0x75 }, ++ { CCI_REG8(0x5ab7), 0x75 }, { CCI_REG8(0x5ab8), 0x75 }, ++ { CCI_REG8(0x5ab9), 0x75 }, { CCI_REG8(0x5aba), 0x75 }, ++ { CCI_REG8(0x5abb), 0x75 }, { CCI_REG8(0x5abc), 0x75 }, ++ { CCI_REG8(0x5abd), 0x75 }, { CCI_REG8(0x5abe), 0x75 }, ++ { CCI_REG8(0x5abf), 0x75 }, { CCI_REG8(0x5ac0), 0x75 }, ++ { CCI_REG8(0x5ac1), 0x75 }, { CCI_REG8(0x5ac2), 0x75 }, ++ { CCI_REG8(0x5ac3), 0x75 }, { CCI_REG8(0x5ac4), 0x75 }, ++ { CCI_REG8(0x5ac5), 0x75 }, { CCI_REG8(0x5ac6), 0x75 }, ++ { CCI_REG8(0x5ac7), 0x75 }, { CCI_REG8(0x5ac8), 0x75 }, ++ { CCI_REG8(0x5ac9), 0x75 }, { CCI_REG8(0x5aca), 0x75 }, ++ { CCI_REG8(0x5acb), 0x75 }, { CCI_REG8(0x5acc), 0x75 }, ++ { CCI_REG8(0x5acd), 0x75 }, { CCI_REG8(0x5ace), 0x75 }, ++ { CCI_REG8(0x5acf), 0x75 }, { CCI_REG8(0x5ad0), 0x75 }, ++ { CCI_REG8(0x5ad1), 0x75 }, { CCI_REG8(0x5ad2), 0x75 }, ++ { CCI_REG8(0x5ad3), 0x75 }, { CCI_REG8(0x5ad4), 0x75 }, ++ { CCI_REG8(0x5ad5), 0x75 }, { CCI_REG8(0x5ad6), 0x75 }, ++ { CCI_REG8(0x5ad7), 0x75 }, { CCI_REG8(0x5ad8), 0x75 }, ++ { CCI_REG8(0x5ad9), 0x75 }, { CCI_REG8(0x5ada), 0x75 }, ++ { CCI_REG8(0x5adb), 0x75 }, { CCI_REG8(0x5adc), 0x75 }, ++ { CCI_REG8(0x5add), 0x75 }, { CCI_REG8(0x5ade), 0x75 }, ++ { CCI_REG8(0x5adf), 0x75 }, { CCI_REG8(0x5ae0), 0x75 }, ++ { CCI_REG8(0x5ae1), 0x75 }, { CCI_REG8(0x5ae2), 0x75 }, ++ { CCI_REG8(0x5ae3), 0x75 }, { CCI_REG8(0x5ae4), 0x75 }, ++ { CCI_REG8(0x5ae5), 0x75 }, { CCI_REG8(0x5ae6), 0x75 }, ++ { CCI_REG8(0x5ae7), 0x75 }, { CCI_REG8(0x5ae8), 0x75 }, ++ { CCI_REG8(0x5ae9), 0x75 }, { CCI_REG8(0x5aea), 0x75 }, ++ { CCI_REG8(0x5aeb), 0x75 }, { CCI_REG8(0x5aec), 0x75 }, ++ { CCI_REG8(0x5aed), 0x75 }, { CCI_REG8(0x5aee), 0x75 }, ++ { CCI_REG8(0x5aef), 0x75 }, { CCI_REG8(0x5af0), 0x75 }, ++ { CCI_REG8(0x5af1), 0x75 }, { CCI_REG8(0x5af2), 0x75 }, ++ { CCI_REG8(0x5af3), 0x75 }, { CCI_REG8(0x5af4), 0x75 }, ++ { CCI_REG8(0x5af5), 0x75 }, { CCI_REG8(0x5af6), 0x75 }, ++ { CCI_REG8(0x5af7), 0x75 }, { CCI_REG8(0x5af8), 0x75 }, ++ { CCI_REG8(0x5af9), 0x75 }, { CCI_REG8(0x5afa), 0x75 }, ++ { CCI_REG8(0x5afb), 0x75 }, { CCI_REG8(0x5afc), 0x75 }, ++ { CCI_REG8(0x5afd), 0x75 }, { CCI_REG8(0x5afe), 0x75 }, ++ { CCI_REG8(0x5aff), 0x75 }, { CCI_REG8(0x5b00), 0x75 }, ++ { CCI_REG8(0x5b01), 0x75 }, { CCI_REG8(0x5b02), 0x75 }, ++ { CCI_REG8(0x5b03), 0x75 }, { CCI_REG8(0x5b04), 0x75 }, ++ { CCI_REG8(0x5b05), 0x75 }, { CCI_REG8(0x5b06), 0x75 }, ++ { CCI_REG8(0x5b07), 0x75 }, { CCI_REG8(0x5b08), 0x75 }, ++ { CCI_REG8(0x5b09), 0x75 }, { CCI_REG8(0x5b0a), 0x75 }, ++ { CCI_REG8(0x5b0b), 0x75 }, { CCI_REG8(0x5b0c), 0x75 }, ++ { CCI_REG8(0x5b0d), 0x75 }, { CCI_REG8(0x5b0e), 0x75 }, ++ { CCI_REG8(0x5b0f), 0x75 }, { CCI_REG8(0x5b10), 0x75 }, ++ { CCI_REG8(0x5b11), 0x75 }, { CCI_REG8(0x5b12), 0x75 }, ++ { CCI_REG8(0x5b13), 0x75 }, { CCI_REG8(0x5b14), 0x75 }, ++ { CCI_REG8(0x5b15), 0x75 }, { CCI_REG8(0x5b16), 0x75 }, ++ { CCI_REG8(0x5b17), 0x75 }, { CCI_REG8(0x5b18), 0x75 }, ++ { CCI_REG8(0x5b19), 0x75 }, { CCI_REG8(0x5b1a), 0x75 }, ++ { CCI_REG8(0x5b1b), 0x75 }, { CCI_REG8(0x5b1c), 0x75 }, ++ { CCI_REG8(0x5b1d), 0x75 }, { CCI_REG8(0x5b1e), 0x75 }, ++ { CCI_REG8(0x5b1f), 0x75 }, { CCI_REG8(0x5b20), 0x75 }, ++ { CCI_REG8(0x5b21), 0x75 }, { CCI_REG8(0x5b22), 0x75 }, ++ { CCI_REG8(0x5b23), 0x75 }, { CCI_REG8(0x5b24), 0x75 }, ++ { CCI_REG8(0x5b25), 0x75 }, { CCI_REG8(0x5b26), 0x75 }, ++ { CCI_REG8(0x5b27), 0x75 }, { CCI_REG8(0x5b28), 0x75 }, ++ { CCI_REG8(0x5b29), 0x75 }, { CCI_REG8(0x5b2a), 0x75 }, ++ { CCI_REG8(0x5b2b), 0x75 }, { CCI_REG8(0x5b2c), 0x75 }, ++ { CCI_REG8(0x5b2d), 0x75 }, { CCI_REG8(0x5b2e), 0x75 }, ++ { CCI_REG8(0x5b2f), 0x75 }, { CCI_REG8(0x5b30), 0x75 }, ++ { CCI_REG8(0x5b31), 0x75 }, { CCI_REG8(0x5b32), 0x75 }, ++ { CCI_REG8(0x5b33), 0x75 }, { CCI_REG8(0x5b34), 0x75 }, ++ { CCI_REG8(0x5b35), 0x75 }, { CCI_REG8(0x5b36), 0x75 }, ++ { CCI_REG8(0x5b37), 0x75 }, { CCI_REG8(0x5b38), 0x75 }, ++ { CCI_REG8(0x5b39), 0x75 }, { CCI_REG8(0x5b3a), 0x75 }, ++ { CCI_REG8(0x5b3b), 0x75 }, { CCI_REG8(0x5b3c), 0x75 }, ++ { CCI_REG8(0x5b3d), 0x75 }, { CCI_REG8(0x5b3e), 0x75 }, ++ { CCI_REG8(0x5b3f), 0x75 }, { CCI_REG8(0x5b40), 0x75 }, ++ { CCI_REG8(0x5b41), 0x75 }, { CCI_REG8(0x5b42), 0x75 }, ++ { CCI_REG8(0x5b43), 0x75 }, { CCI_REG8(0x5b44), 0x75 }, ++ { CCI_REG8(0x5b45), 0x75 }, { CCI_REG8(0x5b46), 0x75 }, ++ { CCI_REG8(0x5b47), 0x75 }, { CCI_REG8(0x5b48), 0x75 }, ++ { CCI_REG8(0x5b49), 0x75 }, { CCI_REG8(0x5b4a), 0x75 }, ++ { CCI_REG8(0x5b4b), 0x75 }, { CCI_REG8(0x5b4c), 0x75 }, ++ { CCI_REG8(0x5b4d), 0x75 }, { CCI_REG8(0x5b4e), 0x75 }, ++ { CCI_REG8(0x5b4f), 0x75 }, { CCI_REG8(0x5b50), 0x75 }, ++ { CCI_REG8(0x5b51), 0x75 }, { CCI_REG8(0x5b52), 0x75 }, ++ { CCI_REG8(0x5b53), 0x75 }, { CCI_REG8(0x5b54), 0x75 }, ++ { CCI_REG8(0x5b55), 0x75 }, { CCI_REG8(0x5b56), 0x75 }, ++ { CCI_REG8(0x5b57), 0x75 }, { CCI_REG8(0x5b58), 0x75 }, ++ { CCI_REG8(0x5b59), 0x75 }, { CCI_REG8(0x5b5a), 0x75 }, ++ { CCI_REG8(0x5b5b), 0x75 }, { CCI_REG8(0x5b5c), 0x75 }, ++ { CCI_REG8(0x5b5d), 0x75 }, { CCI_REG8(0x5b5e), 0x75 }, ++ { CCI_REG8(0x5b5f), 0x75 }, { CCI_REG8(0x5b80), 0x75 }, ++ { CCI_REG8(0x5b81), 0x75 }, { CCI_REG8(0x5b82), 0x75 }, ++ { CCI_REG8(0x5b83), 0x75 }, { CCI_REG8(0x5b84), 0x75 }, ++ { CCI_REG8(0x5b85), 0x75 }, { CCI_REG8(0x5b86), 0x75 }, ++ { CCI_REG8(0x5b87), 0x75 }, { CCI_REG8(0x5b88), 0x75 }, ++ { CCI_REG8(0x5b89), 0x75 }, { CCI_REG8(0x5b8a), 0x75 }, ++ { CCI_REG8(0x5b8b), 0x75 }, { CCI_REG8(0x5b8c), 0x75 }, ++ { CCI_REG8(0x5b8d), 0x75 }, { CCI_REG8(0x5b8e), 0x75 }, ++ { CCI_REG8(0x5b8f), 0x75 }, { CCI_REG8(0x5b90), 0x75 }, ++ { CCI_REG8(0x5b91), 0x75 }, { CCI_REG8(0x5b92), 0x75 }, ++ { CCI_REG8(0x5b93), 0x75 }, { CCI_REG8(0x5b94), 0x75 }, ++ { CCI_REG8(0x5b95), 0x75 }, { CCI_REG8(0x5b96), 0x75 }, ++ { CCI_REG8(0x5b97), 0x75 }, { CCI_REG8(0x5b98), 0x75 }, ++ { CCI_REG8(0x5b99), 0x75 }, { CCI_REG8(0x5b9a), 0x75 }, ++ { CCI_REG8(0x5b9b), 0x75 }, { CCI_REG8(0x5b9c), 0x75 }, ++ { CCI_REG8(0x5b9d), 0x75 }, { CCI_REG8(0x5b9e), 0x75 }, ++ { CCI_REG8(0x5b9f), 0x75 }, { CCI_REG8(0x5ba0), 0x75 }, ++ { CCI_REG8(0x5ba1), 0x75 }, { CCI_REG8(0x5ba2), 0x75 }, ++ { CCI_REG8(0x5ba3), 0x75 }, { CCI_REG8(0x5ba4), 0x75 }, ++ { CCI_REG8(0x5ba5), 0x75 }, { CCI_REG8(0x5ba6), 0x75 }, ++ { CCI_REG8(0x5ba7), 0x75 }, { CCI_REG8(0x5ba8), 0x75 }, ++ { CCI_REG8(0x5ba9), 0x75 }, { CCI_REG8(0x5baa), 0x75 }, ++ { CCI_REG8(0x5bab), 0x75 }, { CCI_REG8(0x5bac), 0x75 }, ++ { CCI_REG8(0x5bad), 0x75 }, { CCI_REG8(0x5bae), 0x75 }, ++ { CCI_REG8(0x5baf), 0x75 }, { CCI_REG8(0x5bb0), 0x75 }, ++ { CCI_REG8(0x5bb1), 0x75 }, { CCI_REG8(0x5bb2), 0x75 }, ++ { CCI_REG8(0x5bb3), 0x75 }, { CCI_REG8(0x5bb4), 0x75 }, ++ { CCI_REG8(0x5bb5), 0x75 }, { CCI_REG8(0x5bb6), 0x75 }, ++ { CCI_REG8(0x5bb7), 0x75 }, { CCI_REG8(0x5bb8), 0x75 }, ++ { CCI_REG8(0x5bb9), 0x75 }, { CCI_REG8(0x5bba), 0x75 }, ++ { CCI_REG8(0x5bbb), 0x75 }, { CCI_REG8(0x5bbc), 0x75 }, ++ { CCI_REG8(0x5bbd), 0x75 }, { CCI_REG8(0x5bbe), 0x75 }, ++ { CCI_REG8(0x5bbf), 0x75 }, { CCI_REG8(0x5bc0), 0x75 }, ++ { CCI_REG8(0x5bc1), 0x75 }, { CCI_REG8(0x5bc2), 0x75 }, ++ { CCI_REG8(0x5bc3), 0x75 }, { CCI_REG8(0x5bc4), 0x75 }, ++ { CCI_REG8(0x5bc5), 0x75 }, { CCI_REG8(0x5bc6), 0x75 }, ++ { CCI_REG8(0x5bc7), 0x75 }, { CCI_REG8(0x5bc8), 0x75 }, ++ { CCI_REG8(0x5bc9), 0x75 }, { CCI_REG8(0x5bca), 0x75 }, ++ { CCI_REG8(0x5bcb), 0x75 }, { CCI_REG8(0x5bcc), 0x75 }, ++ { CCI_REG8(0x5bcd), 0x75 }, { CCI_REG8(0x5bce), 0x75 }, ++ { CCI_REG8(0x5bcf), 0x75 }, { CCI_REG8(0x5bd0), 0x75 }, ++ { CCI_REG8(0x5bd1), 0x75 }, { CCI_REG8(0x5bd2), 0x75 }, ++ { CCI_REG8(0x5bd3), 0x75 }, { CCI_REG8(0x5bd4), 0x75 }, ++ { CCI_REG8(0x5bd5), 0x75 }, { CCI_REG8(0x5bd6), 0x75 }, ++ { CCI_REG8(0x5bd7), 0x75 }, { CCI_REG8(0x5bd8), 0x75 }, ++ { CCI_REG8(0x5bd9), 0x75 }, { CCI_REG8(0x5bda), 0x75 }, ++ { CCI_REG8(0x5bdb), 0x75 }, { CCI_REG8(0x5bdc), 0x75 }, ++ { CCI_REG8(0x5bdd), 0x75 }, { CCI_REG8(0x5bde), 0x75 }, ++ { CCI_REG8(0x5bdf), 0x75 }, { CCI_REG8(0x5be0), 0x75 }, ++ { CCI_REG8(0x5be1), 0x75 }, { CCI_REG8(0x5be2), 0x75 }, ++ { CCI_REG8(0x5be3), 0x75 }, { CCI_REG8(0x5be4), 0x75 }, ++ { CCI_REG8(0x5be5), 0x75 }, { CCI_REG8(0x5be6), 0x75 }, ++ { CCI_REG8(0x5be7), 0x75 }, { CCI_REG8(0x5be8), 0x75 }, ++ { CCI_REG8(0x5be9), 0x75 }, { CCI_REG8(0x5bea), 0x75 }, ++ { CCI_REG8(0x5beb), 0x75 }, { CCI_REG8(0x5bec), 0x75 }, ++ { CCI_REG8(0x5bed), 0x75 }, { CCI_REG8(0x5bee), 0x75 }, ++ { CCI_REG8(0x5bef), 0x75 }, { CCI_REG8(0x5bf0), 0x75 }, ++ { CCI_REG8(0x5bf1), 0x75 }, { CCI_REG8(0x5bf2), 0x75 }, ++ { CCI_REG8(0x5bf3), 0x75 }, { CCI_REG8(0x5bf4), 0x75 }, ++ { CCI_REG8(0x5bf5), 0x75 }, { CCI_REG8(0x5bf6), 0x75 }, ++ { CCI_REG8(0x5bf7), 0x75 }, { CCI_REG8(0x5bf8), 0x75 }, ++ { CCI_REG8(0x5bf9), 0x75 }, { CCI_REG8(0x5bfa), 0x75 }, ++ { CCI_REG8(0x5bfb), 0x75 }, { CCI_REG8(0x5bfc), 0x75 }, ++ { CCI_REG8(0x5bfd), 0x75 }, { CCI_REG8(0x5bfe), 0x75 }, ++ { CCI_REG8(0x5bff), 0x75 }, { CCI_REG8(0x5c00), 0x75 }, ++ { CCI_REG8(0x5c01), 0x75 }, { CCI_REG8(0x5c02), 0x75 }, ++ { CCI_REG8(0x5c03), 0x75 }, { CCI_REG8(0x5c04), 0x75 }, ++ { CCI_REG8(0x5c05), 0x75 }, { CCI_REG8(0x5c06), 0x75 }, ++ { CCI_REG8(0x5c07), 0x75 }, { CCI_REG8(0x5c08), 0x75 }, ++ { CCI_REG8(0x5c09), 0x75 }, { CCI_REG8(0x5c0a), 0x75 }, ++ { CCI_REG8(0x5c0b), 0x75 }, { CCI_REG8(0x5c0c), 0x75 }, ++ { CCI_REG8(0x5c0d), 0x75 }, { CCI_REG8(0x5c0e), 0x75 }, ++ { CCI_REG8(0x5c0f), 0x75 }, { CCI_REG8(0x5c10), 0x75 }, ++ { CCI_REG8(0x5c11), 0x75 }, { CCI_REG8(0x5c12), 0x75 }, ++ { CCI_REG8(0x5c13), 0x75 }, { CCI_REG8(0x5c14), 0x75 }, ++ { CCI_REG8(0x5c15), 0x75 }, { CCI_REG8(0x5c16), 0x75 }, ++ { CCI_REG8(0x5c17), 0x75 }, { CCI_REG8(0x5c18), 0x75 }, ++ { CCI_REG8(0x5c19), 0x75 }, { CCI_REG8(0x5c1a), 0x75 }, ++ { CCI_REG8(0x5c1b), 0x75 }, { CCI_REG8(0x5c1c), 0x75 }, ++ { CCI_REG8(0x5c1d), 0x75 }, { CCI_REG8(0x5c1e), 0x75 }, ++ { CCI_REG8(0x5c1f), 0x75 }, { CCI_REG8(0x5c20), 0x75 }, ++ { CCI_REG8(0x5c21), 0x75 }, { CCI_REG8(0x5c22), 0x75 }, ++ { CCI_REG8(0x5c23), 0x75 }, { CCI_REG8(0x5c24), 0x75 }, ++ { CCI_REG8(0x5c25), 0x75 }, { CCI_REG8(0x5c26), 0x75 }, ++ { CCI_REG8(0x5c27), 0x75 }, { CCI_REG8(0x5c28), 0x75 }, ++ { CCI_REG8(0x5c29), 0x75 }, { CCI_REG8(0x5c2a), 0x75 }, ++ { CCI_REG8(0x5c2b), 0x75 }, { CCI_REG8(0x5c2c), 0x75 }, ++ { CCI_REG8(0x5c2d), 0x75 }, { CCI_REG8(0x5c2e), 0x75 }, ++ { CCI_REG8(0x5c2f), 0x75 }, { CCI_REG8(0x5c30), 0x75 }, ++ { CCI_REG8(0x5c31), 0x75 }, { CCI_REG8(0x5c32), 0x75 }, ++ { CCI_REG8(0x5c33), 0x75 }, { CCI_REG8(0x5c34), 0x75 }, ++ { CCI_REG8(0x5c35), 0x75 }, { CCI_REG8(0x5c36), 0x75 }, ++ { CCI_REG8(0x5c37), 0x75 }, { CCI_REG8(0x5c38), 0x75 }, ++ { CCI_REG8(0x5c39), 0x75 }, { CCI_REG8(0x5c3a), 0x75 }, ++ { CCI_REG8(0x5c3b), 0x75 }, { CCI_REG8(0x5c3c), 0x75 }, ++ { CCI_REG8(0x5c3d), 0x75 }, { CCI_REG8(0x5c3e), 0x75 }, ++ { CCI_REG8(0x5c3f), 0x75 }, { CCI_REG8(0x5c40), 0x75 }, ++ { CCI_REG8(0x5c41), 0x75 }, { CCI_REG8(0x5c42), 0x75 }, ++ { CCI_REG8(0x5c43), 0x75 }, { CCI_REG8(0x5c44), 0x75 }, ++ { CCI_REG8(0x5c45), 0x75 }, { CCI_REG8(0x5c46), 0x75 }, ++ { CCI_REG8(0x5c47), 0x75 }, { CCI_REG8(0x5c48), 0x75 }, ++ { CCI_REG8(0x5c49), 0x75 }, { CCI_REG8(0x5c4a), 0x75 }, ++ { CCI_REG8(0x5c4b), 0x75 }, { CCI_REG8(0x5c4c), 0x75 }, ++ { CCI_REG8(0x5c4d), 0x75 }, { CCI_REG8(0x5c4e), 0x75 }, ++ { CCI_REG8(0x5c4f), 0x75 }, { CCI_REG8(0x5c50), 0x75 }, ++ { CCI_REG8(0x5c51), 0x75 }, { CCI_REG8(0x5c52), 0x75 }, ++ { CCI_REG8(0x5c53), 0x75 }, { CCI_REG8(0x5c54), 0x75 }, ++ { CCI_REG8(0x5c55), 0x75 }, { CCI_REG8(0x5c56), 0x75 }, ++ { CCI_REG8(0x5c57), 0x75 }, { CCI_REG8(0x5c58), 0x75 }, ++ { CCI_REG8(0x5c59), 0x75 }, { CCI_REG8(0x5c5a), 0x75 }, ++ { CCI_REG8(0x5c5b), 0x75 }, { CCI_REG8(0x5c5c), 0x75 }, ++ { CCI_REG8(0x5c5d), 0x75 }, { CCI_REG8(0x5c5e), 0x75 }, ++ { CCI_REG8(0x5c5f), 0x75 }, { CCI_REG8(0x5c60), 0x75 }, ++ { CCI_REG8(0x5c61), 0x75 }, { CCI_REG8(0x5c62), 0x75 }, ++ { CCI_REG8(0x5c63), 0x75 }, { CCI_REG8(0x5c64), 0x75 }, ++ { CCI_REG8(0x5c65), 0x75 }, { CCI_REG8(0x5c66), 0x75 }, ++ { CCI_REG8(0x5c67), 0x75 }, { CCI_REG8(0x5c68), 0x75 }, ++ { CCI_REG8(0x5c69), 0x75 }, { CCI_REG8(0x5c6a), 0x75 }, ++ { CCI_REG8(0x5c6b), 0x75 }, { CCI_REG8(0x5c6c), 0x75 }, ++ { CCI_REG8(0x5c6d), 0x75 }, { CCI_REG8(0x5c6e), 0x75 }, ++ { CCI_REG8(0x5c6f), 0x75 }, { CCI_REG8(0x5c70), 0x75 }, ++ { CCI_REG8(0x5c71), 0x75 }, { CCI_REG8(0x5c72), 0x75 }, ++ { CCI_REG8(0x5c73), 0x75 }, { CCI_REG8(0x5c74), 0x75 }, ++ { CCI_REG8(0x5c75), 0x75 }, { CCI_REG8(0x5c76), 0x75 }, ++ { CCI_REG8(0x5c77), 0x75 }, { CCI_REG8(0x5c78), 0x75 }, ++ { CCI_REG8(0x5c79), 0x75 }, { CCI_REG8(0x5c7a), 0x75 }, ++ { CCI_REG8(0x5c7b), 0x75 }, { CCI_REG8(0x5c7c), 0x75 }, ++ { CCI_REG8(0x5c7d), 0x75 }, { CCI_REG8(0x5c7e), 0x75 }, ++ { CCI_REG8(0x5c7f), 0x75 }, { CCI_REG8(0x5c80), 0x75 }, ++ { CCI_REG8(0x5c81), 0x75 }, { CCI_REG8(0x5c82), 0x75 }, ++ { CCI_REG8(0x5c83), 0x75 }, { CCI_REG8(0x5c84), 0x75 }, ++ { CCI_REG8(0x5c85), 0x75 }, { CCI_REG8(0x5c86), 0x75 }, ++ { CCI_REG8(0x5c87), 0x75 }, { CCI_REG8(0x5c88), 0x75 }, ++ { CCI_REG8(0x5c89), 0x75 }, { CCI_REG8(0x5c8a), 0x75 }, ++ { CCI_REG8(0x5c8b), 0x75 }, { CCI_REG8(0x5c8c), 0x75 }, ++ { CCI_REG8(0x5c8d), 0x75 }, { CCI_REG8(0x5c8e), 0x75 }, ++ { CCI_REG8(0x5c8f), 0x75 }, { CCI_REG8(0x5c90), 0x75 }, ++ { CCI_REG8(0x5c91), 0x75 }, { CCI_REG8(0x5c92), 0x75 }, ++ { CCI_REG8(0x5c93), 0x75 }, { CCI_REG8(0x5c94), 0x75 }, ++ { CCI_REG8(0x5c95), 0x75 }, { CCI_REG8(0x5c96), 0x75 }, ++ { CCI_REG8(0x5c97), 0x75 }, { CCI_REG8(0x5c98), 0x75 }, ++ { CCI_REG8(0x5c99), 0x75 }, { CCI_REG8(0x5c9a), 0x75 }, ++ { CCI_REG8(0x5c9b), 0x75 }, { CCI_REG8(0x5c9c), 0x75 }, ++ { CCI_REG8(0x5c9d), 0x75 }, { CCI_REG8(0x5c9e), 0x75 }, ++ { CCI_REG8(0x5c9f), 0x75 }, { CCI_REG8(0x5ca0), 0x75 }, ++ { CCI_REG8(0x5ca1), 0x75 }, { CCI_REG8(0x5ca2), 0x75 }, ++ { CCI_REG8(0x5ca3), 0x75 }, { CCI_REG8(0x5ca4), 0x75 }, ++ { CCI_REG8(0x5ca5), 0x75 }, { CCI_REG8(0x5ca6), 0x75 }, ++ { CCI_REG8(0x5ca7), 0x75 }, { CCI_REG8(0x5ca8), 0x75 }, ++ { CCI_REG8(0x5ca9), 0x75 }, { CCI_REG8(0x5caa), 0x75 }, ++ { CCI_REG8(0x5cab), 0x75 }, { CCI_REG8(0x5cac), 0x75 }, ++ { CCI_REG8(0x5cad), 0x75 }, { CCI_REG8(0x5cae), 0x75 }, ++ { CCI_REG8(0x5caf), 0x75 }, { CCI_REG8(0x5cb0), 0x75 }, ++ { CCI_REG8(0x5cb1), 0x75 }, { CCI_REG8(0x5cb2), 0x75 }, ++ { CCI_REG8(0x5cb3), 0x75 }, { CCI_REG8(0x5cb4), 0x75 }, ++ { CCI_REG8(0x5cb5), 0x75 }, { CCI_REG8(0x5cb6), 0x75 }, ++ { CCI_REG8(0x5cb7), 0x75 }, { CCI_REG8(0x5cb8), 0x75 }, ++ { CCI_REG8(0x5cb9), 0x75 }, { CCI_REG8(0x5cba), 0x75 }, ++ { CCI_REG8(0x5cbb), 0x75 }, { CCI_REG8(0x5cbc), 0x75 }, ++ { CCI_REG8(0x5cbd), 0x75 }, { CCI_REG8(0x5cbe), 0x75 }, ++ { CCI_REG8(0x5cbf), 0x75 }, { CCI_REG8(0x5cc0), 0x75 }, ++ { CCI_REG8(0x5cc1), 0x75 }, { CCI_REG8(0x5cc2), 0x75 }, ++ { CCI_REG8(0x5cc3), 0x75 }, { CCI_REG8(0x5cc4), 0x75 }, ++ { CCI_REG8(0x5cc5), 0x75 }, { CCI_REG8(0x5cc6), 0x75 }, ++ { CCI_REG8(0x5cc7), 0x75 }, { CCI_REG8(0x5cc8), 0x75 }, ++ { CCI_REG8(0x5cc9), 0x75 }, { CCI_REG8(0x5cca), 0x75 }, ++ { CCI_REG8(0x5ccb), 0x75 }, { CCI_REG8(0x5ccc), 0x75 }, ++ { CCI_REG8(0x5ccd), 0x75 }, { CCI_REG8(0x5cce), 0x75 }, ++ { CCI_REG8(0x5ccf), 0x75 }, { CCI_REG8(0x5cd0), 0x75 }, ++ { CCI_REG8(0x5cd1), 0x75 }, { CCI_REG8(0x5cd2), 0x75 }, ++ { CCI_REG8(0x5cd3), 0x75 }, { CCI_REG8(0x5cd4), 0x75 }, ++ { CCI_REG8(0x5cd5), 0x75 }, { CCI_REG8(0x5cd6), 0x75 }, ++ { CCI_REG8(0x5cd7), 0x75 }, { CCI_REG8(0x5cd8), 0x75 }, ++ { CCI_REG8(0x5cd9), 0x75 }, { CCI_REG8(0x5cda), 0x75 }, ++ { CCI_REG8(0x5cdb), 0x75 }, { CCI_REG8(0x5cdc), 0x75 }, ++ { CCI_REG8(0x5cdd), 0x75 }, { CCI_REG8(0x5cde), 0x75 }, ++ { CCI_REG8(0x5cdf), 0x75 }, { CCI_REG8(0x5ce0), 0x75 }, ++ { CCI_REG8(0x5ce1), 0x75 }, { CCI_REG8(0x5ce2), 0x75 }, ++ { CCI_REG8(0x5ce3), 0x75 }, { CCI_REG8(0x5ce4), 0x75 }, ++ { CCI_REG8(0x5ce5), 0x75 }, { CCI_REG8(0x5ce6), 0x75 }, ++ { CCI_REG8(0x5ce7), 0x75 }, { CCI_REG8(0x5ce8), 0x75 }, ++ { CCI_REG8(0x5ce9), 0x75 }, { CCI_REG8(0x5cea), 0x75 }, ++ { CCI_REG8(0x5ceb), 0x75 }, { CCI_REG8(0x5cec), 0x75 }, ++ { CCI_REG8(0x5ced), 0x75 }, { CCI_REG8(0x5cee), 0x75 }, ++ { CCI_REG8(0x5cef), 0x75 }, { CCI_REG8(0x5cf0), 0x75 }, ++ { CCI_REG8(0x5cf1), 0x75 }, { CCI_REG8(0x5cf2), 0x75 }, ++ { CCI_REG8(0x5cf3), 0x75 }, { CCI_REG8(0x5cf4), 0x75 }, ++ { CCI_REG8(0x5cf5), 0x75 }, { CCI_REG8(0x5cf6), 0x75 }, ++ { CCI_REG8(0x5cf7), 0x75 }, { CCI_REG8(0x5cf8), 0x75 }, ++ { CCI_REG8(0x5cf9), 0x75 }, { CCI_REG8(0x5cfa), 0x75 }, ++ { CCI_REG8(0x5cfb), 0x75 }, { CCI_REG8(0x5cfc), 0x75 }, ++ { CCI_REG8(0x5cfd), 0x75 }, { CCI_REG8(0x5cfe), 0x75 }, ++ { CCI_REG8(0x5cff), 0x75 }, { CCI_REG8(0x5d00), 0x75 }, ++ { CCI_REG8(0x5d01), 0x75 }, { CCI_REG8(0x5d02), 0x75 }, ++ { CCI_REG8(0x5d03), 0x75 }, { CCI_REG8(0x5d04), 0x75 }, ++ { CCI_REG8(0x5d05), 0x75 }, { CCI_REG8(0x5d06), 0x75 }, ++ { CCI_REG8(0x5d07), 0x75 }, { CCI_REG8(0x5d08), 0x75 }, ++ { CCI_REG8(0x5d09), 0x75 }, { CCI_REG8(0x5d0a), 0x75 }, ++ { CCI_REG8(0x5d0b), 0x75 }, { CCI_REG8(0x5d0c), 0x75 }, ++ { CCI_REG8(0x5d0d), 0x75 }, { CCI_REG8(0x5d0e), 0x75 }, ++ { CCI_REG8(0x5d0f), 0x75 }, { CCI_REG8(0x5d10), 0x75 }, ++ { CCI_REG8(0x5d11), 0x75 }, { CCI_REG8(0x5d12), 0x75 }, ++ { CCI_REG8(0x5d13), 0x75 }, { CCI_REG8(0x5d14), 0x75 }, ++ { CCI_REG8(0x5d15), 0x75 }, { CCI_REG8(0x5d16), 0x75 }, ++ { CCI_REG8(0x5d17), 0x75 }, { CCI_REG8(0x5d18), 0x75 }, ++ { CCI_REG8(0x5d19), 0x75 }, { CCI_REG8(0x5d1a), 0x75 }, ++ { CCI_REG8(0x5d1b), 0x75 }, { CCI_REG8(0x5d1c), 0x75 }, ++ { CCI_REG8(0x5d1d), 0x75 }, { CCI_REG8(0x5d1e), 0x75 }, ++ { CCI_REG8(0x5d1f), 0x75 }, { CCI_REG8(0x5d20), 0x75 }, ++ { CCI_REG8(0x5d21), 0x75 }, { CCI_REG8(0x5d22), 0x75 }, ++ { CCI_REG8(0x5d23), 0x75 }, { CCI_REG8(0x5d24), 0x75 }, ++ { CCI_REG8(0x5d25), 0x75 }, { CCI_REG8(0x5d26), 0x75 }, ++ { CCI_REG8(0x5d27), 0x75 }, { CCI_REG8(0x5d28), 0x75 }, ++ { CCI_REG8(0x5d29), 0x75 }, { CCI_REG8(0x5d2a), 0x75 }, ++ { CCI_REG8(0x5d2b), 0x75 }, { CCI_REG8(0x5d2c), 0x75 }, ++ { CCI_REG8(0x5d2d), 0x75 }, { CCI_REG8(0x5d2e), 0x75 }, ++ { CCI_REG8(0x5d2f), 0x75 }, { CCI_REG8(0x5d30), 0x75 }, ++ { CCI_REG8(0x5d31), 0x75 }, { CCI_REG8(0x5d32), 0x75 }, ++ { CCI_REG8(0x5d33), 0x75 }, { CCI_REG8(0x5d34), 0x75 }, ++ { CCI_REG8(0x5d35), 0x75 }, { CCI_REG8(0x5d36), 0x75 }, ++ { CCI_REG8(0x5d37), 0x75 }, { CCI_REG8(0x5d38), 0x75 }, ++ { CCI_REG8(0x5d39), 0x75 }, { CCI_REG8(0x5d3a), 0x75 }, ++ { CCI_REG8(0x5d3b), 0x75 }, { CCI_REG8(0x5d3c), 0x75 }, ++ { CCI_REG8(0x5d3d), 0x75 }, { CCI_REG8(0x5d3e), 0x75 }, ++ { CCI_REG8(0x5d3f), 0x75 }, { CCI_REG8(0x5d40), 0x75 }, ++ { CCI_REG8(0x5d41), 0x75 }, { CCI_REG8(0x5d42), 0x75 }, ++ { CCI_REG8(0x5d43), 0x75 }, { CCI_REG8(0x5d44), 0x75 }, ++ { CCI_REG8(0x5d45), 0x75 }, { CCI_REG8(0x5d46), 0x75 }, ++ { CCI_REG8(0x5d47), 0x75 }, { CCI_REG8(0x5d48), 0x75 }, ++ { CCI_REG8(0x5d49), 0x75 }, { CCI_REG8(0x5d4a), 0x75 }, ++ { CCI_REG8(0x5d4b), 0x75 }, { CCI_REG8(0x5d4c), 0x75 }, ++ { CCI_REG8(0x5d4d), 0x75 }, { CCI_REG8(0x5d4e), 0x75 }, ++ { CCI_REG8(0x5d4f), 0x75 }, { CCI_REG8(0x5d50), 0x75 }, ++ { CCI_REG8(0x5d51), 0x75 }, { CCI_REG8(0x5d52), 0x75 }, ++ { CCI_REG8(0x5d53), 0x75 }, { CCI_REG8(0x5d54), 0x75 }, ++ { CCI_REG8(0x5d55), 0x75 }, { CCI_REG8(0x5d56), 0x75 }, ++ { CCI_REG8(0x5d57), 0x75 }, { CCI_REG8(0x5d58), 0x75 }, ++ { CCI_REG8(0x5d59), 0x75 }, { CCI_REG8(0x5d5a), 0x75 }, ++ { CCI_REG8(0x5d5b), 0x75 }, { CCI_REG8(0x5d5c), 0x75 }, ++ { CCI_REG8(0x5d5d), 0x75 }, { CCI_REG8(0x5d5e), 0x75 }, ++ { CCI_REG8(0x5d5f), 0x75 }, { CCI_REG8(0x5d60), 0x75 }, ++ { CCI_REG8(0x5d61), 0x75 }, { CCI_REG8(0x5d62), 0x75 }, ++ { CCI_REG8(0x5d63), 0x75 }, { CCI_REG8(0x5d64), 0x75 }, ++ { CCI_REG8(0x5d65), 0x75 }, { CCI_REG8(0x5d66), 0x75 }, ++ { CCI_REG8(0x5d67), 0x75 }, { CCI_REG8(0x5d68), 0x75 }, ++ { CCI_REG8(0x5d69), 0x75 }, { CCI_REG8(0x5d6a), 0x75 }, ++ { CCI_REG8(0x5d6b), 0x75 }, { CCI_REG8(0x5d6c), 0x75 }, ++ { CCI_REG8(0x5d6d), 0x75 }, { CCI_REG8(0x5d6e), 0x75 }, ++ { CCI_REG8(0x5d6f), 0x75 }, { CCI_REG8(0x5d70), 0x75 }, ++ { CCI_REG8(0x5d71), 0x75 }, { CCI_REG8(0x5d72), 0x75 }, ++ { CCI_REG8(0x5d73), 0x75 }, { CCI_REG8(0x5d74), 0x75 }, ++ { CCI_REG8(0x5d75), 0x75 }, { CCI_REG8(0x5d76), 0x75 }, ++ { CCI_REG8(0x5d77), 0x75 }, { CCI_REG8(0x5d78), 0x75 }, ++ { CCI_REG8(0x5d79), 0x75 }, { CCI_REG8(0x5d7a), 0x75 }, ++ { CCI_REG8(0x5d7b), 0x75 }, { CCI_REG8(0x5d7c), 0x75 }, ++ { CCI_REG8(0x5d7d), 0x75 }, { CCI_REG8(0x5d7e), 0x75 }, ++ { CCI_REG8(0x5d7f), 0x75 }, { CCI_REG8(0x5d80), 0x75 }, ++ { CCI_REG8(0x5d81), 0x75 }, { CCI_REG8(0x5d82), 0x75 }, ++ { CCI_REG8(0x5d83), 0x75 }, { CCI_REG8(0x5d84), 0x75 }, ++ { CCI_REG8(0x5d85), 0x75 }, { CCI_REG8(0x5d86), 0x75 }, ++ { CCI_REG8(0x5d87), 0x75 }, { CCI_REG8(0x5d88), 0x75 }, ++ { CCI_REG8(0x5d89), 0x75 }, { CCI_REG8(0x5d8a), 0x75 }, ++ { CCI_REG8(0x5d8b), 0x75 }, { CCI_REG8(0x5d8c), 0x75 }, ++ { CCI_REG8(0x5d8d), 0x75 }, { CCI_REG8(0x5d8e), 0x75 }, ++ { CCI_REG8(0x5d8f), 0x75 }, { CCI_REG8(0x5d90), 0x75 }, ++ { CCI_REG8(0x5d91), 0x75 }, { CCI_REG8(0x5d92), 0x75 }, ++ { CCI_REG8(0x5d93), 0x75 }, { CCI_REG8(0x5d94), 0x75 }, ++ { CCI_REG8(0x5d95), 0x75 }, { CCI_REG8(0x5d96), 0x75 }, ++ { CCI_REG8(0x5d97), 0x75 }, { CCI_REG8(0x5d98), 0x75 }, ++ { CCI_REG8(0x5d99), 0x75 }, { CCI_REG8(0x5d9a), 0x75 }, ++ { CCI_REG8(0x5d9b), 0x75 }, { CCI_REG8(0x5d9c), 0x75 }, ++ { CCI_REG8(0x5d9d), 0x75 }, { CCI_REG8(0x5d9e), 0x75 }, ++ { CCI_REG8(0x5d9f), 0x75 }, { CCI_REG8(0x5da0), 0x75 }, ++ { CCI_REG8(0x5da1), 0x75 }, { CCI_REG8(0x5da2), 0x75 }, ++ { CCI_REG8(0x5da3), 0x75 }, { CCI_REG8(0x5da4), 0x75 }, ++ { CCI_REG8(0x5da5), 0x75 }, { CCI_REG8(0x5da6), 0x75 }, ++ { CCI_REG8(0x5da7), 0x75 }, { CCI_REG8(0x5da8), 0x75 }, ++ { CCI_REG8(0x5da9), 0x75 }, { CCI_REG8(0x5daa), 0x75 }, ++ { CCI_REG8(0x5dab), 0x75 }, { CCI_REG8(0x5dac), 0x75 }, ++ { CCI_REG8(0x5dad), 0x75 }, { CCI_REG8(0x5dae), 0x75 }, ++ { CCI_REG8(0x5daf), 0x75 }, { CCI_REG8(0x5db0), 0x75 }, ++ { CCI_REG8(0x5db1), 0x75 }, { CCI_REG8(0x5db2), 0x75 }, ++ { CCI_REG8(0x5db3), 0x75 }, { CCI_REG8(0x5db4), 0x75 }, ++ { CCI_REG8(0x5db5), 0x75 }, { CCI_REG8(0x5db6), 0x75 }, ++ { CCI_REG8(0x5db7), 0x75 }, { CCI_REG8(0x5db8), 0x75 }, ++ { CCI_REG8(0x5db9), 0x75 }, { CCI_REG8(0x5dba), 0x75 }, ++ { CCI_REG8(0x5dbb), 0x75 }, { CCI_REG8(0x5dbc), 0x75 }, ++ { CCI_REG8(0x5dbd), 0x75 }, { CCI_REG8(0x5dbe), 0x75 }, ++ { CCI_REG8(0x5dbf), 0x75 }, { CCI_REG8(0x5dc0), 0x75 }, ++ { CCI_REG8(0x5dc1), 0x75 }, { CCI_REG8(0x5dc2), 0x75 }, ++ { CCI_REG8(0x5dc3), 0x75 }, { CCI_REG8(0x5dc4), 0x75 }, ++ { CCI_REG8(0x5dc5), 0x75 }, { CCI_REG8(0x5dc6), 0x75 }, ++ { CCI_REG8(0x5dc7), 0x75 }, { CCI_REG8(0x5dc8), 0x75 }, ++ { CCI_REG8(0x5dc9), 0x75 }, { CCI_REG8(0x5dca), 0x75 }, ++ { CCI_REG8(0x5dcb), 0x75 }, { CCI_REG8(0x5dcc), 0x75 }, ++ { CCI_REG8(0x5dcd), 0x75 }, { CCI_REG8(0x5dce), 0x75 }, ++ { CCI_REG8(0x5dcf), 0x75 }, { CCI_REG8(0x5dd0), 0x75 }, ++ { CCI_REG8(0x5dd1), 0x75 }, { CCI_REG8(0x5dd2), 0x75 }, ++ { CCI_REG8(0x5dd3), 0x75 }, { CCI_REG8(0x5dd4), 0x75 }, ++ { CCI_REG8(0x5dd5), 0x75 }, { CCI_REG8(0x5dd6), 0x75 }, ++ { CCI_REG8(0x5dd7), 0x75 }, { CCI_REG8(0x5dd8), 0x75 }, ++ { CCI_REG8(0x5dd9), 0x75 }, { CCI_REG8(0x5dda), 0x75 }, ++ { CCI_REG8(0x5ddb), 0x75 }, { CCI_REG8(0x5ddc), 0x75 }, ++ { CCI_REG8(0x5ddd), 0x75 }, { CCI_REG8(0x5dde), 0x75 }, ++ { CCI_REG8(0x5ddf), 0x75 }, { CCI_REG8(0x5de0), 0x75 }, ++ { CCI_REG8(0x5de1), 0x75 }, { CCI_REG8(0x5de2), 0x75 }, ++ { CCI_REG8(0x5de3), 0x75 }, { CCI_REG8(0x5de4), 0x75 }, ++ { CCI_REG8(0x5de5), 0x75 }, { CCI_REG8(0x5de6), 0x75 }, ++ { CCI_REG8(0x5de7), 0x75 }, { CCI_REG8(0x5de8), 0x75 }, ++ { CCI_REG8(0x5de9), 0x75 }, { CCI_REG8(0x5dea), 0x75 }, ++ { CCI_REG8(0x5deb), 0x75 }, { CCI_REG8(0x5dec), 0x75 }, ++ { CCI_REG8(0x5ded), 0x75 }, { CCI_REG8(0x5dee), 0x75 }, ++ { CCI_REG8(0x5def), 0x75 }, { CCI_REG8(0x5df0), 0x75 }, ++ { CCI_REG8(0x5df1), 0x75 }, { CCI_REG8(0x5df2), 0x75 }, ++ { CCI_REG8(0x5df3), 0x75 }, { CCI_REG8(0x5df4), 0x75 }, ++ { CCI_REG8(0x5df5), 0x75 }, { CCI_REG8(0x5df6), 0x75 }, ++ { CCI_REG8(0x5df7), 0x75 }, { CCI_REG8(0x5df8), 0x75 }, ++ { CCI_REG8(0x5df9), 0x75 }, { CCI_REG8(0x5dfa), 0x75 }, ++ { CCI_REG8(0x5dfb), 0x75 }, { CCI_REG8(0x5dfc), 0x75 }, ++ { CCI_REG8(0x5dfd), 0x75 }, { CCI_REG8(0x5dfe), 0x75 }, ++ { CCI_REG8(0x5dff), 0x75 }, { CCI_REG8(0x5e00), 0x75 }, ++ { CCI_REG8(0x5e01), 0x75 }, { CCI_REG8(0x5e02), 0x75 }, ++ { CCI_REG8(0x5e03), 0x75 }, { CCI_REG8(0x5e04), 0x75 }, ++ { CCI_REG8(0x5e05), 0x75 }, { CCI_REG8(0x5e06), 0x75 }, ++ { CCI_REG8(0x5e07), 0x75 }, { CCI_REG8(0x5e08), 0x75 }, ++ { CCI_REG8(0x5e09), 0x75 }, { CCI_REG8(0x5e0a), 0x75 }, ++ { CCI_REG8(0x5e0b), 0x75 }, { CCI_REG8(0x5e0c), 0x75 }, ++ { CCI_REG8(0x5e0d), 0x75 }, { CCI_REG8(0x5e0e), 0x75 }, ++ { CCI_REG8(0x5e0f), 0x75 }, { CCI_REG8(0x5e10), 0x75 }, ++ { CCI_REG8(0x5e11), 0x75 }, { CCI_REG8(0x5e12), 0x75 }, ++ { CCI_REG8(0x5e13), 0x75 }, { CCI_REG8(0x5e14), 0x75 }, ++ { CCI_REG8(0x5e15), 0x75 }, { CCI_REG8(0x5e16), 0x75 }, ++ { CCI_REG8(0x5e17), 0x75 }, { CCI_REG8(0x5e18), 0x75 }, ++ { CCI_REG8(0x5e19), 0x75 }, { CCI_REG8(0x5e1a), 0x75 }, ++ { CCI_REG8(0x5e1b), 0x75 }, { CCI_REG8(0x5e1c), 0x75 }, ++ { CCI_REG8(0x5e1d), 0x75 }, { CCI_REG8(0x5e1e), 0x75 }, ++ { CCI_REG8(0x5e1f), 0x75 }, { CCI_REG8(0x5e20), 0x75 }, ++ { CCI_REG8(0x5e21), 0x75 }, { CCI_REG8(0x5e22), 0x75 }, ++ { CCI_REG8(0x5e23), 0x75 }, { CCI_REG8(0x5e24), 0x75 }, ++ { CCI_REG8(0x5e25), 0x75 }, { CCI_REG8(0x5e26), 0x75 }, ++ { CCI_REG8(0x5e27), 0x75 }, { CCI_REG8(0x5e28), 0x75 }, ++ { CCI_REG8(0x5e29), 0x75 }, { CCI_REG8(0x5e2a), 0x75 }, ++ { CCI_REG8(0x5e2b), 0x75 }, { CCI_REG8(0x5e2c), 0x75 }, ++ { CCI_REG8(0x5e2d), 0x75 }, { CCI_REG8(0x5e2e), 0x75 }, ++ { CCI_REG8(0x5e2f), 0x75 }, { CCI_REG8(0x5e30), 0x75 }, ++ { CCI_REG8(0x5e31), 0x75 }, { CCI_REG8(0x5e32), 0x75 }, ++ { CCI_REG8(0x5e33), 0x75 }, { CCI_REG8(0x5e34), 0x75 }, ++ { CCI_REG8(0x5e35), 0x75 }, { CCI_REG8(0x5e36), 0x75 }, ++ { CCI_REG8(0x5e37), 0x75 }, { CCI_REG8(0x5e38), 0x75 }, ++ { CCI_REG8(0x5e39), 0x75 }, { CCI_REG8(0x5e3a), 0x75 }, ++ { CCI_REG8(0x5e3b), 0x75 }, { CCI_REG8(0x5e3c), 0x75 }, ++ { CCI_REG8(0x5e3d), 0x75 }, { CCI_REG8(0x5e3e), 0x75 }, ++ { CCI_REG8(0x5e3f), 0x75 }, { CCI_REG8(0x5e40), 0x75 }, ++ { CCI_REG8(0x5e41), 0x75 }, { CCI_REG8(0x5e42), 0x75 }, ++ { CCI_REG8(0x5e43), 0x75 }, { CCI_REG8(0x5e44), 0x75 }, ++ { CCI_REG8(0x5e45), 0x75 }, { CCI_REG8(0x5e46), 0x75 }, ++ { CCI_REG8(0x5e47), 0x75 }, { CCI_REG8(0x5e48), 0x75 }, ++ { CCI_REG8(0x5e49), 0x75 }, { CCI_REG8(0x5e4a), 0x75 }, ++ { CCI_REG8(0x5e4b), 0x75 }, { CCI_REG8(0x5e4c), 0x75 }, ++ { CCI_REG8(0x5e4d), 0x75 }, { CCI_REG8(0x5e4e), 0x75 }, ++ { CCI_REG8(0x5e4f), 0x75 }, { CCI_REG8(0x5e50), 0x75 }, ++ { CCI_REG8(0x5e51), 0x75 }, { CCI_REG8(0x5e52), 0x75 }, ++ { CCI_REG8(0x5e53), 0x75 }, { CCI_REG8(0x5e54), 0x75 }, ++ { CCI_REG8(0x5e55), 0x75 }, { CCI_REG8(0x5e56), 0x75 }, ++ { CCI_REG8(0x5e57), 0x75 }, { CCI_REG8(0x5e58), 0x75 }, ++ { CCI_REG8(0x5e59), 0x75 }, { CCI_REG8(0x5e5a), 0x75 }, ++ { CCI_REG8(0x5e5b), 0x75 }, { CCI_REG8(0x5e5c), 0x75 }, ++ { CCI_REG8(0x5e5d), 0x75 }, { CCI_REG8(0x5e5e), 0x75 }, ++ { CCI_REG8(0x5e5f), 0x75 }, { CCI_REG8(0x5e60), 0x75 }, ++ { CCI_REG8(0x5e61), 0x75 }, { CCI_REG8(0x5e62), 0x75 }, ++ { CCI_REG8(0x5e63), 0x75 }, { CCI_REG8(0x5e64), 0x75 }, ++ { CCI_REG8(0x5e65), 0x75 }, { CCI_REG8(0x5e66), 0x75 }, ++ { CCI_REG8(0x5e67), 0x75 }, { CCI_REG8(0x5e68), 0x75 }, ++ { CCI_REG8(0x5e69), 0x75 }, { CCI_REG8(0x5e6a), 0x75 }, ++ { CCI_REG8(0x5e6b), 0x75 }, { CCI_REG8(0x5e6c), 0x75 }, ++ { CCI_REG8(0x5e6d), 0x75 }, { CCI_REG8(0x5e6e), 0x75 }, ++ { CCI_REG8(0x5e6f), 0x75 }, { CCI_REG8(0x5e70), 0x75 }, ++ { CCI_REG8(0x5e71), 0x75 }, { CCI_REG8(0x5e72), 0x75 }, ++ { CCI_REG8(0x5e73), 0x75 }, { CCI_REG8(0x5e74), 0x75 }, ++ { CCI_REG8(0x5e75), 0x75 }, { CCI_REG8(0x5e76), 0x75 }, ++ { CCI_REG8(0x5e77), 0x75 }, { CCI_REG8(0x5e78), 0x75 }, ++ { CCI_REG8(0x5e79), 0x75 }, { CCI_REG8(0x5e7a), 0x75 }, ++ { CCI_REG8(0x5e7b), 0x75 }, { CCI_REG8(0x5e7c), 0x75 }, ++ { CCI_REG8(0x5e7d), 0x75 }, { CCI_REG8(0x5e7e), 0x75 }, ++ { CCI_REG8(0x5e7f), 0x75 }, { CCI_REG8(0x5e80), 0x75 }, ++ { CCI_REG8(0x5e81), 0x75 }, { CCI_REG8(0x5e82), 0x75 }, ++ { CCI_REG8(0x5e83), 0x75 }, { CCI_REG8(0x5e84), 0x75 }, ++ { CCI_REG8(0x5e85), 0x75 }, { CCI_REG8(0x5e86), 0x75 }, ++ { CCI_REG8(0x5e87), 0x75 }, { CCI_REG8(0x5e88), 0x75 }, ++ { CCI_REG8(0x5e89), 0x75 }, { CCI_REG8(0x5e8a), 0x75 }, ++ { CCI_REG8(0x5e8b), 0x75 }, { CCI_REG8(0x5e8c), 0x75 }, ++ { CCI_REG8(0x5e8d), 0x75 }, { CCI_REG8(0x5e8e), 0x75 }, ++ { CCI_REG8(0x5e8f), 0x75 }, { CCI_REG8(0x5e90), 0x75 }, ++ { CCI_REG8(0x5e91), 0x75 }, { CCI_REG8(0x5e92), 0x75 }, ++ { CCI_REG8(0x5e93), 0x75 }, { CCI_REG8(0x5e94), 0x75 }, ++ { CCI_REG8(0x5e95), 0x75 }, { CCI_REG8(0x5e96), 0x75 }, ++ { CCI_REG8(0x5e97), 0x75 }, { CCI_REG8(0x5e98), 0x75 }, ++ { CCI_REG8(0x5e99), 0x75 }, { CCI_REG8(0x5e9a), 0x75 }, ++ { CCI_REG8(0x5e9b), 0x75 }, { CCI_REG8(0x5e9c), 0x75 }, ++ { CCI_REG8(0x5e9d), 0x75 }, { CCI_REG8(0x5e9e), 0x75 }, ++ { CCI_REG8(0x5e9f), 0x75 }, { CCI_REG8(0x5ea0), 0x75 }, ++ { CCI_REG8(0x5ea1), 0x75 }, { CCI_REG8(0x5ea2), 0x75 }, ++ { CCI_REG8(0x5ea3), 0x75 }, { CCI_REG8(0x5ea4), 0x75 }, ++ { CCI_REG8(0x5ea5), 0x75 }, { CCI_REG8(0x5ea6), 0x75 }, ++ { CCI_REG8(0x5ea7), 0x75 }, { CCI_REG8(0x5ea8), 0x75 }, ++ { CCI_REG8(0x5ea9), 0x75 }, { CCI_REG8(0x5eaa), 0x75 }, ++ { CCI_REG8(0x5eab), 0x75 }, { CCI_REG8(0x5eac), 0x75 }, ++ { CCI_REG8(0x5ead), 0x75 }, { CCI_REG8(0x5eae), 0x75 }, ++ { CCI_REG8(0x5eaf), 0x75 }, { CCI_REG8(0x5eb0), 0x75 }, ++ { CCI_REG8(0x5eb1), 0x75 }, { CCI_REG8(0x5eb2), 0x75 }, ++ { CCI_REG8(0x5eb3), 0x75 }, { CCI_REG8(0x5eb4), 0x75 }, ++ { CCI_REG8(0x5eb5), 0x75 }, { CCI_REG8(0x5eb6), 0x75 }, ++ { CCI_REG8(0x5eb7), 0x75 }, { CCI_REG8(0x5eb8), 0x75 }, ++ { CCI_REG8(0x5eb9), 0x75 }, { CCI_REG8(0x5eba), 0x75 }, ++ { CCI_REG8(0x5ebb), 0x75 }, { CCI_REG8(0x5ebc), 0x75 }, ++ { CCI_REG8(0x5ebd), 0x75 }, { CCI_REG8(0x5ebe), 0x75 }, ++ { CCI_REG8(0x5ebf), 0x75 }, { CCI_REG8(0x5ec0), 0x75 }, ++ { CCI_REG8(0x5ec1), 0x75 }, { CCI_REG8(0x5ec2), 0x75 }, ++ { CCI_REG8(0x5ec3), 0x75 }, { CCI_REG8(0x5ec4), 0x75 }, ++ { CCI_REG8(0x5ec5), 0x75 }, { CCI_REG8(0x5ec6), 0x75 }, ++ { CCI_REG8(0x5ec7), 0x75 }, { CCI_REG8(0x5ec8), 0x75 }, ++ { CCI_REG8(0x5ec9), 0x75 }, { CCI_REG8(0x5eca), 0x75 }, ++ { CCI_REG8(0x5ecb), 0x75 }, { CCI_REG8(0x5ecc), 0x75 }, ++ { CCI_REG8(0x5ecd), 0x75 }, { CCI_REG8(0x5ece), 0x75 }, ++ { CCI_REG8(0x5ecf), 0x75 }, { CCI_REG8(0x5ed0), 0x75 }, ++ { CCI_REG8(0x5ed1), 0x75 }, { CCI_REG8(0x5ed2), 0x75 }, ++ { CCI_REG8(0x5ed3), 0x75 }, { CCI_REG8(0x5ed4), 0x75 }, ++ { CCI_REG8(0x5ed5), 0x75 }, { CCI_REG8(0x5ed6), 0x75 }, ++ { CCI_REG8(0x5ed7), 0x75 }, { CCI_REG8(0x5ed8), 0x75 }, ++ { CCI_REG8(0x5ed9), 0x75 }, { CCI_REG8(0x5eda), 0x75 }, ++ { CCI_REG8(0x5edb), 0x75 }, { CCI_REG8(0x5edc), 0x75 }, ++ { CCI_REG8(0x5edd), 0x75 }, { CCI_REG8(0x5ede), 0x75 }, ++ { CCI_REG8(0x5edf), 0x75 }, { CCI_REG8(0xfff9), 0x08 }, ++ { CCI_REG8(0x1570), 0x00 }, { CCI_REG8(0x15d0), 0x00 }, ++ { CCI_REG8(0x15a0), 0x02 }, { CCI_REG8(0x15a1), 0x00 }, ++ { CCI_REG8(0x15a2), 0x02 }, { CCI_REG8(0x15a3), 0x76 }, ++ { CCI_REG8(0x15a4), 0x03 }, { CCI_REG8(0x15a5), 0x08 }, ++ { CCI_REG8(0x15a6), 0x00 }, { CCI_REG8(0x15a7), 0x60 }, ++ { CCI_REG8(0x15a8), 0x01 }, { CCI_REG8(0x15a9), 0x00 }, ++ { CCI_REG8(0x15aa), 0x02 }, { CCI_REG8(0x15ab), 0x00 }, ++ { CCI_REG8(0x1600), 0x02 }, { CCI_REG8(0x1601), 0x00 }, ++ { CCI_REG8(0x1602), 0x02 }, { CCI_REG8(0x1603), 0x76 }, ++ { CCI_REG8(0x1604), 0x03 }, { CCI_REG8(0x1605), 0x08 }, ++ { CCI_REG8(0x1606), 0x00 }, { CCI_REG8(0x1607), 0x60 }, ++ { CCI_REG8(0x1608), 0x01 }, { CCI_REG8(0x1609), 0x00 }, ++ { CCI_REG8(0x160a), 0x02 }, { CCI_REG8(0x160b), 0x00 }, ++ { CCI_REG8(0x1633), 0x03 }, { CCI_REG8(0x1634), 0x01 }, ++ { CCI_REG8(0x163c), 0x3a }, { CCI_REG8(0x163d), 0x01 }, ++ { CCI_REG8(0x1648), 0x32 }, { CCI_REG8(0x1658), 0x01 }, ++ { CCI_REG8(0x1659), 0x01 }, { CCI_REG8(0x165f), 0x01 }, ++ { CCI_REG8(0x1677), 0x01 }, { CCI_REG8(0x1690), 0x08 }, ++ { CCI_REG8(0x1691), 0x00 }, { CCI_REG8(0x1692), 0x20 }, ++ { CCI_REG8(0x1693), 0x00 }, { CCI_REG8(0x1694), 0x10 }, ++ { CCI_REG8(0x1695), 0x14 }, { CCI_REG8(0x1696), 0x10 }, ++ { CCI_REG8(0x1697), 0x0e }, { CCI_REG8(0x1730), 0x01 }, ++ { CCI_REG8(0x1732), 0x00 }, { CCI_REG8(0x1733), 0x10 }, ++ { CCI_REG8(0x1734), 0x01 }, { CCI_REG8(0x1735), 0x00 }, ++ { CCI_REG8(0x1748), 0x01 }, { CCI_REG8(0xfff9), 0x06 }, ++ { CCI_REG8(0x5000), 0xff }, { CCI_REG8(0x5001), 0x3d }, ++ { CCI_REG8(0x5002), 0xf5 }, { CCI_REG8(0x5004), 0x80 }, ++ { CCI_REG8(0x5006), 0x04 }, { CCI_REG8(0x5061), 0x20 }, ++ { CCI_REG8(0x5063), 0x20 }, { CCI_REG8(0x5064), 0x24 }, ++ { CCI_REG8(0x5065), 0x00 }, { CCI_REG8(0x5066), 0x1b }, ++ { CCI_REG8(0x5067), 0x00 }, { CCI_REG8(0x5068), 0x03 }, ++ { CCI_REG8(0x5069), 0x10 }, { CCI_REG8(0x506a), 0x20 }, ++ { CCI_REG8(0x506b), 0x04 }, { CCI_REG8(0x506c), 0x04 }, ++ { CCI_REG8(0x506d), 0x0c }, { CCI_REG8(0x506e), 0x0c }, ++ { CCI_REG8(0x506f), 0x04 }, { CCI_REG8(0x5070), 0x0c }, ++ { CCI_REG8(0x5071), 0x14 }, { CCI_REG8(0x5072), 0x1c }, ++ { CCI_REG8(0x5073), 0x01 }, { CCI_REG8(0x5074), 0x01 }, ++ { CCI_REG8(0x5075), 0xbe }, { CCI_REG8(0x5083), 0x00 }, ++ { CCI_REG8(0x5114), 0x03 }, { CCI_REG8(0x51b0), 0x00 }, ++ { CCI_REG8(0x51b3), 0x0e }, { CCI_REG8(0x51b5), 0x02 }, ++ { CCI_REG8(0x51b6), 0x00 }, { CCI_REG8(0x51b7), 0x00 }, ++ { CCI_REG8(0x51b8), 0x00 }, { CCI_REG8(0x51b9), 0x70 }, ++ { CCI_REG8(0x51ba), 0x00 }, { CCI_REG8(0x51bb), 0x10 }, ++ { CCI_REG8(0x51bc), 0x00 }, { CCI_REG8(0x51bd), 0x00 }, ++ { CCI_REG8(0x51d2), 0xff }, { CCI_REG8(0x51d3), 0x1c }, ++ { CCI_REG8(0x5250), 0x34 }, { CCI_REG8(0x5251), 0x00 }, ++ { CCI_REG8(0x525b), 0x00 }, { CCI_REG8(0x525d), 0x00 }, ++ { CCI_REG8(0x527a), 0x00 }, { CCI_REG8(0x527b), 0x38 }, ++ { CCI_REG8(0x527c), 0x00 }, { CCI_REG8(0x527d), 0x4b }, ++ { CCI_REG8(0x5286), 0x1b }, { CCI_REG8(0x5287), 0x40 }, ++ { CCI_REG8(0x5290), 0x00 }, { CCI_REG8(0x5291), 0x50 }, ++ { CCI_REG8(0x5292), 0x00 }, { CCI_REG8(0x5293), 0x50 }, ++ { CCI_REG8(0x5294), 0x00 }, { CCI_REG8(0x5295), 0x50 }, ++ { CCI_REG8(0x5296), 0x00 }, { CCI_REG8(0x5297), 0x50 }, ++ { CCI_REG8(0x5298), 0x00 }, { CCI_REG8(0x5299), 0x50 }, ++ { CCI_REG8(0x529a), 0x01 }, { CCI_REG8(0x529b), 0x00 }, ++ { CCI_REG8(0x529c), 0x01 }, { CCI_REG8(0x529d), 0x00 }, ++ { CCI_REG8(0x529e), 0x00 }, { CCI_REG8(0x529f), 0x50 }, ++ { CCI_REG8(0x52a0), 0x00 }, { CCI_REG8(0x52a1), 0x50 }, ++ { CCI_REG8(0x52a2), 0x01 }, { CCI_REG8(0x52a3), 0x00 }, ++ { CCI_REG8(0x52a4), 0x01 }, { CCI_REG8(0x52a5), 0x00 }, ++ { CCI_REG8(0x52a6), 0x00 }, { CCI_REG8(0x52a7), 0x50 }, ++ { CCI_REG8(0x52a8), 0x00 }, { CCI_REG8(0x52a9), 0x50 }, ++ { CCI_REG8(0x52aa), 0x00 }, { CCI_REG8(0x52ab), 0x50 }, ++ { CCI_REG8(0x52ac), 0x00 }, { CCI_REG8(0x52ad), 0x50 }, ++ { CCI_REG8(0x52ae), 0x00 }, { CCI_REG8(0x52af), 0x50 }, ++ { CCI_REG8(0x52b0), 0x00 }, { CCI_REG8(0x52b1), 0x50 }, ++ { CCI_REG8(0x52b2), 0x00 }, { CCI_REG8(0x52b3), 0x50 }, ++ { CCI_REG8(0x52b4), 0x00 }, { CCI_REG8(0x52b5), 0x50 }, ++ { CCI_REG8(0x52b6), 0x00 }, { CCI_REG8(0x52b7), 0x50 }, ++ { CCI_REG8(0x52b8), 0x00 }, { CCI_REG8(0x52b9), 0x50 }, ++ { CCI_REG8(0x52ba), 0x01 }, { CCI_REG8(0x52bb), 0x00 }, ++ { CCI_REG8(0x52bc), 0x01 }, { CCI_REG8(0x52bd), 0x00 }, ++ { CCI_REG8(0x52be), 0x00 }, { CCI_REG8(0x52bf), 0x50 }, ++ { CCI_REG8(0x52c0), 0x00 }, { CCI_REG8(0x52c1), 0x50 }, ++ { CCI_REG8(0x52c2), 0x01 }, { CCI_REG8(0x52c3), 0x00 }, ++ { CCI_REG8(0x52c4), 0x01 }, { CCI_REG8(0x52c5), 0x00 }, ++ { CCI_REG8(0x52c6), 0x00 }, { CCI_REG8(0x52c7), 0x50 }, ++ { CCI_REG8(0x52c8), 0x00 }, { CCI_REG8(0x52c9), 0x50 }, ++ { CCI_REG8(0x52ca), 0x00 }, { CCI_REG8(0x52cb), 0x50 }, ++ { CCI_REG8(0x52cc), 0x00 }, { CCI_REG8(0x52cd), 0x50 }, ++ { CCI_REG8(0x52ce), 0x00 }, { CCI_REG8(0x52cf), 0x50 }, ++ { CCI_REG8(0x52f0), 0x04 }, { CCI_REG8(0x52f1), 0x03 }, ++ { CCI_REG8(0x52f2), 0x02 }, { CCI_REG8(0x52f3), 0x01 }, ++ { CCI_REG8(0x52f4), 0x08 }, { CCI_REG8(0x52f5), 0x07 }, ++ { CCI_REG8(0x52f6), 0x06 }, { CCI_REG8(0x52f7), 0x05 }, ++ { CCI_REG8(0x52f8), 0x0c }, { CCI_REG8(0x52f9), 0x0b }, ++ { CCI_REG8(0x52fa), 0x0a }, { CCI_REG8(0x52fb), 0x09 }, ++ { CCI_REG8(0x52fc), 0x10 }, { CCI_REG8(0x52fd), 0x0f }, ++ { CCI_REG8(0x52fe), 0x0e }, { CCI_REG8(0x52ff), 0x0d }, ++ { CCI_REG8(0x5300), 0x14 }, { CCI_REG8(0x5301), 0x13 }, ++ { CCI_REG8(0x5302), 0x12 }, { CCI_REG8(0x5303), 0x11 }, ++ { CCI_REG8(0x5304), 0x18 }, { CCI_REG8(0x5305), 0x17 }, ++ { CCI_REG8(0x5306), 0x16 }, { CCI_REG8(0x5307), 0x15 }, ++ { CCI_REG8(0x5308), 0x1c }, { CCI_REG8(0x5309), 0x1b }, ++ { CCI_REG8(0x530a), 0x1a }, { CCI_REG8(0x530b), 0x19 }, ++ { CCI_REG8(0x530c), 0x20 }, { CCI_REG8(0x530d), 0x1f }, ++ { CCI_REG8(0x530e), 0x1e }, { CCI_REG8(0x530f), 0x1d }, ++ { CCI_REG8(0x5310), 0x03 }, { CCI_REG8(0x5311), 0xe8 }, ++ { CCI_REG8(0x5331), 0x0a }, { CCI_REG8(0x5332), 0x43 }, ++ { CCI_REG8(0x5333), 0x45 }, { CCI_REG8(0x5353), 0x09 }, ++ { CCI_REG8(0x5354), 0x00 }, { CCI_REG8(0x5414), 0x03 }, ++ { CCI_REG8(0x54b0), 0x10 }, { CCI_REG8(0x54b3), 0x0e }, ++ { CCI_REG8(0x54b5), 0x02 }, { CCI_REG8(0x54b6), 0x00 }, ++ { CCI_REG8(0x54b7), 0x00 }, { CCI_REG8(0x54b8), 0x00 }, ++ { CCI_REG8(0x54b9), 0x70 }, { CCI_REG8(0x54ba), 0x00 }, ++ { CCI_REG8(0x54bb), 0x10 }, { CCI_REG8(0x54bc), 0x00 }, ++ { CCI_REG8(0x54bd), 0x00 }, { CCI_REG8(0x54d2), 0xff }, ++ { CCI_REG8(0x54d3), 0x1c }, { CCI_REG8(0x5510), 0x03 }, ++ { CCI_REG8(0x5511), 0xe8 }, { CCI_REG8(0x5550), 0x6c }, ++ { CCI_REG8(0x5551), 0x00 }, { CCI_REG8(0x557a), 0x00 }, ++ { CCI_REG8(0x557b), 0x38 }, { CCI_REG8(0x557c), 0x00 }, ++ { CCI_REG8(0x557d), 0x4b }, { CCI_REG8(0x5590), 0x00 }, ++ { CCI_REG8(0x5591), 0x50 }, { CCI_REG8(0x5592), 0x00 }, ++ { CCI_REG8(0x5593), 0x50 }, { CCI_REG8(0x5594), 0x00 }, ++ { CCI_REG8(0x5595), 0x50 }, { CCI_REG8(0x5596), 0x00 }, ++ { CCI_REG8(0x5597), 0x50 }, { CCI_REG8(0x5598), 0x00 }, ++ { CCI_REG8(0x5599), 0x50 }, { CCI_REG8(0x559a), 0x01 }, ++ { CCI_REG8(0x559b), 0x00 }, { CCI_REG8(0x559c), 0x01 }, ++ { CCI_REG8(0x559d), 0x00 }, { CCI_REG8(0x559e), 0x00 }, ++ { CCI_REG8(0x559f), 0x50 }, { CCI_REG8(0x55a0), 0x00 }, ++ { CCI_REG8(0x55a1), 0x50 }, { CCI_REG8(0x55a2), 0x01 }, ++ { CCI_REG8(0x55a3), 0x00 }, { CCI_REG8(0x55a4), 0x01 }, ++ { CCI_REG8(0x55a5), 0x00 }, { CCI_REG8(0x55a6), 0x00 }, ++ { CCI_REG8(0x55a7), 0x50 }, { CCI_REG8(0x55a8), 0x00 }, ++ { CCI_REG8(0x55a9), 0x50 }, { CCI_REG8(0x55aa), 0x00 }, ++ { CCI_REG8(0x55ab), 0x50 }, { CCI_REG8(0x55ac), 0x00 }, ++ { CCI_REG8(0x55ad), 0x50 }, { CCI_REG8(0x55ae), 0x00 }, ++ { CCI_REG8(0x55af), 0x50 }, { CCI_REG8(0x55b0), 0x00 }, ++ { CCI_REG8(0x55b1), 0x50 }, { CCI_REG8(0x55b2), 0x00 }, ++ { CCI_REG8(0x55b3), 0x50 }, { CCI_REG8(0x55b4), 0x00 }, ++ { CCI_REG8(0x55b5), 0x50 }, { CCI_REG8(0x55b6), 0x00 }, ++ { CCI_REG8(0x55b7), 0x50 }, { CCI_REG8(0x55b8), 0x00 }, ++ { CCI_REG8(0x55b9), 0x50 }, { CCI_REG8(0x55ba), 0x01 }, ++ { CCI_REG8(0x55bb), 0x00 }, { CCI_REG8(0x55bc), 0x01 }, ++ { CCI_REG8(0x55bd), 0x00 }, { CCI_REG8(0x55be), 0x00 }, ++ { CCI_REG8(0x55bf), 0x50 }, { CCI_REG8(0x55c0), 0x00 }, ++ { CCI_REG8(0x55c1), 0x50 }, { CCI_REG8(0x55c2), 0x01 }, ++ { CCI_REG8(0x55c3), 0x00 }, { CCI_REG8(0x55c4), 0x01 }, ++ { CCI_REG8(0x55c5), 0x00 }, { CCI_REG8(0x55c6), 0x00 }, ++ { CCI_REG8(0x55c7), 0x50 }, { CCI_REG8(0x55c8), 0x00 }, ++ { CCI_REG8(0x55c9), 0x50 }, { CCI_REG8(0x55ca), 0x00 }, ++ { CCI_REG8(0x55cb), 0x50 }, { CCI_REG8(0x55cc), 0x00 }, ++ { CCI_REG8(0x55cd), 0x50 }, { CCI_REG8(0x55ce), 0x00 }, ++ { CCI_REG8(0x55cf), 0x50 }, { CCI_REG8(0x55f0), 0x04 }, ++ { CCI_REG8(0x55f1), 0x03 }, { CCI_REG8(0x55f2), 0x02 }, ++ { CCI_REG8(0x55f3), 0x01 }, { CCI_REG8(0x55f4), 0x08 }, ++ { CCI_REG8(0x55f5), 0x07 }, { CCI_REG8(0x55f6), 0x06 }, ++ { CCI_REG8(0x55f7), 0x05 }, { CCI_REG8(0x55f8), 0x0c }, ++ { CCI_REG8(0x55f9), 0x0b }, { CCI_REG8(0x55fa), 0x0a }, ++ { CCI_REG8(0x55fb), 0x09 }, { CCI_REG8(0x55fc), 0x10 }, ++ { CCI_REG8(0x55fd), 0x0f }, { CCI_REG8(0x55fe), 0x0e }, ++ { CCI_REG8(0x55ff), 0x0d }, { CCI_REG8(0x5600), 0x14 }, ++ { CCI_REG8(0x5601), 0x13 }, { CCI_REG8(0x5602), 0x12 }, ++ { CCI_REG8(0x5603), 0x11 }, { CCI_REG8(0x5604), 0x18 }, ++ { CCI_REG8(0x5605), 0x17 }, { CCI_REG8(0x5606), 0x16 }, ++ { CCI_REG8(0x5607), 0x15 }, { CCI_REG8(0x5608), 0x1c }, ++ { CCI_REG8(0x5609), 0x1b }, { CCI_REG8(0x560a), 0x1a }, ++ { CCI_REG8(0x560b), 0x19 }, { CCI_REG8(0x560c), 0x20 }, ++ { CCI_REG8(0x560d), 0x1f }, { CCI_REG8(0x560e), 0x1e }, ++ { CCI_REG8(0x560f), 0x1d }, { CCI_REG8(0x5631), 0x02 }, ++ { CCI_REG8(0x5632), 0x42 }, { CCI_REG8(0x5633), 0x24 }, ++ { CCI_REG8(0x5653), 0x09 }, { CCI_REG8(0x5654), 0x00 }, ++ { CCI_REG8(0x5714), 0x03 }, { CCI_REG8(0x57b0), 0x10 }, ++ { CCI_REG8(0x57b3), 0x0e }, { CCI_REG8(0x57b5), 0x02 }, ++ { CCI_REG8(0x57b6), 0x00 }, { CCI_REG8(0x57b7), 0x00 }, ++ { CCI_REG8(0x57b8), 0x00 }, { CCI_REG8(0x57b9), 0x70 }, ++ { CCI_REG8(0x57ba), 0x00 }, { CCI_REG8(0x57bb), 0x10 }, ++ { CCI_REG8(0x57bc), 0x00 }, { CCI_REG8(0x57bd), 0x00 }, ++ { CCI_REG8(0x57d2), 0xff }, { CCI_REG8(0x57d3), 0x1c }, ++ { CCI_REG8(0x5810), 0x03 }, { CCI_REG8(0x5811), 0xe8 }, ++ { CCI_REG8(0x5850), 0x6c }, { CCI_REG8(0x5851), 0x00 }, ++ { CCI_REG8(0x587a), 0x00 }, { CCI_REG8(0x587b), 0x38 }, ++ { CCI_REG8(0x587c), 0x00 }, { CCI_REG8(0x587d), 0x4b }, ++ { CCI_REG8(0x5890), 0x00 }, { CCI_REG8(0x5891), 0x50 }, ++ { CCI_REG8(0x5892), 0x00 }, { CCI_REG8(0x5893), 0x50 }, ++ { CCI_REG8(0x5894), 0x00 }, { CCI_REG8(0x5895), 0x50 }, ++ { CCI_REG8(0x5896), 0x00 }, { CCI_REG8(0x5897), 0x50 }, ++ { CCI_REG8(0x5898), 0x00 }, { CCI_REG8(0x5899), 0x50 }, ++ { CCI_REG8(0x589a), 0x01 }, { CCI_REG8(0x589b), 0x00 }, ++ { CCI_REG8(0x589c), 0x01 }, { CCI_REG8(0x589d), 0x00 }, ++ { CCI_REG8(0x589e), 0x00 }, { CCI_REG8(0x589f), 0x50 }, ++ { CCI_REG8(0x58a0), 0x00 }, { CCI_REG8(0x58a1), 0x50 }, ++ { CCI_REG8(0x58a2), 0x01 }, { CCI_REG8(0x58a3), 0x00 }, ++ { CCI_REG8(0x58a4), 0x01 }, { CCI_REG8(0x58a5), 0x00 }, ++ { CCI_REG8(0x58a6), 0x00 }, { CCI_REG8(0x58a7), 0x50 }, ++ { CCI_REG8(0x58a8), 0x00 }, { CCI_REG8(0x58a9), 0x50 }, ++ { CCI_REG8(0x58aa), 0x00 }, { CCI_REG8(0x58ab), 0x50 }, ++ { CCI_REG8(0x58ac), 0x00 }, { CCI_REG8(0x58ad), 0x50 }, ++ { CCI_REG8(0x58ae), 0x00 }, { CCI_REG8(0x58af), 0x50 }, ++ { CCI_REG8(0x58b0), 0x00 }, { CCI_REG8(0x58b1), 0x50 }, ++ { CCI_REG8(0x58b2), 0x00 }, { CCI_REG8(0x58b3), 0x50 }, ++ { CCI_REG8(0x58b4), 0x00 }, { CCI_REG8(0x58b5), 0x50 }, ++ { CCI_REG8(0x58b6), 0x00 }, { CCI_REG8(0x58b7), 0x50 }, ++ { CCI_REG8(0x58b8), 0x00 }, { CCI_REG8(0x58b9), 0x50 }, ++ { CCI_REG8(0x58ba), 0x01 }, { CCI_REG8(0x58bb), 0x00 }, ++ { CCI_REG8(0x58bc), 0x01 }, { CCI_REG8(0x58bd), 0x00 }, ++ { CCI_REG8(0x58be), 0x00 }, { CCI_REG8(0x58bf), 0x50 }, ++ { CCI_REG8(0x58c0), 0x00 }, { CCI_REG8(0x58c1), 0x50 }, ++ { CCI_REG8(0x58c2), 0x01 }, { CCI_REG8(0x58c3), 0x00 }, ++ { CCI_REG8(0x58c4), 0x01 }, { CCI_REG8(0x58c5), 0x00 }, ++ { CCI_REG8(0x58c6), 0x00 }, { CCI_REG8(0x58c7), 0x50 }, ++ { CCI_REG8(0x58c8), 0x00 }, { CCI_REG8(0x58c9), 0x50 }, ++ { CCI_REG8(0x58ca), 0x00 }, { CCI_REG8(0x58cb), 0x50 }, ++ { CCI_REG8(0x58cc), 0x00 }, { CCI_REG8(0x58cd), 0x50 }, ++ { CCI_REG8(0x58ce), 0x00 }, { CCI_REG8(0x58cf), 0x50 }, ++ { CCI_REG8(0x58f0), 0x04 }, { CCI_REG8(0x58f1), 0x03 }, ++ { CCI_REG8(0x58f2), 0x02 }, { CCI_REG8(0x58f3), 0x01 }, ++ { CCI_REG8(0x58f4), 0x08 }, { CCI_REG8(0x58f5), 0x07 }, ++ { CCI_REG8(0x58f6), 0x06 }, { CCI_REG8(0x58f7), 0x05 }, ++ { CCI_REG8(0x58f8), 0x0c }, { CCI_REG8(0x58f9), 0x0b }, ++ { CCI_REG8(0x58fa), 0x0a }, { CCI_REG8(0x58fb), 0x09 }, ++ { CCI_REG8(0x58fc), 0x10 }, { CCI_REG8(0x58fd), 0x0f }, ++ { CCI_REG8(0x58fe), 0x0e }, { CCI_REG8(0x58ff), 0x0d }, ++ { CCI_REG8(0x5900), 0x14 }, { CCI_REG8(0x5901), 0x13 }, ++ { CCI_REG8(0x5902), 0x12 }, { CCI_REG8(0x5903), 0x11 }, ++ { CCI_REG8(0x5904), 0x18 }, { CCI_REG8(0x5905), 0x17 }, ++ { CCI_REG8(0x5906), 0x16 }, { CCI_REG8(0x5907), 0x15 }, ++ { CCI_REG8(0x5908), 0x1c }, { CCI_REG8(0x5909), 0x1b }, ++ { CCI_REG8(0x590a), 0x1a }, { CCI_REG8(0x590b), 0x19 }, ++ { CCI_REG8(0x590c), 0x20 }, { CCI_REG8(0x590d), 0x1f }, ++ { CCI_REG8(0x590e), 0x1e }, { CCI_REG8(0x590f), 0x1d }, ++ { CCI_REG8(0x5931), 0x02 }, { CCI_REG8(0x5932), 0x42 }, ++ { CCI_REG8(0x5933), 0x24 }, { CCI_REG8(0x5953), 0x09 }, ++ { CCI_REG8(0x5954), 0x00 }, { CCI_REG8(0x5989), 0x84 }, ++ { CCI_REG8(0x59c3), 0x04 }, { CCI_REG8(0x59c4), 0x24 }, ++ { CCI_REG8(0x59c5), 0x40 }, { CCI_REG8(0x59c6), 0x1b }, ++ { CCI_REG8(0x59c7), 0x40 }, { CCI_REG8(0x5a02), 0x0f }, ++ { CCI_REG8(0x5f00), 0x29 }, { CCI_REG8(0x5f2d), 0x28 }, ++ { CCI_REG8(0x5f2e), 0x28 }, { CCI_REG8(0x6801), 0x11 }, ++ { CCI_REG8(0x6802), 0x3f }, { CCI_REG8(0x6803), 0xe7 }, ++ { CCI_REG8(0x6825), 0x0f }, { CCI_REG8(0x6826), 0x20 }, ++ { CCI_REG8(0x6827), 0x00 }, { CCI_REG8(0x6829), 0x16 }, ++ { CCI_REG8(0x682b), 0xb3 }, { CCI_REG8(0x682c), 0x01 }, ++ { CCI_REG8(0x6832), 0xff }, { CCI_REG8(0x6833), 0xff }, ++ { CCI_REG8(0x6898), 0x80 }, { CCI_REG8(0x6899), 0x80 }, ++ { CCI_REG8(0x689b), 0x40 }, { CCI_REG8(0x689c), 0x20 }, ++ { CCI_REG8(0x689d), 0x20 }, { CCI_REG8(0x689e), 0x80 }, ++ { CCI_REG8(0x689f), 0x60 }, { CCI_REG8(0x68a0), 0x40 }, ++ { CCI_REG8(0x68a4), 0x40 }, { CCI_REG8(0x68a5), 0x20 }, ++ { CCI_REG8(0x68a6), 0x00 }, { CCI_REG8(0x68b6), 0x80 }, ++ { CCI_REG8(0x68b7), 0x80 }, { CCI_REG8(0x68b8), 0x80 }, ++ { CCI_REG8(0x68bc), 0x80 }, { CCI_REG8(0x68bd), 0x80 }, ++ { CCI_REG8(0x68be), 0x80 }, { CCI_REG8(0x68bf), 0x40 }, ++ { CCI_REG8(0x68c2), 0x80 }, { CCI_REG8(0x68c3), 0x80 }, ++ { CCI_REG8(0x68c4), 0x60 }, { CCI_REG8(0x68c5), 0x30 }, ++ { CCI_REG8(0x6918), 0x80 }, { CCI_REG8(0x6919), 0x80 }, ++ { CCI_REG8(0x691b), 0x40 }, { CCI_REG8(0x691c), 0x20 }, ++ { CCI_REG8(0x691d), 0x20 }, { CCI_REG8(0x691e), 0x80 }, ++ { CCI_REG8(0x691f), 0x60 }, { CCI_REG8(0x6920), 0x40 }, ++ { CCI_REG8(0x6924), 0x40 }, { CCI_REG8(0x6925), 0x20 }, ++ { CCI_REG8(0x6926), 0x00 }, { CCI_REG8(0x6936), 0x40 }, ++ { CCI_REG8(0x6937), 0x40 }, { CCI_REG8(0x6938), 0x20 }, ++ { CCI_REG8(0x6939), 0x20 }, { CCI_REG8(0x693a), 0x10 }, ++ { CCI_REG8(0x693b), 0x10 }, { CCI_REG8(0x693c), 0x20 }, ++ { CCI_REG8(0x693d), 0x20 }, { CCI_REG8(0x693e), 0x10 }, ++ { CCI_REG8(0x693f), 0x10 }, { CCI_REG8(0x6940), 0x00 }, ++ { CCI_REG8(0x6941), 0x00 }, { CCI_REG8(0x6942), 0x08 }, ++ { CCI_REG8(0x6943), 0x08 }, { CCI_REG8(0x6944), 0x00 }, ++ { CCI_REG8(0x69c2), 0x07 }, { CCI_REG8(0x6a20), 0x01 }, ++ { CCI_REG8(0x6a23), 0x10 }, { CCI_REG8(0x6a26), 0x3d }, ++ { CCI_REG8(0x6a27), 0x3e }, { CCI_REG8(0x6a38), 0x02 }, ++ { CCI_REG8(0x6a39), 0x20 }, { CCI_REG8(0x6a3a), 0x02 }, ++ { CCI_REG8(0x6a3b), 0x84 }, { CCI_REG8(0x6a3e), 0x02 }, ++ { CCI_REG8(0x6a3f), 0x20 }, { CCI_REG8(0x6a47), 0x3b }, ++ { CCI_REG8(0x6a63), 0x04 }, { CCI_REG8(0x6a65), 0x00 }, ++ { CCI_REG8(0x6a67), 0x0f }, { CCI_REG8(0x6b22), 0x07 }, ++ { CCI_REG8(0x6b23), 0xc2 }, { CCI_REG8(0x6b2f), 0x00 }, ++ { CCI_REG8(0x6b60), 0x1f }, { CCI_REG8(0x6bd2), 0x5a }, ++ { CCI_REG8(0x6c20), 0x50 }, { CCI_REG8(0x6c60), 0x50 }, ++ { CCI_REG8(0x6c61), 0x06 }, { CCI_REG8(0x7318), 0x04 }, ++ { CCI_REG8(0x7319), 0x01 }, { CCI_REG8(0x731a), 0x04 }, ++ { CCI_REG8(0x731b), 0x01 }, { CCI_REG8(0x731c), 0x00 }, ++ { CCI_REG8(0x731d), 0x00 }, { CCI_REG8(0x731e), 0x04 }, ++ { CCI_REG8(0x731f), 0x01 }, { CCI_REG8(0x7320), 0x04 }, ++ { CCI_REG8(0x7321), 0x00 }, { CCI_REG8(0x7322), 0x04 }, ++ { CCI_REG8(0x7323), 0x00 }, { CCI_REG8(0x7324), 0x04 }, ++ { CCI_REG8(0x7325), 0x00 }, { CCI_REG8(0x7326), 0x04 }, ++ { CCI_REG8(0x7327), 0x00 }, { CCI_REG8(0x7600), 0x00 }, ++ { CCI_REG8(0x7601), 0x00 }, { CCI_REG8(0x7602), 0x10 }, ++ { CCI_REG8(0x7603), 0x00 }, { CCI_REG8(0x7604), 0x00 }, ++ { CCI_REG8(0x7605), 0x00 }, { CCI_REG8(0x7606), 0x10 }, ++ { CCI_REG8(0x7607), 0x00 }, { CCI_REG8(0x7608), 0x00 }, ++ { CCI_REG8(0x7609), 0x00 }, { CCI_REG8(0x760a), 0x10 }, ++ { CCI_REG8(0x760b), 0x00 }, { CCI_REG8(0x760c), 0x00 }, ++ { CCI_REG8(0x760d), 0x00 }, { CCI_REG8(0x760e), 0x10 }, ++ { CCI_REG8(0x760f), 0x00 }, { CCI_REG8(0x7610), 0x00 }, ++ { CCI_REG8(0x7611), 0x00 }, { CCI_REG8(0x7612), 0x10 }, ++ { CCI_REG8(0x7613), 0x00 }, { CCI_REG8(0x7614), 0x00 }, ++ { CCI_REG8(0x7615), 0x00 }, { CCI_REG8(0x7616), 0x10 }, ++ { CCI_REG8(0x7617), 0x00 }, { CCI_REG8(0x7618), 0x00 }, ++ { CCI_REG8(0x7619), 0x00 }, { CCI_REG8(0x761a), 0x10 }, ++ { CCI_REG8(0x761b), 0x00 }, { CCI_REG8(0x761c), 0x00 }, ++ { CCI_REG8(0x761d), 0x00 }, { CCI_REG8(0x761e), 0x10 }, ++ { CCI_REG8(0x761f), 0x00 }, { CCI_REG8(0x7620), 0x00 }, ++ { CCI_REG8(0x7621), 0x00 }, { CCI_REG8(0x7622), 0x10 }, ++ { CCI_REG8(0x7623), 0x00 }, { CCI_REG8(0x7624), 0x00 }, ++ { CCI_REG8(0x7625), 0x00 }, { CCI_REG8(0x7626), 0x10 }, ++ { CCI_REG8(0x7627), 0x00 }, { CCI_REG8(0x7628), 0x00 }, ++ { CCI_REG8(0x7629), 0x00 }, { CCI_REG8(0x762a), 0x10 }, ++ { CCI_REG8(0x762b), 0x00 }, { CCI_REG8(0x762c), 0x00 }, ++ { CCI_REG8(0x762d), 0x00 }, { CCI_REG8(0x762e), 0x10 }, ++ { CCI_REG8(0x762f), 0x00 }, { CCI_REG8(0x7630), 0x00 }, ++ { CCI_REG8(0x7631), 0x00 }, { CCI_REG8(0x7632), 0x10 }, ++ { CCI_REG8(0x7633), 0x00 }, { CCI_REG8(0x7634), 0x00 }, ++ { CCI_REG8(0x7635), 0x00 }, { CCI_REG8(0x7636), 0x10 }, ++ { CCI_REG8(0x7637), 0x00 }, { CCI_REG8(0x7638), 0x00 }, ++ { CCI_REG8(0x7639), 0x00 }, { CCI_REG8(0x763a), 0x10 }, ++ { CCI_REG8(0x763b), 0x00 }, { CCI_REG8(0x763c), 0x00 }, ++ { CCI_REG8(0x763d), 0x00 }, { CCI_REG8(0x763e), 0x10 }, ++ { CCI_REG8(0x763f), 0x00 }, { CCI_REG8(0x7640), 0x00 }, ++ { CCI_REG8(0x7641), 0x00 }, { CCI_REG8(0x7642), 0x10 }, ++ { CCI_REG8(0x7643), 0x00 }, { CCI_REG8(0x7644), 0x00 }, ++ { CCI_REG8(0x7645), 0x00 }, { CCI_REG8(0x7646), 0x10 }, ++ { CCI_REG8(0x7647), 0x00 }, { CCI_REG8(0x7648), 0x00 }, ++ { CCI_REG8(0x7649), 0x00 }, { CCI_REG8(0x764a), 0x10 }, ++ { CCI_REG8(0x764b), 0x00 }, { CCI_REG8(0x764c), 0x00 }, ++ { CCI_REG8(0x764d), 0x00 }, { CCI_REG8(0x764e), 0x10 }, ++ { CCI_REG8(0x764f), 0x00 }, { CCI_REG8(0x7650), 0x00 }, ++ { CCI_REG8(0x7651), 0x00 }, { CCI_REG8(0x7652), 0x10 }, ++ { CCI_REG8(0x7653), 0x00 }, { CCI_REG8(0x7654), 0x00 }, ++ { CCI_REG8(0x7655), 0x00 }, { CCI_REG8(0x7656), 0x10 }, ++ { CCI_REG8(0x7657), 0x00 }, { CCI_REG8(0x7658), 0x00 }, ++ { CCI_REG8(0x7659), 0x00 }, { CCI_REG8(0x765a), 0x10 }, ++ { CCI_REG8(0x765b), 0x00 }, { CCI_REG8(0x765c), 0x00 }, ++ { CCI_REG8(0x765d), 0x00 }, { CCI_REG8(0x765e), 0x10 }, ++ { CCI_REG8(0x765f), 0x00 }, { CCI_REG8(0x7660), 0x00 }, ++ { CCI_REG8(0x7661), 0x00 }, { CCI_REG8(0x7662), 0x10 }, ++ { CCI_REG8(0x7663), 0x00 }, { CCI_REG8(0x7664), 0x00 }, ++ { CCI_REG8(0x7665), 0x00 }, { CCI_REG8(0x7666), 0x10 }, ++ { CCI_REG8(0x7667), 0x00 }, { CCI_REG8(0x7668), 0x00 }, ++ { CCI_REG8(0x7669), 0x00 }, { CCI_REG8(0x766a), 0x10 }, ++ { CCI_REG8(0x766b), 0x00 }, { CCI_REG8(0x766c), 0x00 }, ++ { CCI_REG8(0x766d), 0x00 }, { CCI_REG8(0x766e), 0x10 }, ++ { CCI_REG8(0x766f), 0x00 }, { CCI_REG8(0x7670), 0x00 }, ++ { CCI_REG8(0x7671), 0x00 }, { CCI_REG8(0x7672), 0x10 }, ++ { CCI_REG8(0x7673), 0x00 }, { CCI_REG8(0x7674), 0x00 }, ++ { CCI_REG8(0x7675), 0x00 }, { CCI_REG8(0x7676), 0x10 }, ++ { CCI_REG8(0x7677), 0x00 }, { CCI_REG8(0x7678), 0x00 }, ++ { CCI_REG8(0x7679), 0x00 }, { CCI_REG8(0x767a), 0x10 }, ++ { CCI_REG8(0x767b), 0x00 }, { CCI_REG8(0x767c), 0x00 }, ++ { CCI_REG8(0x767d), 0x00 }, { CCI_REG8(0x767e), 0x10 }, ++ { CCI_REG8(0x767f), 0x00 }, { CCI_REG8(0x7680), 0x00 }, ++ { CCI_REG8(0x7681), 0x00 }, { CCI_REG8(0x7682), 0x10 }, ++ { CCI_REG8(0x7683), 0x00 }, { CCI_REG8(0x7684), 0x00 }, ++ { CCI_REG8(0x7685), 0x00 }, { CCI_REG8(0x7686), 0x10 }, ++ { CCI_REG8(0x7687), 0x00 }, { CCI_REG8(0x7688), 0x00 }, ++ { CCI_REG8(0x7689), 0x00 }, { CCI_REG8(0x768a), 0x10 }, ++ { CCI_REG8(0x768b), 0x00 }, { CCI_REG8(0x768c), 0x00 }, ++ { CCI_REG8(0x768d), 0x00 }, { CCI_REG8(0x768e), 0x10 }, ++ { CCI_REG8(0x768f), 0x00 }, { CCI_REG8(0x7690), 0x00 }, ++ { CCI_REG8(0x7691), 0x00 }, { CCI_REG8(0x7692), 0x10 }, ++ { CCI_REG8(0x7693), 0x00 }, { CCI_REG8(0x7694), 0x00 }, ++ { CCI_REG8(0x7695), 0x00 }, { CCI_REG8(0x7696), 0x10 }, ++ { CCI_REG8(0x7697), 0x00 }, { CCI_REG8(0x7698), 0x00 }, ++ { CCI_REG8(0x7699), 0x00 }, { CCI_REG8(0x769a), 0x10 }, ++ { CCI_REG8(0x769b), 0x00 }, { CCI_REG8(0x769c), 0x00 }, ++ { CCI_REG8(0x769d), 0x00 }, { CCI_REG8(0x769e), 0x10 }, ++ { CCI_REG8(0x769f), 0x00 }, { CCI_REG8(0x76a0), 0x00 }, ++ { CCI_REG8(0x76a1), 0x00 }, { CCI_REG8(0x76a2), 0x10 }, ++ { CCI_REG8(0x76a3), 0x00 }, { CCI_REG8(0x76a4), 0x00 }, ++ { CCI_REG8(0x76a5), 0x00 }, { CCI_REG8(0x76a6), 0x10 }, ++ { CCI_REG8(0x76a7), 0x00 }, { CCI_REG8(0x76a8), 0x00 }, ++ { CCI_REG8(0x76a9), 0x00 }, { CCI_REG8(0x76aa), 0x10 }, ++ { CCI_REG8(0x76ab), 0x00 }, { CCI_REG8(0x76ac), 0x00 }, ++ { CCI_REG8(0x76ad), 0x00 }, { CCI_REG8(0x76ae), 0x10 }, ++ { CCI_REG8(0x76af), 0x00 }, { CCI_REG8(0x76b0), 0x00 }, ++ { CCI_REG8(0x76b1), 0x00 }, { CCI_REG8(0x76b2), 0x10 }, ++ { CCI_REG8(0x76b3), 0x00 }, { CCI_REG8(0x76b4), 0x00 }, ++ { CCI_REG8(0x76b5), 0x00 }, { CCI_REG8(0x76b6), 0x10 }, ++ { CCI_REG8(0x76b7), 0x00 }, { CCI_REG8(0x76b8), 0x00 }, ++ { CCI_REG8(0x76b9), 0x00 }, { CCI_REG8(0x76ba), 0x10 }, ++ { CCI_REG8(0x76bb), 0x00 }, { CCI_REG8(0x76bc), 0x00 }, ++ { CCI_REG8(0x76bd), 0x00 }, { CCI_REG8(0x76be), 0x10 }, ++ { CCI_REG8(0x76bf), 0x00 }, { CCI_REG8(0x76c0), 0x00 }, ++ { CCI_REG8(0x76c1), 0x00 }, { CCI_REG8(0x76c2), 0x10 }, ++ { CCI_REG8(0x76c3), 0x00 }, { CCI_REG8(0x76c4), 0x00 }, ++ { CCI_REG8(0x76c5), 0x00 }, { CCI_REG8(0x76c6), 0x10 }, ++ { CCI_REG8(0x76c7), 0x00 }, { CCI_REG8(0x76c8), 0x00 }, ++ { CCI_REG8(0x76c9), 0x00 }, { CCI_REG8(0x76ca), 0x10 }, ++ { CCI_REG8(0x76cb), 0x00 }, { CCI_REG8(0x76cc), 0x00 }, ++ { CCI_REG8(0x76cd), 0x00 }, { CCI_REG8(0x76ce), 0x10 }, ++ { CCI_REG8(0x76cf), 0x00 }, { CCI_REG8(0x76d0), 0x00 }, ++ { CCI_REG8(0x76d1), 0x00 }, { CCI_REG8(0x76d2), 0x10 }, ++ { CCI_REG8(0x76d3), 0x00 }, { CCI_REG8(0x76d4), 0x00 }, ++ { CCI_REG8(0x76d5), 0x00 }, { CCI_REG8(0x76d6), 0x10 }, ++ { CCI_REG8(0x76d7), 0x00 }, { CCI_REG8(0x76d8), 0x00 }, ++ { CCI_REG8(0x76d9), 0x00 }, { CCI_REG8(0x76da), 0x10 }, ++ { CCI_REG8(0x76db), 0x00 }, { CCI_REG8(0x76dc), 0x00 }, ++ { CCI_REG8(0x76dd), 0x00 }, { CCI_REG8(0x76de), 0x10 }, ++ { CCI_REG8(0x76df), 0x00 }, { CCI_REG8(0x76e0), 0x00 }, ++ { CCI_REG8(0x76e1), 0x00 }, { CCI_REG8(0x76e2), 0x10 }, ++ { CCI_REG8(0x76e3), 0x00 }, { CCI_REG8(0x76e4), 0x00 }, ++ { CCI_REG8(0x76e5), 0x00 }, { CCI_REG8(0x76e6), 0x10 }, ++ { CCI_REG8(0x76e7), 0x00 }, { CCI_REG8(0x76e8), 0x00 }, ++ { CCI_REG8(0x76e9), 0x00 }, { CCI_REG8(0x76ea), 0x10 }, ++ { CCI_REG8(0x76eb), 0x00 }, { CCI_REG8(0x76ec), 0x00 }, ++ { CCI_REG8(0x76ed), 0x00 }, { CCI_REG8(0x76ee), 0x10 }, ++ { CCI_REG8(0x76ef), 0x00 }, { CCI_REG8(0x76f0), 0x00 }, ++ { CCI_REG8(0x76f1), 0x00 }, { CCI_REG8(0x76f2), 0x10 }, ++ { CCI_REG8(0x76f3), 0x00 }, { CCI_REG8(0x76f4), 0x00 }, ++ { CCI_REG8(0x76f5), 0x00 }, { CCI_REG8(0x76f6), 0x10 }, ++ { CCI_REG8(0x76f7), 0x00 }, { CCI_REG8(0x76f8), 0x00 }, ++ { CCI_REG8(0x76f9), 0x00 }, { CCI_REG8(0x76fa), 0x10 }, ++ { CCI_REG8(0x76fb), 0x00 }, { CCI_REG8(0x76fc), 0x00 }, ++ { CCI_REG8(0x76fd), 0x00 }, { CCI_REG8(0x76fe), 0x10 }, ++ { CCI_REG8(0x76ff), 0x00 }, { CCI_REG8(0x7700), 0x00 }, ++ { CCI_REG8(0x7701), 0x00 }, { CCI_REG8(0x7702), 0x10 }, ++ { CCI_REG8(0x7703), 0x00 }, { CCI_REG8(0x7704), 0x00 }, ++ { CCI_REG8(0x7705), 0x00 }, { CCI_REG8(0x7706), 0x10 }, ++ { CCI_REG8(0x7707), 0x00 }, { CCI_REG8(0x7708), 0x00 }, ++ { CCI_REG8(0x7709), 0x00 }, { CCI_REG8(0x770a), 0x10 }, ++ { CCI_REG8(0x770b), 0x00 }, { CCI_REG8(0x770c), 0x00 }, ++ { CCI_REG8(0x770d), 0x00 }, { CCI_REG8(0x770e), 0x10 }, ++ { CCI_REG8(0x770f), 0x00 }, { CCI_REG8(0x7710), 0x00 }, ++ { CCI_REG8(0x7711), 0x00 }, { CCI_REG8(0x7712), 0x10 }, ++ { CCI_REG8(0x7713), 0x00 }, { CCI_REG8(0x7714), 0x00 }, ++ { CCI_REG8(0x7715), 0x00 }, { CCI_REG8(0x7716), 0x10 }, ++ { CCI_REG8(0x7717), 0x00 }, { CCI_REG8(0x7718), 0x00 }, ++ { CCI_REG8(0x7719), 0x00 }, { CCI_REG8(0x771a), 0x10 }, ++ { CCI_REG8(0x771b), 0x00 }, { CCI_REG8(0x771c), 0x00 }, ++ { CCI_REG8(0x771d), 0x00 }, { CCI_REG8(0x771e), 0x10 }, ++ { CCI_REG8(0x771f), 0x00 }, { CCI_REG8(0x7720), 0x00 }, ++ { CCI_REG8(0x7721), 0x00 }, { CCI_REG8(0x7722), 0x10 }, ++ { CCI_REG8(0x7723), 0x00 }, { CCI_REG8(0x7724), 0x00 }, ++ { CCI_REG8(0x7725), 0x00 }, { CCI_REG8(0x7726), 0x10 }, ++ { CCI_REG8(0x7727), 0x00 }, { CCI_REG8(0x7728), 0x00 }, ++ { CCI_REG8(0x7729), 0x00 }, { CCI_REG8(0x772a), 0x10 }, ++ { CCI_REG8(0x772b), 0x00 }, { CCI_REG8(0x772c), 0x00 }, ++ { CCI_REG8(0x772d), 0x00 }, { CCI_REG8(0x772e), 0x10 }, ++ { CCI_REG8(0x772f), 0x00 }, { CCI_REG8(0x7730), 0x00 }, ++ { CCI_REG8(0x7731), 0x00 }, { CCI_REG8(0x7732), 0x10 }, ++ { CCI_REG8(0x7733), 0x00 }, { CCI_REG8(0x7734), 0x00 }, ++ { CCI_REG8(0x7735), 0x00 }, { CCI_REG8(0x7736), 0x10 }, ++ { CCI_REG8(0x7737), 0x00 }, { CCI_REG8(0x7738), 0x00 }, ++ { CCI_REG8(0x7739), 0x00 }, { CCI_REG8(0x773a), 0x10 }, ++ { CCI_REG8(0x773b), 0x00 }, { CCI_REG8(0x773c), 0x00 }, ++ { CCI_REG8(0x773d), 0x00 }, { CCI_REG8(0x773e), 0x10 }, ++ { CCI_REG8(0x773f), 0x00 }, { CCI_REG8(0x7740), 0x00 }, ++ { CCI_REG8(0x7741), 0x00 }, { CCI_REG8(0x7742), 0x10 }, ++ { CCI_REG8(0x7743), 0x00 }, { CCI_REG8(0x3421), 0x02 }, ++ { CCI_REG8(0x37d0), 0x00 }, { CCI_REG8(0x3632), 0x99 }, ++ { CCI_REG8(0xc518), 0x1f }, { CCI_REG8(0xc519), 0x1f }, ++ { CCI_REG8(0xc51a), 0x1f }, { CCI_REG8(0xc51b), 0x1f }, ++ { CCI_REG8(0xc51c), 0x1f }, { CCI_REG8(0xc51d), 0x1f }, ++ { CCI_REG8(0xc51e), 0x1f }, { CCI_REG8(0xc51f), 0x1f }, ++ { CCI_REG8(0xc520), 0x1f }, { CCI_REG8(0xc521), 0x1f }, ++ { CCI_REG8(0x3616), 0xa0 }, { CCI_REG8(0x3615), 0xc5 }, ++ { CCI_REG8(0xc4c1), 0x02 }, { CCI_REG8(0xc4c2), 0x02 }, ++ { CCI_REG8(0xc4c3), 0x03 }, { CCI_REG8(0xc4c4), 0x03 }, ++ { CCI_REG8(0xc4f6), 0x0a }, { CCI_REG8(0xc4f7), 0x0a }, ++ { CCI_REG8(0xc4f8), 0x0a }, { CCI_REG8(0xc4f9), 0x0a }, ++ { CCI_REG8(0xc4fa), 0x0a }, { CCI_REG8(0xc4c6), 0x0a }, ++ { CCI_REG8(0xc4c7), 0x0a }, { CCI_REG8(0xc4c8), 0x0a }, ++ { CCI_REG8(0xc4c9), 0x0a }, { CCI_REG8(0xc4ca), 0x14 }, ++ { CCI_REG8(0xc4cb), 0x14 }, { CCI_REG8(0xc4cc), 0x14 }, ++ { CCI_REG8(0xc4cd), 0x14 }, { CCI_REG8(0x3b92), 0x05 }, ++ { CCI_REG8(0x3b93), 0x05 }, { CCI_REG8(0x3b94), 0x05 }, ++ { CCI_REG8(0x3b95), 0x05 }, { CCI_REG8(0x3623), 0x10 }, ++ { CCI_REG8(0xc522), 0x18 }, { CCI_REG8(0xc523), 0x12 }, ++ { CCI_REG8(0xc524), 0x0e }, { CCI_REG8(0xc525), 0x0b }, ++ { CCI_REG8(0xc526), 0x18 }, { CCI_REG8(0xc527), 0x12 }, ++ { CCI_REG8(0xc528), 0x0c }, { CCI_REG8(0xc529), 0x08 }, ++ { CCI_REG8(0xc52a), 0x18 }, { CCI_REG8(0xc52b), 0x12 }, ++ { CCI_REG8(0xc52c), 0x0e }, { CCI_REG8(0xc52d), 0x0b }, ++ { CCI_REG8(0xc52e), 0x18 }, { CCI_REG8(0xc52f), 0x12 }, ++ { CCI_REG8(0xc530), 0x0e }, { CCI_REG8(0xc531), 0x0b }, ++ { CCI_REG8(0xc532), 0x18 }, { CCI_REG8(0xc533), 0x12 }, ++ { CCI_REG8(0xc534), 0x0e }, { CCI_REG8(0xc535), 0x0b }, ++ { CCI_REG8(0xc536), 0x18 }, { CCI_REG8(0xc537), 0x12 }, ++ { CCI_REG8(0xc538), 0x0e }, { CCI_REG8(0xc539), 0x0b }, ++ { CCI_REG8(0xc53a), 0x18 }, { CCI_REG8(0xc53b), 0x12 }, ++ { CCI_REG8(0xc53c), 0x0c }, { CCI_REG8(0xc53d), 0x08 }, ++ { CCI_REG8(0xc53e), 0x18 }, { CCI_REG8(0xc53f), 0x12 }, ++ { CCI_REG8(0xc540), 0x0e }, { CCI_REG8(0xc541), 0x0b }, ++ { CCI_REG8(0xc542), 0x18 }, { CCI_REG8(0xc543), 0x12 }, ++ { CCI_REG8(0xc544), 0x0e }, { CCI_REG8(0xc545), 0x0b }, ++ { CCI_REG8(0xc546), 0x18 }, { CCI_REG8(0xc547), 0x12 }, ++ { CCI_REG8(0xc548), 0x0e }, { CCI_REG8(0xc549), 0x0b }, ++ { CCI_REG8(0x3701), 0x18 }, { CCI_REG8(0x3702), 0x38 }, ++ { CCI_REG8(0x3703), 0x72 }, { CCI_REG8(0x3708), 0x26 }, ++ { CCI_REG8(0x3709), 0xe6 }, { CCI_REG8(0x3a1d), 0x18 }, ++ { CCI_REG8(0x3a1e), 0x18 }, { CCI_REG8(0x3a21), 0x18 }, ++ { CCI_REG8(0x3a22), 0x18 }, { CCI_REG8(0x39fb), 0x18 }, ++ { CCI_REG8(0x39fc), 0x18 }, { CCI_REG8(0x39fd), 0x18 }, ++ { CCI_REG8(0x39fe), 0x18 }, { CCI_REG8(0xc44a), 0x08 }, ++ { CCI_REG8(0xc44c), 0x08 }, { CCI_REG8(0xc5e8), 0x0a }, ++ { CCI_REG8(0xc5ea), 0x0a }, { CCI_REG8(0x391d), 0x54 }, ++ { CCI_REG8(0x391e), 0xca }, { CCI_REG8(0x3991), 0x0c }, ++ { CCI_REG8(0x399d), 0x0c }, { CCI_REG8(0x3744), 0x24 }, ++ { CCI_REG8(0x374b), 0x0c }, { CCI_REG8(0x3be7), 0x1e }, ++ { CCI_REG8(0x3be8), 0x26 }, { CCI_REG8(0x3a50), 0x14 }, ++ { CCI_REG8(0x3a54), 0x14 }, { CCI_REG8(0x3add), 0x1f }, ++ { CCI_REG8(0x3adf), 0x24 }, { CCI_REG8(0x3aef), 0x1f }, ++ { CCI_REG8(0x3af0), 0x24 }, { CCI_REG8(0xc57f), 0x30 }, ++ { CCI_REG8(0xc580), 0x30 }, { CCI_REG8(0xc581), 0x30 }, ++ { CCI_REG8(0xc582), 0x30 }, { CCI_REG8(0xc583), 0x30 }, ++ { CCI_REG8(0xc584), 0x30 }, { CCI_REG8(0xc585), 0x30 }, ++ { CCI_REG8(0xc586), 0x30 }, { CCI_REG8(0xc587), 0x30 }, ++ { CCI_REG8(0xc588), 0x30 }, { CCI_REG8(0xc589), 0x30 }, ++ { CCI_REG8(0xc58a), 0x30 }, { CCI_REG8(0xc58b), 0x30 }, ++ { CCI_REG8(0xc58c), 0x30 }, { CCI_REG8(0xc58d), 0x30 }, ++ { CCI_REG8(0xc58e), 0x30 }, { CCI_REG8(0xc58f), 0x30 }, ++ { CCI_REG8(0xc590), 0x30 }, { CCI_REG8(0xc591), 0x30 }, ++ { CCI_REG8(0xc592), 0x30 }, { CCI_REG8(0xc598), 0x30 }, ++ { CCI_REG8(0xc599), 0x30 }, { CCI_REG8(0xc59a), 0x30 }, ++ { CCI_REG8(0xc59b), 0x30 }, { CCI_REG8(0xc59c), 0x30 }, ++ { CCI_REG8(0xc59d), 0x30 }, { CCI_REG8(0xc59e), 0x30 }, ++ { CCI_REG8(0xc59f), 0x30 }, { CCI_REG8(0xc5a0), 0x30 }, ++ { CCI_REG8(0xc5a1), 0x30 }, { CCI_REG8(0xc5a2), 0x30 }, ++ { CCI_REG8(0xc5a3), 0x30 }, { CCI_REG8(0xc5a4), 0x30 }, ++ { CCI_REG8(0xc5a5), 0x30 }, { CCI_REG8(0xc5a6), 0x30 }, ++ { CCI_REG8(0xc5a7), 0x30 }, { CCI_REG8(0xc5a8), 0x30 }, ++ { CCI_REG8(0xc5a9), 0x30 }, { CCI_REG8(0xc5aa), 0x30 }, ++ { CCI_REG8(0xc5ab), 0x30 }, { CCI_REG8(0xc5b1), 0x38 }, ++ { CCI_REG8(0xc5b2), 0x38 }, { CCI_REG8(0xc5b3), 0x38 }, ++ { CCI_REG8(0xc5b4), 0x38 }, { CCI_REG8(0xc5b5), 0x38 }, ++ { CCI_REG8(0xc5b6), 0x38 }, { CCI_REG8(0xc5b7), 0x38 }, ++ { CCI_REG8(0xc5b8), 0x38 }, { CCI_REG8(0xc5b9), 0x38 }, ++ { CCI_REG8(0xc5ba), 0x38 }, { CCI_REG8(0xc5bb), 0x38 }, ++ { CCI_REG8(0xc5bc), 0x38 }, { CCI_REG8(0xc5bd), 0x38 }, ++ { CCI_REG8(0xc5be), 0x38 }, { CCI_REG8(0xc5bf), 0x38 }, ++ { CCI_REG8(0xc5c0), 0x38 }, { CCI_REG8(0xc5c1), 0x38 }, ++ { CCI_REG8(0xc5c2), 0x38 }, { CCI_REG8(0xc5c3), 0x38 }, ++ { CCI_REG8(0xc5c4), 0x38 }, { CCI_REG8(0xc5ca), 0x38 }, ++ { CCI_REG8(0xc5cb), 0x38 }, { CCI_REG8(0xc5cc), 0x38 }, ++ { CCI_REG8(0xc5cd), 0x38 }, { CCI_REG8(0xc5ce), 0x38 }, ++ { CCI_REG8(0xc5cf), 0x38 }, { CCI_REG8(0xc5d0), 0x38 }, ++ { CCI_REG8(0xc5d1), 0x38 }, { CCI_REG8(0xc5d2), 0x38 }, ++ { CCI_REG8(0xc5d3), 0x38 }, { CCI_REG8(0xc5d4), 0x38 }, ++ { CCI_REG8(0xc5d5), 0x38 }, { CCI_REG8(0xc5d6), 0x38 }, ++ { CCI_REG8(0xc5d7), 0x38 }, { CCI_REG8(0xc5d8), 0x38 }, ++ { CCI_REG8(0xc5d9), 0x38 }, { CCI_REG8(0xc5da), 0x38 }, ++ { CCI_REG8(0xc5db), 0x38 }, { CCI_REG8(0xc5dc), 0x38 }, ++ { CCI_REG8(0xc5dd), 0x38 }, { CCI_REG8(0x3a60), 0x68 }, ++ { CCI_REG8(0x3a6f), 0x68 }, { CCI_REG8(0x3a5e), 0xdc }, ++ { CCI_REG8(0x3a6d), 0xdc }, { CCI_REG8(0x3aed), 0x6e }, ++ { CCI_REG8(0x3af1), 0x73 }, { CCI_REG8(0x3992), 0x02 }, ++ { CCI_REG8(0x399e), 0x02 }, { CCI_REG8(0x371d), 0x17 }, ++ { CCI_REG8(0x371f), 0x08 }, { CCI_REG8(0x3721), 0xc9 }, ++ { CCI_REG8(0x401e), 0x00 }, { CCI_REG8(0x401f), 0xf8 }, ++ { CCI_REG8(0x3642), 0x00 }, { CCI_REG8(0x3641), 0x7f }, ++ { CCI_REG8(0x3ac5), 0x0c }, { CCI_REG8(0x3ac6), 0x09 }, ++ { CCI_REG8(0x3ac7), 0x06 }, { CCI_REG8(0x3ac8), 0x02 }, ++ { CCI_REG8(0x3ac9), 0x0c }, { CCI_REG8(0x3aca), 0x09 }, ++ { CCI_REG8(0x3acb), 0x06 }, { CCI_REG8(0x3acc), 0x02 }, ++ { CCI_REG8(0x3acd), 0x0c }, { CCI_REG8(0x3ace), 0x09 }, ++ { CCI_REG8(0x3acf), 0x07 }, { CCI_REG8(0x3ad0), 0x04 }, ++ { CCI_REG8(0x3ad1), 0x0c }, { CCI_REG8(0x3ad2), 0x09 }, ++ { CCI_REG8(0x3ad3), 0x07 }, { CCI_REG8(0x3ad4), 0x04 }, ++ { CCI_REG8(0xc483), 0x0c }, { CCI_REG8(0xc484), 0x0c }, ++ { CCI_REG8(0xc485), 0x0c }, { CCI_REG8(0xc486), 0x0c }, ++ { CCI_REG8(0x3a2f), 0x0c }, { CCI_REG8(0x3a30), 0x09 }, ++ { CCI_REG8(0x3a31), 0x06 }, { CCI_REG8(0x3a32), 0x02 }, ++ { CCI_REG8(0x3a34), 0x0c }, { CCI_REG8(0x3a35), 0x09 }, ++ { CCI_REG8(0x3a36), 0x07 }, { CCI_REG8(0x3a37), 0x04 }, ++ { CCI_REG8(0x3a43), 0x0c }, { CCI_REG8(0x3a44), 0x09 }, ++ { CCI_REG8(0x3a45), 0x06 }, { CCI_REG8(0x3a46), 0x02 }, ++ { CCI_REG8(0x3a48), 0x0c }, { CCI_REG8(0x3a49), 0x09 }, ++ { CCI_REG8(0x3a4a), 0x07 }, { CCI_REG8(0x3a4b), 0x04 }, ++ { CCI_REG8(0xc487), 0x0c }, { CCI_REG8(0xc488), 0x0c }, ++ { CCI_REG8(0xc489), 0x0c }, { CCI_REG8(0xc48a), 0x0c }, ++ { CCI_REG8(0x3645), 0xbd }, { CCI_REG8(0x373f), 0x00 }, ++ { CCI_REG8(0x374f), 0x10 }, { CCI_REG8(0x3743), 0xc6 }, ++ { CCI_REG8(0x3717), 0x82 }, { CCI_REG8(0x3732), 0x07 }, ++ { CCI_REG8(0x3731), 0x16 }, { CCI_REG8(0x3730), 0x16 }, ++ { CCI_REG8(0x3828), 0x07 }, { CCI_REG8(0x3714), 0x68 }, ++ { CCI_REG8(0x371d), 0x02 }, { CCI_REG8(0x371f), 0x02 }, ++ { CCI_REG8(0x37e0), 0x00 }, { CCI_REG8(0x37e1), 0x03 }, ++ { CCI_REG8(0x37e2), 0x07 }, { CCI_REG8(0x3734), 0x3e }, ++ { CCI_REG8(0x3736), 0x02 }, { CCI_REG8(0x37e4), 0x36 }, ++ { CCI_REG8(0x37e9), 0x1c }, { CCI_REG8(0x37ea), 0x01 }, ++ { CCI_REG8(0x37eb), 0x0a }, { CCI_REG8(0x37ec), 0x1c }, ++ { CCI_REG8(0x37ed), 0x01 }, { CCI_REG8(0x37ee), 0x36 }, ++ { CCI_REG8(0x373b), 0x1c }, { CCI_REG8(0x373c), 0x02 }, ++ { CCI_REG8(0x37bb), 0x1c }, { CCI_REG8(0x37bc), 0x02 }, ++ { CCI_REG8(0x37b8), 0x0c }, { CCI_REG8(0x371c), 0x01 }, ++ { CCI_REG8(0x371e), 0x11 }, { CCI_REG8(0x371d), 0x01 }, ++ { CCI_REG8(0x371f), 0x01 }, { CCI_REG8(0x3721), 0x01 }, ++ { CCI_REG8(0x3725), 0x12 }, { CCI_REG8(0x37e3), 0x06 }, ++ { CCI_REG8(0x37dd), 0x86 }, { CCI_REG8(0x37db), 0x0a }, ++ { CCI_REG8(0x37dc), 0x14 }, { CCI_REG8(0x3727), 0x20 }, ++ { CCI_REG8(0x37b2), 0x80 }, { CCI_REG8(0x37da), 0x04 }, ++ { CCI_REG8(0x37df), 0x01 }, { CCI_REG8(0x3731), 0x11 }, ++ { CCI_REG8(0x37dd), 0x86 }, { CCI_REG8(0x37df), 0x01 }, ++ { CCI_REG8(0x37da), 0x03 }, { CCI_REG8(0x37b2), 0x80 }, ++ { CCI_REG8(0x3727), 0x20 }, { CCI_REG8(0x4883), 0x26 }, ++ { CCI_REG8(0x488b), 0x88 }, { CCI_REG8(0x3d85), 0x1f }, ++ { CCI_REG8(0x3d81), 0x01 }, { CCI_REG8(0x3d84), 0x40 }, ++ { CCI_REG8(0x3d88), 0x00 }, { CCI_REG8(0x3d89), 0x00 }, ++ { CCI_REG8(0x3d8a), 0x0b }, { CCI_REG8(0x3d8b), 0xff }, ++ { CCI_REG8(0x4d00), 0x05 }, { CCI_REG8(0x4d01), 0xc4 }, ++ { CCI_REG8(0x4d02), 0xa3 }, { CCI_REG8(0x4d03), 0x8c }, ++ { CCI_REG8(0x4d04), 0xfb }, { CCI_REG8(0x4d05), 0xed }, ++ { CCI_REG8(0x4010), 0x28 }, { CCI_REG8(0x4030), 0x00 }, ++ { CCI_REG8(0x4031), 0x00 }, { CCI_REG8(0x4032), 0x00 }, ++ { CCI_REG8(0x4033), 0x00 }, { CCI_REG8(0x4034), 0x00 }, ++ { CCI_REG8(0x4035), 0x00 }, { CCI_REG8(0x4036), 0x00 }, ++ { CCI_REG8(0x4037), 0x00 }, { CCI_REG8(0x4040), 0x00 }, ++ { CCI_REG8(0x4041), 0x00 }, { CCI_REG8(0x4042), 0x00 }, ++ { CCI_REG8(0x4043), 0x00 }, { CCI_REG8(0x4044), 0x00 }, ++ { CCI_REG8(0x4045), 0x00 }, { CCI_REG8(0x4046), 0x00 }, ++ { CCI_REG8(0x4047), 0x00 }, { CCI_REG8(0x3400), 0x00 }, ++ { CCI_REG8(0x3421), 0x23 }, { CCI_REG8(0x3422), 0xfc }, ++ { CCI_REG8(0x3423), 0x07 }, { CCI_REG8(0x3424), 0x01 }, ++ { CCI_REG8(0x3425), 0x04 }, { CCI_REG8(0x3426), 0x50 }, ++ { CCI_REG8(0x3427), 0x55 }, { CCI_REG8(0x3428), 0x15 }, ++ { CCI_REG8(0x3429), 0x00 }, { CCI_REG8(0x3025), 0x03 }, ++ { CCI_REG8(0x3053), 0x00 }, { CCI_REG8(0x3054), 0x00 }, ++ { CCI_REG8(0x3055), 0x00 }, { CCI_REG8(0x3056), 0x00 }, ++ { CCI_REG8(0x3057), 0x00 }, { CCI_REG8(0x3058), 0x00 }, ++ { CCI_REG8(0x305c), 0x00 }, { CCI_REG8(0x340c), 0x1f }, ++ { CCI_REG8(0x340d), 0x00 }, { CCI_REG8(0x3501), 0x01 }, ++ { CCI_REG8(0x3542), 0x48 }, { CCI_REG8(0x3582), 0x24 }, ++ { CCI_REG8(0x3015), 0xf1 }, { CCI_REG8(0x3018), 0xf2 }, ++ { CCI_REG8(0x301c), 0xf2 }, { CCI_REG8(0x301d), 0xf6 }, ++ { CCI_REG8(0x301e), 0xf1 }, { CCI_REG8(0x0100), 0x01 }, ++ { CCI_REG8(0xfff9), 0x08 }, { CCI_REG8(0x3900), 0xcd }, ++ { CCI_REG8(0x3901), 0xcd }, { CCI_REG8(0x3902), 0xcd }, ++ { CCI_REG8(0x3903), 0xcd }, { CCI_REG8(0x3904), 0xcd }, ++ { CCI_REG8(0x3905), 0xcd }, { CCI_REG8(0x3906), 0xcd }, ++ { CCI_REG8(0x3907), 0xcd }, { CCI_REG8(0x3908), 0xcd }, ++ { CCI_REG8(0x3909), 0xcd }, { CCI_REG8(0x390a), 0xcd }, ++ { CCI_REG8(0x390b), 0xcd }, { CCI_REG8(0x390c), 0xcd }, ++ { CCI_REG8(0x390d), 0xcd }, { CCI_REG8(0x390e), 0xcd }, ++ { CCI_REG8(0x390f), 0xcd }, { CCI_REG8(0x3910), 0xcd }, ++ { CCI_REG8(0x3911), 0xcd }, { CCI_REG8(0x3912), 0xcd }, ++ { CCI_REG8(0x3913), 0xcd }, { CCI_REG8(0x3914), 0xcd }, ++ { CCI_REG8(0x3915), 0xcd }, { CCI_REG8(0x3916), 0xcd }, ++ { CCI_REG8(0x3917), 0xcd }, { CCI_REG8(0x3918), 0xcd }, ++ { CCI_REG8(0x3919), 0xcd }, { CCI_REG8(0x391a), 0xcd }, ++ { CCI_REG8(0x391b), 0xcd }, { CCI_REG8(0x391c), 0xcd }, ++ { CCI_REG8(0x391d), 0xcd }, { CCI_REG8(0x391e), 0xcd }, ++ { CCI_REG8(0x391f), 0xcd }, { CCI_REG8(0x3920), 0xcd }, ++ { CCI_REG8(0x3921), 0xcd }, { CCI_REG8(0x3922), 0xcd }, ++ { CCI_REG8(0x3923), 0xcd }, { CCI_REG8(0x3924), 0xcd }, ++ { CCI_REG8(0x3925), 0xcd }, { CCI_REG8(0x3926), 0xcd }, ++ { CCI_REG8(0x3927), 0xcd }, { CCI_REG8(0x3928), 0xcd }, ++ { CCI_REG8(0x3929), 0xcd }, { CCI_REG8(0x392a), 0xcd }, ++ { CCI_REG8(0x392b), 0xcd }, { CCI_REG8(0x392c), 0xcd }, ++ { CCI_REG8(0x392d), 0xcd }, { CCI_REG8(0x392e), 0xcd }, ++ { CCI_REG8(0x392f), 0xcd }, { CCI_REG8(0x3930), 0xcd }, ++ { CCI_REG8(0x3931), 0xcd }, { CCI_REG8(0x3932), 0xcd }, ++ { CCI_REG8(0x3933), 0xcd }, { CCI_REG8(0x3934), 0xcd }, ++ { CCI_REG8(0x3935), 0xcd }, { CCI_REG8(0x3936), 0xcd }, ++ { CCI_REG8(0x3937), 0xcd }, { CCI_REG8(0x3938), 0xcd }, ++ { CCI_REG8(0x3939), 0xcd }, { CCI_REG8(0x393a), 0xcd }, ++ { CCI_REG8(0x393b), 0xcd }, { CCI_REG8(0x393c), 0xcd }, ++ { CCI_REG8(0x393d), 0xcd }, { CCI_REG8(0x393e), 0xcd }, ++ { CCI_REG8(0x393f), 0xcd }, { CCI_REG8(0x3940), 0xcd }, ++ { CCI_REG8(0x3941), 0xcd }, { CCI_REG8(0x3942), 0xcd }, ++ { CCI_REG8(0x3943), 0xcd }, { CCI_REG8(0x3944), 0xcd }, ++ { CCI_REG8(0x3945), 0xcd }, { CCI_REG8(0x3946), 0xcd }, ++ { CCI_REG8(0x3947), 0xcd }, { CCI_REG8(0x3948), 0xcd }, ++ { CCI_REG8(0x3949), 0xcd }, { CCI_REG8(0x394a), 0xcd }, ++ { CCI_REG8(0x394b), 0xcd }, { CCI_REG8(0x394c), 0xcd }, ++ { CCI_REG8(0x394d), 0xcd }, { CCI_REG8(0x394e), 0xcd }, ++ { CCI_REG8(0x394f), 0xcd }, { CCI_REG8(0x3950), 0xcd }, ++ { CCI_REG8(0x3951), 0xcd }, { CCI_REG8(0x3952), 0xcd }, ++ { CCI_REG8(0x3953), 0xcd }, { CCI_REG8(0x3954), 0xcd }, ++ { CCI_REG8(0x3955), 0xcd }, { CCI_REG8(0x3956), 0xcd }, ++ { CCI_REG8(0x3957), 0xcd }, { CCI_REG8(0x3958), 0xcd }, ++ { CCI_REG8(0x3959), 0xcd }, { CCI_REG8(0x395a), 0xcd }, ++ { CCI_REG8(0x395b), 0xcd }, { CCI_REG8(0x395c), 0xcd }, ++ { CCI_REG8(0x395d), 0xcd }, { CCI_REG8(0x395e), 0xcd }, ++ { CCI_REG8(0x395f), 0xcd }, { CCI_REG8(0x3960), 0xcd }, ++ { CCI_REG8(0x3961), 0xcd }, { CCI_REG8(0x3962), 0xcd }, ++ { CCI_REG8(0x3963), 0xcd }, { CCI_REG8(0x3964), 0xcd }, ++ { CCI_REG8(0x3965), 0xcd }, { CCI_REG8(0x3966), 0xcd }, ++ { CCI_REG8(0x3967), 0xcd }, { CCI_REG8(0x3968), 0xcd }, ++ { CCI_REG8(0x3969), 0xcd }, { CCI_REG8(0x396a), 0xcd }, ++ { CCI_REG8(0x396b), 0xcd }, { CCI_REG8(0x396c), 0xcd }, ++ { CCI_REG8(0x396d), 0xcd }, { CCI_REG8(0x396e), 0xcd }, ++ { CCI_REG8(0x396f), 0xcd }, { CCI_REG8(0x3970), 0xcd }, ++ { CCI_REG8(0x3971), 0xcd }, { CCI_REG8(0x3972), 0xcd }, ++ { CCI_REG8(0x3973), 0xcd }, { CCI_REG8(0x3974), 0xcd }, ++ { CCI_REG8(0x3975), 0xcd }, { CCI_REG8(0x3976), 0xcd }, ++ { CCI_REG8(0x3977), 0xcd }, { CCI_REG8(0x3978), 0xcd }, ++ { CCI_REG8(0x3979), 0xcd }, { CCI_REG8(0x397a), 0xcd }, ++ { CCI_REG8(0x397b), 0xcd }, { CCI_REG8(0x397c), 0xcd }, ++ { CCI_REG8(0x397d), 0xcd }, { CCI_REG8(0x397e), 0xcd }, ++ { CCI_REG8(0x397f), 0xcd }, { CCI_REG8(0x3980), 0xcd }, ++ { CCI_REG8(0x3981), 0xcd }, { CCI_REG8(0x3982), 0xcd }, ++ { CCI_REG8(0x3983), 0xcd }, { CCI_REG8(0x3984), 0xcd }, ++ { CCI_REG8(0x3985), 0xcd }, { CCI_REG8(0x3986), 0xcd }, ++ { CCI_REG8(0x3987), 0xcd }, { CCI_REG8(0x3988), 0xcd }, ++ { CCI_REG8(0x3989), 0xcd }, { CCI_REG8(0x398a), 0xcd }, ++ { CCI_REG8(0x398b), 0xcd }, { CCI_REG8(0x398c), 0xcd }, ++ { CCI_REG8(0x398d), 0xcd }, { CCI_REG8(0x398e), 0xcd }, ++ { CCI_REG8(0x398f), 0xcd }, { CCI_REG8(0x3990), 0xcd }, ++ { CCI_REG8(0x3991), 0xcd }, { CCI_REG8(0x3992), 0xcd }, ++ { CCI_REG8(0x3993), 0xcd }, { CCI_REG8(0x3994), 0xcd }, ++ { CCI_REG8(0x3995), 0xcd }, { CCI_REG8(0x3996), 0xcd }, ++ { CCI_REG8(0x3997), 0xcd }, { CCI_REG8(0x3998), 0xcd }, ++ { CCI_REG8(0x3999), 0xcd }, { CCI_REG8(0x399a), 0xcd }, ++ { CCI_REG8(0x399b), 0xcd }, { CCI_REG8(0x399c), 0xcd }, ++ { CCI_REG8(0x399d), 0xcd }, { CCI_REG8(0x399e), 0xcd }, ++ { CCI_REG8(0x399f), 0xcd }, { CCI_REG8(0x39a0), 0xcd }, ++ { CCI_REG8(0x39a1), 0xcd }, { CCI_REG8(0x39a2), 0xcd }, ++ { CCI_REG8(0x39a3), 0xcd }, { CCI_REG8(0x39a4), 0xcd }, ++ { CCI_REG8(0x39a5), 0xcd }, { CCI_REG8(0x39a6), 0xcd }, ++ { CCI_REG8(0x39a7), 0xcd }, { CCI_REG8(0x39a8), 0xcd }, ++ { CCI_REG8(0x39a9), 0xcd }, { CCI_REG8(0x39aa), 0xcd }, ++ { CCI_REG8(0x39ab), 0xcd }, { CCI_REG8(0x39ac), 0xcd }, ++ { CCI_REG8(0x39ad), 0xcd }, { CCI_REG8(0x39ae), 0xcd }, ++ { CCI_REG8(0x39af), 0xcd }, { CCI_REG8(0x39b0), 0xcd }, ++ { CCI_REG8(0x39b1), 0xcd }, { CCI_REG8(0x39b2), 0xcd }, ++ { CCI_REG8(0x39b3), 0xcd }, { CCI_REG8(0x39b4), 0xcd }, ++ { CCI_REG8(0x39b5), 0xcd }, { CCI_REG8(0x39b6), 0xcd }, ++ { CCI_REG8(0x39b7), 0xcd }, { CCI_REG8(0x39b8), 0xcd }, ++ { CCI_REG8(0x39b9), 0xcd }, { CCI_REG8(0x39ba), 0xcd }, ++ { CCI_REG8(0x39bb), 0xcd }, { CCI_REG8(0x39bc), 0xcd }, ++ { CCI_REG8(0x39bd), 0xcd }, { CCI_REG8(0x39be), 0xcd }, ++ { CCI_REG8(0x39bf), 0xcd }, { CCI_REG8(0x39c0), 0xcd }, ++ { CCI_REG8(0x39c1), 0xcd }, { CCI_REG8(0x39c2), 0xcd }, ++ { CCI_REG8(0x39c3), 0xcd }, { CCI_REG8(0x39c4), 0xcd }, ++ { CCI_REG8(0x39c5), 0xcd }, { CCI_REG8(0x39c6), 0xcd }, ++ { CCI_REG8(0x39c7), 0xcd }, { CCI_REG8(0x39c8), 0xcd }, ++ { CCI_REG8(0x39c9), 0xcd }, { CCI_REG8(0x39ca), 0xcd }, ++ { CCI_REG8(0x39cb), 0xcd }, { CCI_REG8(0x39cc), 0xcd }, ++ { CCI_REG8(0x39cd), 0xcd }, { CCI_REG8(0x39ce), 0xcd }, ++ { CCI_REG8(0x39cf), 0xcd }, { CCI_REG8(0x39d0), 0xcd }, ++ { CCI_REG8(0x39d1), 0xcd }, { CCI_REG8(0x39d2), 0xcd }, ++ { CCI_REG8(0x39d3), 0xcd }, { CCI_REG8(0x39d4), 0xcd }, ++ { CCI_REG8(0x39d5), 0xcd }, { CCI_REG8(0x39d6), 0xcd }, ++ { CCI_REG8(0x39d7), 0xcd }, { CCI_REG8(0x39d8), 0xcd }, ++ { CCI_REG8(0x39d9), 0xcd }, { CCI_REG8(0x39da), 0xcd }, ++ { CCI_REG8(0x39db), 0xcd }, { CCI_REG8(0x39dc), 0xcd }, ++ { CCI_REG8(0x39dd), 0xcd }, { CCI_REG8(0x39de), 0xcd }, ++ { CCI_REG8(0x39df), 0xcd }, { CCI_REG8(0x39e0), 0xcd }, ++ { CCI_REG8(0x39e1), 0x40 }, { CCI_REG8(0x39e2), 0x40 }, ++ { CCI_REG8(0x39e3), 0x40 }, { CCI_REG8(0x39e4), 0x40 }, ++ { CCI_REG8(0x39e5), 0x40 }, { CCI_REG8(0x39e6), 0x40 }, ++ { CCI_REG8(0x39e7), 0x40 }, { CCI_REG8(0x39e8), 0x40 }, ++ { CCI_REG8(0x39e9), 0x40 }, { CCI_REG8(0x39ea), 0x40 }, ++ { CCI_REG8(0x39eb), 0x40 }, { CCI_REG8(0x39ec), 0x40 }, ++ { CCI_REG8(0x39ed), 0x40 }, { CCI_REG8(0x39ee), 0x40 }, ++ { CCI_REG8(0x39ef), 0x40 }, { CCI_REG8(0x39f0), 0x40 }, ++ { CCI_REG8(0x39f1), 0x40 }, { CCI_REG8(0x39f2), 0x40 }, ++ { CCI_REG8(0x39f3), 0x40 }, { CCI_REG8(0x39f4), 0x40 }, ++ { CCI_REG8(0x39f5), 0x40 }, { CCI_REG8(0x39f6), 0x40 }, ++ { CCI_REG8(0x39f7), 0x40 }, { CCI_REG8(0x39f8), 0x40 }, ++ { CCI_REG8(0x39f9), 0x40 }, { CCI_REG8(0x39fa), 0x40 }, ++ { CCI_REG8(0x39fb), 0x40 }, { CCI_REG8(0x39fc), 0x40 }, ++ { CCI_REG8(0x39fd), 0x40 }, { CCI_REG8(0x39fe), 0x40 }, ++ { CCI_REG8(0x39ff), 0x40 }, { CCI_REG8(0x3a00), 0x40 }, ++ { CCI_REG8(0x3a01), 0x40 }, { CCI_REG8(0x3a02), 0x40 }, ++ { CCI_REG8(0x3a03), 0x40 }, { CCI_REG8(0x3a04), 0x40 }, ++ { CCI_REG8(0x3a05), 0x40 }, { CCI_REG8(0x3a06), 0x40 }, ++ { CCI_REG8(0x3a07), 0x40 }, { CCI_REG8(0x3a08), 0x40 }, ++ { CCI_REG8(0x3a09), 0x40 }, { CCI_REG8(0x3a0a), 0x40 }, ++ { CCI_REG8(0x3a0b), 0x40 }, { CCI_REG8(0x3a0c), 0x40 }, ++ { CCI_REG8(0x3a0d), 0x40 }, { CCI_REG8(0x3a0e), 0x40 }, ++ { CCI_REG8(0x3a0f), 0x40 }, { CCI_REG8(0x3a10), 0x40 }, ++ { CCI_REG8(0x3a11), 0x40 }, { CCI_REG8(0x3a12), 0x40 }, ++ { CCI_REG8(0x3a13), 0x40 }, { CCI_REG8(0x3a14), 0x40 }, ++ { CCI_REG8(0x3a15), 0x40 }, { CCI_REG8(0x3a16), 0x40 }, ++ { CCI_REG8(0x3a17), 0x40 }, { CCI_REG8(0x3a18), 0x40 }, ++ { CCI_REG8(0x3a19), 0x40 }, { CCI_REG8(0x3a1a), 0x40 }, ++ { CCI_REG8(0x3a1b), 0x40 }, { CCI_REG8(0x3a1c), 0x40 }, ++ { CCI_REG8(0x3a1d), 0x40 }, { CCI_REG8(0x3a1e), 0x40 }, ++ { CCI_REG8(0x3a1f), 0x40 }, { CCI_REG8(0x3a20), 0x40 }, ++ { CCI_REG8(0x3a21), 0x40 }, { CCI_REG8(0x3a22), 0x40 }, ++ { CCI_REG8(0x3a23), 0x40 }, { CCI_REG8(0x3a24), 0x40 }, ++ { CCI_REG8(0x3a25), 0x40 }, { CCI_REG8(0x3a26), 0x40 }, ++ { CCI_REG8(0x3a27), 0x40 }, { CCI_REG8(0x3a28), 0x40 }, ++ { CCI_REG8(0x3a29), 0x40 }, { CCI_REG8(0x3a2a), 0x40 }, ++ { CCI_REG8(0x3a2b), 0x40 }, { CCI_REG8(0x3a2c), 0x40 }, ++ { CCI_REG8(0x3a2d), 0x40 }, { CCI_REG8(0x3a2e), 0x40 }, ++ { CCI_REG8(0x3a2f), 0x40 }, { CCI_REG8(0x3a30), 0x40 }, ++ { CCI_REG8(0x3a31), 0x40 }, { CCI_REG8(0x3a32), 0x40 }, ++ { CCI_REG8(0x3a33), 0x40 }, { CCI_REG8(0x3a34), 0x40 }, ++ { CCI_REG8(0x3a35), 0x40 }, { CCI_REG8(0x3a36), 0x40 }, ++ { CCI_REG8(0x3a37), 0x40 }, { CCI_REG8(0x3a38), 0x40 }, ++ { CCI_REG8(0x3a39), 0x40 }, { CCI_REG8(0x3a3a), 0x40 }, ++ { CCI_REG8(0x3a3b), 0xcd }, { CCI_REG8(0x3a3c), 0xcd }, ++ { CCI_REG8(0x3a3d), 0xcd }, { CCI_REG8(0x3a3e), 0xcd }, ++ { CCI_REG8(0x3a3f), 0xcd }, { CCI_REG8(0x3a40), 0xcd }, ++ { CCI_REG8(0x3a41), 0xcd }, { CCI_REG8(0x3a42), 0xcd }, ++ { CCI_REG8(0x3a43), 0xcd }, { CCI_REG8(0x3a44), 0xcd }, ++ { CCI_REG8(0x3a45), 0xcd }, { CCI_REG8(0x3a46), 0xcd }, ++ { CCI_REG8(0x3a47), 0xcd }, { CCI_REG8(0x3a48), 0xcd }, ++ { CCI_REG8(0x3a49), 0xcd }, { CCI_REG8(0x3a4a), 0xcd }, ++ { CCI_REG8(0x3a4b), 0xcd }, { CCI_REG8(0x3a4c), 0xcd }, ++ { CCI_REG8(0x3a4d), 0xcd }, { CCI_REG8(0x3a4e), 0xcd }, ++ { CCI_REG8(0x3a4f), 0xcd }, { CCI_REG8(0x3a50), 0xcd }, ++ { CCI_REG8(0x3a51), 0xcd }, { CCI_REG8(0x3a52), 0xcd }, ++ { CCI_REG8(0x3a53), 0xcd }, { CCI_REG8(0x3a54), 0xcd }, ++ { CCI_REG8(0x3a55), 0xcd }, { CCI_REG8(0x3a56), 0xcd }, ++ { CCI_REG8(0x3a57), 0xcd }, { CCI_REG8(0x3a58), 0xcd }, ++ { CCI_REG8(0x3a59), 0xcd }, { CCI_REG8(0x3a5a), 0xcd }, ++ { CCI_REG8(0x3a5b), 0xcd }, { CCI_REG8(0x3a5c), 0xcd }, ++ { CCI_REG8(0x3a5d), 0xcd }, { CCI_REG8(0x3a5e), 0xcd }, ++ { CCI_REG8(0x3a5f), 0xcd }, { CCI_REG8(0x3a60), 0xcd }, ++ { CCI_REG8(0x3a61), 0xcd }, { CCI_REG8(0x3a62), 0xcd }, ++ { CCI_REG8(0x3a63), 0xcd }, { CCI_REG8(0x3a64), 0xcd }, ++ { CCI_REG8(0x3a65), 0xcd }, { CCI_REG8(0x3a66), 0xcd }, ++ { CCI_REG8(0x3a67), 0xcd }, { CCI_REG8(0x3a68), 0xcd }, ++ { CCI_REG8(0x3a69), 0xcd }, { CCI_REG8(0x3a6a), 0xcd }, ++ { CCI_REG8(0x3a6b), 0xcd }, { CCI_REG8(0x3a6c), 0xcd }, ++ { CCI_REG8(0x3a6d), 0xcd }, { CCI_REG8(0x3a6e), 0xcd }, ++ { CCI_REG8(0x3a6f), 0xcd }, { CCI_REG8(0x3a70), 0xcd }, ++ { CCI_REG8(0x3a71), 0xcd }, { CCI_REG8(0x3a72), 0xcd }, ++ { CCI_REG8(0x3a73), 0xcd }, { CCI_REG8(0x3a74), 0xcd }, ++ { CCI_REG8(0x3a75), 0xcd }, { CCI_REG8(0x3a76), 0xcd }, ++ { CCI_REG8(0x3a77), 0xcd }, { CCI_REG8(0x3a78), 0xcd }, ++ { CCI_REG8(0x3a79), 0xcd }, { CCI_REG8(0x3a7a), 0xcd }, ++ { CCI_REG8(0x3a7b), 0xcd }, { CCI_REG8(0x3a7c), 0xcd }, ++ { CCI_REG8(0x3a7d), 0xcd }, { CCI_REG8(0x3a7e), 0xcd }, ++ { CCI_REG8(0x3a7f), 0xcd }, { CCI_REG8(0x3a80), 0xcd }, ++ { CCI_REG8(0x3a81), 0xcd }, { CCI_REG8(0x3a82), 0xcd }, ++ { CCI_REG8(0x3a83), 0xcd }, { CCI_REG8(0x3a84), 0xcd }, ++ { CCI_REG8(0x3a85), 0xcd }, { CCI_REG8(0x3a86), 0xcd }, ++ { CCI_REG8(0x3a87), 0xcd }, { CCI_REG8(0x3a88), 0xcd }, ++ { CCI_REG8(0x3a89), 0xcd }, { CCI_REG8(0x3a8a), 0xcd }, ++ { CCI_REG8(0x3a8b), 0xcd }, { CCI_REG8(0x3a8c), 0xcd }, ++ { CCI_REG8(0x3a8d), 0xcd }, { CCI_REG8(0x3a8e), 0xcd }, ++ { CCI_REG8(0x3a8f), 0xcd }, { CCI_REG8(0x3a90), 0xcd }, ++ { CCI_REG8(0x3a91), 0xcd }, { CCI_REG8(0x3a92), 0xcd }, ++ { CCI_REG8(0x3a93), 0xcd }, { CCI_REG8(0x3a94), 0xcd }, ++ { CCI_REG8(0x3a95), 0x40 }, { CCI_REG8(0x3a96), 0x40 }, ++ { CCI_REG8(0x3a97), 0x40 }, { CCI_REG8(0x3a98), 0x40 }, ++ { CCI_REG8(0x3a99), 0x40 }, { CCI_REG8(0x3a9a), 0x40 }, ++ { CCI_REG8(0x3a9b), 0x40 }, { CCI_REG8(0x3a9c), 0x40 }, ++ { CCI_REG8(0x3a9d), 0x40 }, { CCI_REG8(0x3a9e), 0x40 }, ++ { CCI_REG8(0x3a9f), 0x40 }, { CCI_REG8(0x3aa0), 0x40 }, ++ { CCI_REG8(0x3aa1), 0x40 }, { CCI_REG8(0x3aa2), 0x40 }, ++ { CCI_REG8(0x3aa3), 0x40 }, { CCI_REG8(0x3aa4), 0x40 }, ++ { CCI_REG8(0x3aa5), 0x40 }, { CCI_REG8(0x3aa6), 0x40 }, ++ { CCI_REG8(0x3aa7), 0x40 }, { CCI_REG8(0x3aa8), 0x40 }, ++ { CCI_REG8(0x3aa9), 0x40 }, { CCI_REG8(0x3aaa), 0x40 }, ++ { CCI_REG8(0x3aab), 0x40 }, { CCI_REG8(0x3aac), 0x40 }, ++ { CCI_REG8(0x3aad), 0x40 }, { CCI_REG8(0x3aae), 0x40 }, ++ { CCI_REG8(0x3aaf), 0x40 }, { CCI_REG8(0x3ab0), 0x40 }, ++ { CCI_REG8(0x3ab1), 0x40 }, { CCI_REG8(0x3ab2), 0x40 }, ++ { CCI_REG8(0x3ab3), 0x40 }, { CCI_REG8(0x3ab4), 0x40 }, ++ { CCI_REG8(0x3ab5), 0x40 }, { CCI_REG8(0x3ab6), 0x40 }, ++ { CCI_REG8(0x3ab7), 0x40 }, { CCI_REG8(0x3ab8), 0x40 }, ++ { CCI_REG8(0x3ab9), 0x40 }, { CCI_REG8(0x3aba), 0x40 }, ++ { CCI_REG8(0x3abb), 0x40 }, { CCI_REG8(0x3abc), 0x40 }, ++ { CCI_REG8(0x3abd), 0x40 }, { CCI_REG8(0x3abe), 0x40 }, ++ { CCI_REG8(0x3abf), 0x40 }, { CCI_REG8(0x3ac0), 0x40 }, ++ { CCI_REG8(0x3ac1), 0x40 }, { CCI_REG8(0x3ac2), 0x40 }, ++ { CCI_REG8(0x3ac3), 0x40 }, { CCI_REG8(0x3ac4), 0x40 }, ++ { CCI_REG8(0x3ac5), 0x40 }, { CCI_REG8(0x3ac6), 0x40 }, ++ { CCI_REG8(0x3ac7), 0x40 }, { CCI_REG8(0x3ac8), 0x40 }, ++ { CCI_REG8(0x3ac9), 0x40 }, { CCI_REG8(0x3aca), 0x40 }, ++ { CCI_REG8(0x3acb), 0x40 }, { CCI_REG8(0x3acc), 0x40 }, ++ { CCI_REG8(0x3acd), 0x40 }, { CCI_REG8(0x3ace), 0x40 }, ++ { CCI_REG8(0x3acf), 0x40 }, { CCI_REG8(0x3ad0), 0x40 }, ++ { CCI_REG8(0x3ad1), 0x40 }, { CCI_REG8(0x3ad2), 0x40 }, ++ { CCI_REG8(0x3ad3), 0x40 }, { CCI_REG8(0x3ad4), 0x40 }, ++ { CCI_REG8(0x3ad5), 0x40 }, { CCI_REG8(0x3ad6), 0x40 }, ++ { CCI_REG8(0x3ad7), 0x40 }, { CCI_REG8(0x3ad8), 0x40 }, ++ { CCI_REG8(0x3ad9), 0x40 }, { CCI_REG8(0x3ada), 0x40 }, ++ { CCI_REG8(0x3adb), 0x40 }, { CCI_REG8(0x3adc), 0x40 }, ++ { CCI_REG8(0x3add), 0x40 }, { CCI_REG8(0x3ade), 0x40 }, ++ { CCI_REG8(0x3adf), 0x40 }, { CCI_REG8(0x3ae0), 0x40 }, ++ { CCI_REG8(0x3ae1), 0x40 }, { CCI_REG8(0x3ae2), 0x40 }, ++ { CCI_REG8(0x3ae3), 0x40 }, { CCI_REG8(0x3ae4), 0x40 }, ++ { CCI_REG8(0x3ae5), 0x40 }, { CCI_REG8(0x3ae6), 0x40 }, ++ { CCI_REG8(0x3ae7), 0x40 }, { CCI_REG8(0x3ae8), 0x40 }, ++ { CCI_REG8(0x3ae9), 0x40 }, { CCI_REG8(0x3aea), 0x40 }, ++ { CCI_REG8(0x3aeb), 0x40 }, { CCI_REG8(0x3aec), 0x40 }, ++ { CCI_REG8(0x3aed), 0x40 }, { CCI_REG8(0x3aee), 0x40 }, ++ { CCI_REG8(0x3aef), 0xcd }, { CCI_REG8(0x3af0), 0xcd }, ++ { CCI_REG8(0x3af1), 0xcd }, { CCI_REG8(0x3af2), 0xcd }, ++ { CCI_REG8(0x3af3), 0xcd }, { CCI_REG8(0x3af4), 0xcd }, ++ { CCI_REG8(0x3af5), 0xcd }, { CCI_REG8(0x3af6), 0xcd }, ++ { CCI_REG8(0x3af7), 0xcd }, { CCI_REG8(0x3af8), 0xcd }, ++ { CCI_REG8(0x3af9), 0xcd }, { CCI_REG8(0x3afa), 0xcd }, ++ { CCI_REG8(0x3afb), 0xcd }, { CCI_REG8(0x3afc), 0xcd }, ++ { CCI_REG8(0x3afd), 0xcd }, { CCI_REG8(0x3afe), 0xcd }, ++ { CCI_REG8(0x3aff), 0xcd }, { CCI_REG8(0x3b00), 0xcd }, ++ { CCI_REG8(0x3b01), 0xcd }, { CCI_REG8(0x3b02), 0xcd }, ++ { CCI_REG8(0x3b03), 0xcd }, { CCI_REG8(0x3b04), 0xcd }, ++ { CCI_REG8(0x3b05), 0xcd }, { CCI_REG8(0x3b06), 0xcd }, ++ { CCI_REG8(0x3b07), 0xcd }, { CCI_REG8(0x3b08), 0xcd }, ++ { CCI_REG8(0x3b09), 0xcd }, { CCI_REG8(0x3b0a), 0xcd }, ++ { CCI_REG8(0x3b0b), 0xcd }, { CCI_REG8(0x3b0c), 0xcd }, ++ { CCI_REG8(0x3b0d), 0xcd }, { CCI_REG8(0x3b0e), 0xcd }, ++ { CCI_REG8(0x3b0f), 0xcd }, { CCI_REG8(0x3b10), 0xcd }, ++ { CCI_REG8(0x3b11), 0xcd }, { CCI_REG8(0x3b12), 0xcd }, ++ { CCI_REG8(0x3b13), 0xcd }, { CCI_REG8(0x3b14), 0xcd }, ++ { CCI_REG8(0x3b15), 0xcd }, { CCI_REG8(0x3b16), 0xcd }, ++ { CCI_REG8(0x3b17), 0xcd }, { CCI_REG8(0x3b18), 0xcd }, ++ { CCI_REG8(0x3b19), 0xcd }, { CCI_REG8(0x3b1a), 0xcd }, ++ { CCI_REG8(0x3b1b), 0xcd }, { CCI_REG8(0x3b1c), 0xcd }, ++ { CCI_REG8(0x3b1d), 0xcd }, { CCI_REG8(0x3b1e), 0xcd }, ++ { CCI_REG8(0x3b1f), 0xcd }, { CCI_REG8(0x3b20), 0xcd }, ++ { CCI_REG8(0x3b21), 0xcd }, { CCI_REG8(0x3b22), 0xcd }, ++ { CCI_REG8(0x3b23), 0xcd }, { CCI_REG8(0x3b24), 0xcd }, ++ { CCI_REG8(0x3b25), 0xcd }, { CCI_REG8(0x3b26), 0xcd }, ++ { CCI_REG8(0x3b27), 0xcd }, { CCI_REG8(0x3b28), 0xcd }, ++ { CCI_REG8(0x3b29), 0xcd }, { CCI_REG8(0x3b2a), 0xcd }, ++ { CCI_REG8(0x3b2b), 0xcd }, { CCI_REG8(0x3b2c), 0xcd }, ++ { CCI_REG8(0x3b2d), 0xcd }, { CCI_REG8(0x3b2e), 0xcd }, ++ { CCI_REG8(0x3b2f), 0xcd }, { CCI_REG8(0x3b30), 0xcd }, ++ { CCI_REG8(0x3b31), 0xcd }, { CCI_REG8(0x3b32), 0xcd }, ++ { CCI_REG8(0x3b33), 0xcd }, { CCI_REG8(0x3b34), 0xcd }, ++ { CCI_REG8(0x3b35), 0xcd }, { CCI_REG8(0x3b36), 0xcd }, ++ { CCI_REG8(0x3b37), 0xcd }, { CCI_REG8(0x3b38), 0xcd }, ++ { CCI_REG8(0x3b39), 0xcd }, { CCI_REG8(0x3b3a), 0xcd }, ++ { CCI_REG8(0x3b3b), 0xcd }, { CCI_REG8(0x3b3c), 0xcd }, ++ { CCI_REG8(0x3b3d), 0xcd }, { CCI_REG8(0x3b3e), 0xcd }, ++ { CCI_REG8(0x3b3f), 0xcd }, { CCI_REG8(0x3b40), 0xcd }, ++ { CCI_REG8(0x3b41), 0xcd }, { CCI_REG8(0x3b42), 0xcd }, ++ { CCI_REG8(0x3b43), 0xcd }, { CCI_REG8(0x3b44), 0xcd }, ++ { CCI_REG8(0x3b45), 0xcd }, { CCI_REG8(0x3b46), 0xcd }, ++ { CCI_REG8(0x3b47), 0xcd }, { CCI_REG8(0x3b48), 0xcd }, ++ { CCI_REG8(0x3b49), 0xcd }, { CCI_REG8(0x3b4a), 0xcd }, ++ { CCI_REG8(0x3b4b), 0xcd }, { CCI_REG8(0x3b4c), 0xcd }, ++ { CCI_REG8(0x3b4d), 0xcd }, { CCI_REG8(0x3b4e), 0xcd }, ++ { CCI_REG8(0x3b4f), 0xcd }, { CCI_REG8(0x3b50), 0xcd }, ++ { CCI_REG8(0x3b51), 0xcd }, { CCI_REG8(0x3b52), 0xcd }, ++ { CCI_REG8(0x3b53), 0xcd }, { CCI_REG8(0x3b54), 0xcd }, ++ { CCI_REG8(0x3b55), 0xcd }, { CCI_REG8(0x3b56), 0xcd }, ++ { CCI_REG8(0x3b57), 0xcd }, { CCI_REG8(0x3b58), 0xcd }, ++ { CCI_REG8(0x3b59), 0xcd }, { CCI_REG8(0x3b5a), 0xcd }, ++ { CCI_REG8(0x3b5b), 0xcd }, { CCI_REG8(0x3b5c), 0xcd }, ++ { CCI_REG8(0x3b5d), 0xcd }, { CCI_REG8(0x3b5e), 0xcd }, ++ { CCI_REG8(0x3b5f), 0xcd }, { CCI_REG8(0x3b60), 0xcd }, ++ { CCI_REG8(0x3b61), 0xcd }, { CCI_REG8(0x3b62), 0xcd }, ++ { CCI_REG8(0x3b63), 0xcd }, { CCI_REG8(0x3b64), 0xcd }, ++ { CCI_REG8(0x3b65), 0xcd }, { CCI_REG8(0x3b66), 0xcd }, ++ { CCI_REG8(0x3b67), 0xcd }, { CCI_REG8(0x3b68), 0xcd }, ++ { CCI_REG8(0x3b69), 0xcd }, { CCI_REG8(0x3b6a), 0xcd }, ++ { CCI_REG8(0x3b6b), 0xcd }, { CCI_REG8(0x3b6c), 0xcd }, ++ { CCI_REG8(0x3b6d), 0xcd }, { CCI_REG8(0x3b6e), 0xcd }, ++ { CCI_REG8(0x3b6f), 0xcd }, { CCI_REG8(0x3b70), 0xcd }, ++ { CCI_REG8(0x3b71), 0xcd }, { CCI_REG8(0x3b72), 0xcd }, ++ { CCI_REG8(0x3b73), 0xcd }, { CCI_REG8(0x3b74), 0xcd }, ++ { CCI_REG8(0x3b75), 0xcd }, { CCI_REG8(0x3b76), 0xcd }, ++ { CCI_REG8(0x3b77), 0xcd }, { CCI_REG8(0x3b78), 0xcd }, ++ { CCI_REG8(0x3b79), 0xcd }, { CCI_REG8(0x3b7a), 0xcd }, ++ { CCI_REG8(0x3b7b), 0xcd }, { CCI_REG8(0x3b7c), 0xcd }, ++ { CCI_REG8(0x3b7d), 0xcd }, { CCI_REG8(0x3b7e), 0xcd }, ++ { CCI_REG8(0x3b7f), 0xcd }, { CCI_REG8(0x3b80), 0xcd }, ++ { CCI_REG8(0x3b81), 0xcd }, { CCI_REG8(0x3b82), 0xcd }, ++ { CCI_REG8(0x3b83), 0xcd }, { CCI_REG8(0x3b84), 0xcd }, ++ { CCI_REG8(0x3b85), 0xcd }, { CCI_REG8(0x3b86), 0xcd }, ++ { CCI_REG8(0x3b87), 0xcd }, { CCI_REG8(0x3b88), 0xcd }, ++ { CCI_REG8(0x3b89), 0xcd }, { CCI_REG8(0x3b8a), 0xcd }, ++ { CCI_REG8(0x3b8b), 0xcd }, { CCI_REG8(0x3b8c), 0xcd }, ++ { CCI_REG8(0x3b8d), 0xcd }, { CCI_REG8(0x3b8e), 0xcd }, ++ { CCI_REG8(0x3b8f), 0xcd }, { CCI_REG8(0x3b90), 0xcd }, ++ { CCI_REG8(0x3b91), 0xcd }, { CCI_REG8(0x3b92), 0xcd }, ++ { CCI_REG8(0x3b93), 0xcd }, { CCI_REG8(0x3b94), 0xcd }, ++ { CCI_REG8(0x3b95), 0xcd }, { CCI_REG8(0x3b96), 0xcd }, ++ { CCI_REG8(0x3b97), 0xcd }, { CCI_REG8(0x3b98), 0xcd }, ++ { CCI_REG8(0x3b99), 0xcd }, { CCI_REG8(0x3b9a), 0xcd }, ++ { CCI_REG8(0x3b9b), 0xcd }, { CCI_REG8(0x3b9c), 0xcd }, ++ { CCI_REG8(0x3b9d), 0xcd }, { CCI_REG8(0x3b9e), 0xcd }, ++ { CCI_REG8(0x3b9f), 0xcd }, { CCI_REG8(0x3ba0), 0xcd }, ++ { CCI_REG8(0x3ba1), 0xcd }, { CCI_REG8(0x3ba2), 0xcd }, ++ { CCI_REG8(0x3ba3), 0xcd }, { CCI_REG8(0x3ba4), 0xcd }, ++ { CCI_REG8(0x3ba5), 0xcd }, { CCI_REG8(0x3ba6), 0xcd }, ++ { CCI_REG8(0x3ba7), 0xcd }, { CCI_REG8(0x3ba8), 0xcd }, ++ { CCI_REG8(0x3ba9), 0xcd }, { CCI_REG8(0x3baa), 0xcd }, ++ { CCI_REG8(0x3bab), 0xcd }, { CCI_REG8(0x3bac), 0xcd }, ++ { CCI_REG8(0x3bad), 0xcd }, { CCI_REG8(0x3bae), 0xcd }, ++ { CCI_REG8(0x3baf), 0xcd }, { CCI_REG8(0x3bb0), 0xcd }, ++ { CCI_REG8(0x3bb1), 0xcd }, { CCI_REG8(0x3bb2), 0xcd }, ++ { CCI_REG8(0x3bb3), 0xcd }, { CCI_REG8(0x3bb4), 0xcd }, ++ { CCI_REG8(0x3bb5), 0xcd }, { CCI_REG8(0x3bb6), 0xcd }, ++ { CCI_REG8(0x3bb7), 0xcd }, { CCI_REG8(0x3bb8), 0xcd }, ++ { CCI_REG8(0x3bb9), 0xcd }, { CCI_REG8(0x3bba), 0xcd }, ++ { CCI_REG8(0x3bbb), 0xcd }, { CCI_REG8(0x3bbc), 0xcd }, ++ { CCI_REG8(0x3bbd), 0xcd }, { CCI_REG8(0x3bbe), 0xcd }, ++ { CCI_REG8(0x3bbf), 0xcd }, { CCI_REG8(0x3bc0), 0xcd }, ++ { CCI_REG8(0x3bc1), 0xcd }, { CCI_REG8(0x3bc2), 0xcd }, ++ { CCI_REG8(0x3bc3), 0xcd }, { CCI_REG8(0x3bc4), 0xcd }, ++ { CCI_REG8(0x3bc5), 0xcd }, { CCI_REG8(0x3bc6), 0xcd }, ++ { CCI_REG8(0x3bc7), 0xcd }, { CCI_REG8(0x3bc8), 0xcd }, ++ { CCI_REG8(0x3bc9), 0xcd }, { CCI_REG8(0x3bca), 0xcd }, ++ { CCI_REG8(0x3bcb), 0xcd }, { CCI_REG8(0x3bcc), 0xcd }, ++ { CCI_REG8(0x3bcd), 0xcd }, { CCI_REG8(0x3bce), 0xcd }, ++ { CCI_REG8(0x3bcf), 0xcd }, { CCI_REG8(0x3bd0), 0xcd }, ++ { CCI_REG8(0x3bd1), 0xcd }, { CCI_REG8(0x3bd2), 0xcd }, ++ { CCI_REG8(0x3bd3), 0xcd }, { CCI_REG8(0x3bd4), 0xcd }, ++ { CCI_REG8(0x3bd5), 0xcd }, { CCI_REG8(0x3bd6), 0xcd }, ++ { CCI_REG8(0x3bd7), 0xcd }, { CCI_REG8(0x3bd8), 0xcd }, ++ { CCI_REG8(0x3bd9), 0xcd }, { CCI_REG8(0x3bda), 0xcd }, ++ { CCI_REG8(0x3bdb), 0xcd }, { CCI_REG8(0x3bdc), 0xcd }, ++ { CCI_REG8(0x3bdd), 0xcd }, { CCI_REG8(0x3bde), 0xcd }, ++ { CCI_REG8(0x3bdf), 0xcd }, { CCI_REG8(0x3be0), 0xcd }, ++ { CCI_REG8(0x3be1), 0xcd }, { CCI_REG8(0x3be2), 0xcd }, ++ { CCI_REG8(0x3be3), 0xcd }, { CCI_REG8(0x3be4), 0xcd }, ++ { CCI_REG8(0x3be5), 0xcd }, { CCI_REG8(0x3be6), 0xcd }, ++ { CCI_REG8(0x3be7), 0xcd }, { CCI_REG8(0x3be8), 0xcd }, ++ { CCI_REG8(0x3be9), 0xcd }, { CCI_REG8(0x3bea), 0xcd }, ++ { CCI_REG8(0x3beb), 0xcd }, { CCI_REG8(0x3bec), 0xcd }, ++ { CCI_REG8(0x3bed), 0xcd }, { CCI_REG8(0x3bee), 0xcd }, ++ { CCI_REG8(0x3bef), 0xcd }, { CCI_REG8(0x3bf0), 0xcd }, ++ { CCI_REG8(0x3bf1), 0xcd }, { CCI_REG8(0x3bf2), 0xcd }, ++ { CCI_REG8(0x3bf3), 0xcd }, { CCI_REG8(0x3bf4), 0xcd }, ++ { CCI_REG8(0x3bf5), 0xcd }, { CCI_REG8(0x3bf6), 0xcd }, ++ { CCI_REG8(0x3bf7), 0xcd }, { CCI_REG8(0x3bf8), 0xcd }, ++ { CCI_REG8(0x3bf9), 0xcd }, { CCI_REG8(0x3bfa), 0xcd }, ++ { CCI_REG8(0x3bfb), 0xcd }, { CCI_REG8(0x3bfc), 0xcd }, ++ { CCI_REG8(0x3bfd), 0xcd }, { CCI_REG8(0x3bfe), 0xcd }, ++ { CCI_REG8(0x3bff), 0xcd }, { CCI_REG8(0x3c00), 0xcd }, ++ { CCI_REG8(0x3c01), 0xcd }, { CCI_REG8(0x3c02), 0xcd }, ++ { CCI_REG8(0x3c03), 0xcd }, { CCI_REG8(0x3c04), 0xcd }, ++ { CCI_REG8(0x3c05), 0xcd }, { CCI_REG8(0x3c06), 0xcd }, ++ { CCI_REG8(0x3c07), 0xcd }, { CCI_REG8(0x3c08), 0xcd }, ++ { CCI_REG8(0x3c09), 0xcd }, { CCI_REG8(0x3c0a), 0xcd }, ++ { CCI_REG8(0x3c0b), 0xcd }, { CCI_REG8(0x3c0c), 0xcd }, ++ { CCI_REG8(0x3c0d), 0xcd }, { CCI_REG8(0x3c0e), 0xcd }, ++ { CCI_REG8(0x3c0f), 0xcd }, { CCI_REG8(0x3c10), 0xcd }, ++ { CCI_REG8(0x3c11), 0xcd }, { CCI_REG8(0x3c12), 0xcd }, ++ { CCI_REG8(0x3c13), 0xcd }, { CCI_REG8(0x3c14), 0xcd }, ++ { CCI_REG8(0x3c15), 0xcd }, { CCI_REG8(0x3c16), 0xcd }, ++ { CCI_REG8(0x3c17), 0xcd }, { CCI_REG8(0x3c18), 0xcd }, ++ { CCI_REG8(0x3c19), 0xcd }, { CCI_REG8(0x3c1a), 0xcd }, ++ { CCI_REG8(0x3c1b), 0xcd }, { CCI_REG8(0x3c1c), 0xcd }, ++ { CCI_REG8(0x3c1d), 0xcd }, { CCI_REG8(0x3c1e), 0xcd }, ++ { CCI_REG8(0x3c1f), 0xcd }, { CCI_REG8(0x3c20), 0xcd }, ++ { CCI_REG8(0x3c21), 0xcd }, { CCI_REG8(0x3c22), 0xcd }, ++ { CCI_REG8(0x3c23), 0xcd }, { CCI_REG8(0x3c24), 0xcd }, ++ { CCI_REG8(0x3c25), 0xcd }, { CCI_REG8(0x3c26), 0xcd }, ++ { CCI_REG8(0x3c27), 0xcd }, { CCI_REG8(0x3c28), 0xcd }, ++ { CCI_REG8(0x3c29), 0xcd }, { CCI_REG8(0x3c2a), 0xcd }, ++ { CCI_REG8(0x3c2b), 0xcd }, { CCI_REG8(0x3c2c), 0xcd }, ++ { CCI_REG8(0x3c2d), 0xcd }, { CCI_REG8(0x3c2e), 0xcd }, ++ { CCI_REG8(0x3c2f), 0xcd }, { CCI_REG8(0x3c30), 0xcd }, ++ { CCI_REG8(0x3c31), 0xcd }, { CCI_REG8(0x3c32), 0xcd }, ++ { CCI_REG8(0x3c33), 0xcd }, { CCI_REG8(0x3c34), 0xcd }, ++ { CCI_REG8(0x3c35), 0xcd }, { CCI_REG8(0x3c36), 0xcd }, ++ { CCI_REG8(0x3c37), 0xcd }, { CCI_REG8(0x3c38), 0xcd }, ++ { CCI_REG8(0x3c39), 0xcd }, { CCI_REG8(0x3c3a), 0xcd }, ++ { CCI_REG8(0x3c3b), 0xcd }, { CCI_REG8(0x3c3c), 0xcd }, ++ { CCI_REG8(0x3c3d), 0xcd }, { CCI_REG8(0x3c3e), 0xcd }, ++ { CCI_REG8(0x3c3f), 0xcd }, { CCI_REG8(0x3c40), 0xcd }, ++ { CCI_REG8(0x3c41), 0xcd }, { CCI_REG8(0x3c42), 0xcd }, ++ { CCI_REG8(0x3c43), 0xcd }, { CCI_REG8(0x3c44), 0xcd }, ++ { CCI_REG8(0x3c45), 0xcd }, { CCI_REG8(0x3c46), 0xcd }, ++ { CCI_REG8(0x3c47), 0xcd }, { CCI_REG8(0x3c48), 0xcd }, ++ { CCI_REG8(0x3c49), 0xcd }, { CCI_REG8(0x3c4a), 0xcd }, ++ { CCI_REG8(0x3c4b), 0xcd }, { CCI_REG8(0x3c4c), 0xcd }, ++ { CCI_REG8(0x3c4d), 0xcd }, { CCI_REG8(0x3c4e), 0xcd }, ++ { CCI_REG8(0x3c4f), 0xcd }, { CCI_REG8(0x3c50), 0xcd }, ++ { CCI_REG8(0x3c51), 0xcd }, { CCI_REG8(0x3c52), 0xcd }, ++ { CCI_REG8(0x3c53), 0xcd }, { CCI_REG8(0x3c54), 0xcd }, ++ { CCI_REG8(0x3c55), 0xcd }, { CCI_REG8(0x3c56), 0xcd }, ++ { CCI_REG8(0x3c57), 0xcd }, { CCI_REG8(0x3c58), 0xcd }, ++ { CCI_REG8(0x3c59), 0xcd }, { CCI_REG8(0x3c5a), 0xcd }, ++ { CCI_REG8(0x3c5b), 0xcd }, { CCI_REG8(0x3c5c), 0xcd }, ++ { CCI_REG8(0x3c5d), 0xcd }, { CCI_REG8(0x3c5e), 0xcd }, ++ { CCI_REG8(0x3c5f), 0xcd }, { CCI_REG8(0x3c60), 0xcd }, ++ { CCI_REG8(0x3c61), 0xcd }, { CCI_REG8(0x3c62), 0xcd }, ++ { CCI_REG8(0x3c63), 0xcd }, { CCI_REG8(0x3c64), 0xcd }, ++ { CCI_REG8(0x3c65), 0xcd }, { CCI_REG8(0x3c66), 0xcd }, ++ { CCI_REG8(0x3c67), 0xcd }, { CCI_REG8(0x3c68), 0xcd }, ++ { CCI_REG8(0x3c69), 0xcd }, { CCI_REG8(0x3c6a), 0xcd }, ++ { CCI_REG8(0x3c6b), 0xcd }, { CCI_REG8(0x3c6c), 0xcd }, ++ { CCI_REG8(0x3c6d), 0xcd }, { CCI_REG8(0x3c6e), 0xcd }, ++ { CCI_REG8(0x3c6f), 0xcd }, { CCI_REG8(0x3c70), 0xcd }, ++ { CCI_REG8(0x3c71), 0xcd }, { CCI_REG8(0x3c72), 0xcd }, ++ { CCI_REG8(0x3c73), 0xcd }, { CCI_REG8(0x3c74), 0xcd }, ++ { CCI_REG8(0x3c75), 0xcd }, { CCI_REG8(0x3c76), 0xcd }, ++ { CCI_REG8(0x3c77), 0xcd }, { CCI_REG8(0x3c78), 0xcd }, ++ { CCI_REG8(0x3c79), 0xcd }, { CCI_REG8(0x3c7a), 0xcd }, ++ { CCI_REG8(0x3c7b), 0xcd }, { CCI_REG8(0x3c7c), 0xcd }, ++ { CCI_REG8(0x3c7d), 0xcd }, { CCI_REG8(0x3c7e), 0xcd }, ++ { CCI_REG8(0x3c7f), 0xcd }, { CCI_REG8(0x3c80), 0xcd }, ++ { CCI_REG8(0x3c81), 0xcd }, { CCI_REG8(0x3c82), 0xcd }, ++ { CCI_REG8(0x3c83), 0xcd }, { CCI_REG8(0x3c84), 0xcd }, ++ { CCI_REG8(0x3c85), 0xcd }, { CCI_REG8(0x3c86), 0xcd }, ++ { CCI_REG8(0x3c87), 0xcd }, { CCI_REG8(0x3c88), 0xcd }, ++ { CCI_REG8(0x3c89), 0xcd }, { CCI_REG8(0x3c8a), 0xcd }, ++ { CCI_REG8(0x3c8b), 0xcd }, { CCI_REG8(0x3c8c), 0xcd }, ++ { CCI_REG8(0x3c8d), 0xcd }, { CCI_REG8(0x3c8e), 0xcd }, ++ { CCI_REG8(0x3c8f), 0xcd }, { CCI_REG8(0x3c90), 0xcd }, ++ { CCI_REG8(0x3c91), 0xcd }, { CCI_REG8(0x3c92), 0xcd }, ++ { CCI_REG8(0x3c93), 0xcd }, { CCI_REG8(0x3c94), 0xcd }, ++ { CCI_REG8(0x3c95), 0xcd }, { CCI_REG8(0x3c96), 0xcd }, ++ { CCI_REG8(0x3c97), 0xcd }, { CCI_REG8(0x3c98), 0xcd }, ++ { CCI_REG8(0x3c99), 0xcd }, { CCI_REG8(0x3c9a), 0xcd }, ++ { CCI_REG8(0x3c9b), 0xcd }, { CCI_REG8(0x3c9c), 0xcd }, ++ { CCI_REG8(0x3c9d), 0xcd }, { CCI_REG8(0x3c9e), 0xcd }, ++ { CCI_REG8(0x3c9f), 0xcd }, { CCI_REG8(0x3ca0), 0xcd }, ++ { CCI_REG8(0x3ca1), 0xcd }, { CCI_REG8(0x3ca2), 0xcd }, ++ { CCI_REG8(0x3ca3), 0xcd }, { CCI_REG8(0x3ca4), 0xcd }, ++ { CCI_REG8(0x3ca5), 0xcd }, { CCI_REG8(0x3ca6), 0xcd }, ++ { CCI_REG8(0x3ca7), 0xcd }, { CCI_REG8(0x3ca8), 0xcd }, ++ { CCI_REG8(0x3ca9), 0xcd }, { CCI_REG8(0x3caa), 0xcd }, ++ { CCI_REG8(0x3cab), 0xcd }, { CCI_REG8(0x3cac), 0xcd }, ++ { CCI_REG8(0x3cad), 0xcd }, { CCI_REG8(0x3cae), 0xcd }, ++ { CCI_REG8(0x3caf), 0xcd }, { CCI_REG8(0x3cb0), 0xcd }, ++ { CCI_REG8(0x3cb1), 0x40 }, { CCI_REG8(0x3cb2), 0x40 }, ++ { CCI_REG8(0x3cb3), 0x40 }, { CCI_REG8(0x3cb4), 0x40 }, ++ { CCI_REG8(0x3cb5), 0x40 }, { CCI_REG8(0x3cb6), 0x40 }, ++ { CCI_REG8(0x3cb7), 0x40 }, { CCI_REG8(0x3cb8), 0x40 }, ++ { CCI_REG8(0x3cb9), 0x40 }, { CCI_REG8(0x3cba), 0x40 }, ++ { CCI_REG8(0x3cbb), 0x40 }, { CCI_REG8(0x3cbc), 0x40 }, ++ { CCI_REG8(0x3cbd), 0x40 }, { CCI_REG8(0x3cbe), 0x40 }, ++ { CCI_REG8(0x3cbf), 0x40 }, { CCI_REG8(0x3cc0), 0x40 }, ++ { CCI_REG8(0x3cc1), 0x40 }, { CCI_REG8(0x3cc2), 0x40 }, ++ { CCI_REG8(0x3cc3), 0x40 }, { CCI_REG8(0x3cc4), 0x40 }, ++ { CCI_REG8(0x3cc5), 0x40 }, { CCI_REG8(0x3cc6), 0x40 }, ++ { CCI_REG8(0x3cc7), 0x40 }, { CCI_REG8(0x3cc8), 0x40 }, ++ { CCI_REG8(0x3cc9), 0x40 }, { CCI_REG8(0x3cca), 0x40 }, ++ { CCI_REG8(0x3ccb), 0x40 }, { CCI_REG8(0x3ccc), 0x40 }, ++ { CCI_REG8(0x3ccd), 0x40 }, { CCI_REG8(0x3cce), 0x40 }, ++ { CCI_REG8(0x3ccf), 0x40 }, { CCI_REG8(0x3cd0), 0x40 }, ++ { CCI_REG8(0x3cd1), 0x40 }, { CCI_REG8(0x3cd2), 0x40 }, ++ { CCI_REG8(0x3cd3), 0x40 }, { CCI_REG8(0x3cd4), 0x40 }, ++ { CCI_REG8(0x3cd5), 0x40 }, { CCI_REG8(0x3cd6), 0x40 }, ++ { CCI_REG8(0x3cd7), 0x40 }, { CCI_REG8(0x3cd8), 0x40 }, ++ { CCI_REG8(0x3cd9), 0x40 }, { CCI_REG8(0x3cda), 0x40 }, ++ { CCI_REG8(0x3cdb), 0x40 }, { CCI_REG8(0x3cdc), 0x40 }, ++ { CCI_REG8(0x3cdd), 0x40 }, { CCI_REG8(0x3cde), 0x40 }, ++ { CCI_REG8(0x3cdf), 0x40 }, { CCI_REG8(0x3ce0), 0x40 }, ++ { CCI_REG8(0x3ce1), 0x40 }, { CCI_REG8(0x3ce2), 0x40 }, ++ { CCI_REG8(0x3ce3), 0x40 }, { CCI_REG8(0x3ce4), 0x40 }, ++ { CCI_REG8(0x3ce5), 0x40 }, { CCI_REG8(0x3ce6), 0x40 }, ++ { CCI_REG8(0x3ce7), 0x40 }, { CCI_REG8(0x3ce8), 0x40 }, ++ { CCI_REG8(0x3ce9), 0x40 }, { CCI_REG8(0x3cea), 0x40 }, ++ { CCI_REG8(0x3ceb), 0x40 }, { CCI_REG8(0x3cec), 0x40 }, ++ { CCI_REG8(0x3ced), 0x40 }, { CCI_REG8(0x3cee), 0x40 }, ++ { CCI_REG8(0x3cef), 0x40 }, { CCI_REG8(0x3cf0), 0x40 }, ++ { CCI_REG8(0x3cf1), 0x40 }, { CCI_REG8(0x3cf2), 0x40 }, ++ { CCI_REG8(0x3cf3), 0x40 }, { CCI_REG8(0x3cf4), 0x40 }, ++ { CCI_REG8(0x3cf5), 0x40 }, { CCI_REG8(0x3cf6), 0x40 }, ++ { CCI_REG8(0x3cf7), 0x40 }, { CCI_REG8(0x3cf8), 0x40 }, ++ { CCI_REG8(0x3cf9), 0x40 }, { CCI_REG8(0x3cfa), 0x40 }, ++ { CCI_REG8(0x3cfb), 0x40 }, { CCI_REG8(0x3cfc), 0x40 }, ++ { CCI_REG8(0x3cfd), 0x40 }, { CCI_REG8(0x3cfe), 0x40 }, ++ { CCI_REG8(0x3cff), 0x40 }, { CCI_REG8(0x3d00), 0x40 }, ++ { CCI_REG8(0x3d01), 0x40 }, { CCI_REG8(0x3d02), 0x40 }, ++ { CCI_REG8(0x3d03), 0x40 }, { CCI_REG8(0x3d04), 0x40 }, ++ { CCI_REG8(0x3d05), 0x40 }, { CCI_REG8(0x3d06), 0x40 }, ++ { CCI_REG8(0x3d07), 0x40 }, { CCI_REG8(0x3d08), 0x40 }, ++ { CCI_REG8(0x3d09), 0x40 }, { CCI_REG8(0x3d0a), 0x40 }, ++ { CCI_REG8(0x3d0b), 0xcd }, { CCI_REG8(0x3d0c), 0xcd }, ++ { CCI_REG8(0x3d0d), 0xcd }, { CCI_REG8(0x3d0e), 0xcd }, ++ { CCI_REG8(0x3d0f), 0xcd }, { CCI_REG8(0x3d10), 0xcd }, ++ { CCI_REG8(0x3d11), 0xcd }, { CCI_REG8(0x3d12), 0xcd }, ++ { CCI_REG8(0x3d13), 0xcd }, { CCI_REG8(0x3d14), 0xcd }, ++ { CCI_REG8(0x3d15), 0xcd }, { CCI_REG8(0x3d16), 0xcd }, ++ { CCI_REG8(0x3d17), 0xcd }, { CCI_REG8(0x3d18), 0xcd }, ++ { CCI_REG8(0x3d19), 0xcd }, { CCI_REG8(0x3d1a), 0xcd }, ++ { CCI_REG8(0x3d1b), 0xcd }, { CCI_REG8(0x3d1c), 0xcd }, ++ { CCI_REG8(0x3d1d), 0xcd }, { CCI_REG8(0x3d1e), 0xcd }, ++ { CCI_REG8(0x3d1f), 0xcd }, { CCI_REG8(0x3d20), 0xcd }, ++ { CCI_REG8(0x3d21), 0xcd }, { CCI_REG8(0x3d22), 0xcd }, ++ { CCI_REG8(0x3d23), 0xcd }, { CCI_REG8(0x3d24), 0xcd }, ++ { CCI_REG8(0x3d25), 0xcd }, { CCI_REG8(0x3d26), 0xcd }, ++ { CCI_REG8(0x3d27), 0xcd }, { CCI_REG8(0x3d28), 0xcd }, ++ { CCI_REG8(0x3d29), 0xcd }, { CCI_REG8(0x3d2a), 0xcd }, ++ { CCI_REG8(0x3d2b), 0xcd }, { CCI_REG8(0x3d2c), 0xcd }, ++ { CCI_REG8(0x3d2d), 0xcd }, { CCI_REG8(0x3d2e), 0xcd }, ++ { CCI_REG8(0x3d2f), 0xcd }, { CCI_REG8(0x3d30), 0xcd }, ++ { CCI_REG8(0x3d31), 0xcd }, { CCI_REG8(0x3d32), 0xcd }, ++ { CCI_REG8(0x3d33), 0xcd }, { CCI_REG8(0x3d34), 0xcd }, ++ { CCI_REG8(0x3d35), 0xcd }, { CCI_REG8(0x3d36), 0xcd }, ++ { CCI_REG8(0x3d37), 0xcd }, { CCI_REG8(0x3d38), 0xcd }, ++ { CCI_REG8(0x3d39), 0xcd }, { CCI_REG8(0x3d3a), 0xcd }, ++ { CCI_REG8(0x3d3b), 0xcd }, { CCI_REG8(0x3d3c), 0xcd }, ++ { CCI_REG8(0x3d3d), 0xcd }, { CCI_REG8(0x3d3e), 0xcd }, ++ { CCI_REG8(0x3d3f), 0xcd }, { CCI_REG8(0x3d40), 0xcd }, ++ { CCI_REG8(0x3d41), 0xcd }, { CCI_REG8(0x3d42), 0xcd }, ++ { CCI_REG8(0x3d43), 0xcd }, { CCI_REG8(0x3d44), 0xcd }, ++ { CCI_REG8(0x3d45), 0xcd }, { CCI_REG8(0x3d46), 0xcd }, ++ { CCI_REG8(0x3d47), 0xcd }, { CCI_REG8(0x3d48), 0xcd }, ++ { CCI_REG8(0x3d49), 0xcd }, { CCI_REG8(0x3d4a), 0xcd }, ++ { CCI_REG8(0x3d4b), 0xcd }, { CCI_REG8(0x3d4c), 0xcd }, ++ { CCI_REG8(0x3d4d), 0xcd }, { CCI_REG8(0x3d4e), 0xcd }, ++ { CCI_REG8(0x3d4f), 0xcd }, { CCI_REG8(0x3d50), 0xcd }, ++ { CCI_REG8(0x3d51), 0xcd }, { CCI_REG8(0x3d52), 0xcd }, ++ { CCI_REG8(0x3d53), 0xcd }, { CCI_REG8(0x3d54), 0xcd }, ++ { CCI_REG8(0x3d55), 0xcd }, { CCI_REG8(0x3d56), 0xcd }, ++ { CCI_REG8(0x3d57), 0xcd }, { CCI_REG8(0x3d58), 0xcd }, ++ { CCI_REG8(0x3d59), 0xcd }, { CCI_REG8(0x3d5a), 0xcd }, ++ { CCI_REG8(0x3d5b), 0xcd }, { CCI_REG8(0x3d5c), 0xcd }, ++ { CCI_REG8(0x3d5d), 0xcd }, { CCI_REG8(0x3d5e), 0xcd }, ++ { CCI_REG8(0x3d5f), 0xcd }, { CCI_REG8(0x3d60), 0xcd }, ++ { CCI_REG8(0x3d61), 0xcd }, { CCI_REG8(0x3d62), 0xcd }, ++ { CCI_REG8(0x3d63), 0xcd }, { CCI_REG8(0x3d64), 0xcd }, ++ { CCI_REG8(0x3d65), 0x40 }, { CCI_REG8(0x3d66), 0x40 }, ++ { CCI_REG8(0x3d67), 0x40 }, { CCI_REG8(0x3d68), 0x40 }, ++ { CCI_REG8(0x3d69), 0x40 }, { CCI_REG8(0x3d6a), 0x40 }, ++ { CCI_REG8(0x3d6b), 0x40 }, { CCI_REG8(0x3d6c), 0x40 }, ++ { CCI_REG8(0x3d6d), 0x40 }, { CCI_REG8(0x3d6e), 0x40 }, ++ { CCI_REG8(0x3d6f), 0x40 }, { CCI_REG8(0x3d70), 0x40 }, ++ { CCI_REG8(0x3d71), 0x40 }, { CCI_REG8(0x3d72), 0x40 }, ++ { CCI_REG8(0x3d73), 0x40 }, { CCI_REG8(0x3d74), 0x40 }, ++ { CCI_REG8(0x3d75), 0x40 }, { CCI_REG8(0x3d76), 0x40 }, ++ { CCI_REG8(0x3d77), 0x40 }, { CCI_REG8(0x3d78), 0x40 }, ++ { CCI_REG8(0x3d79), 0x40 }, { CCI_REG8(0x3d7a), 0x40 }, ++ { CCI_REG8(0x3d7b), 0x40 }, { CCI_REG8(0x3d7c), 0x40 }, ++ { CCI_REG8(0x3d7d), 0x40 }, { CCI_REG8(0x3d7e), 0x40 }, ++ { CCI_REG8(0x3d7f), 0x40 }, { CCI_REG8(0x3d80), 0x40 }, ++ { CCI_REG8(0x3d81), 0x40 }, { CCI_REG8(0x3d82), 0x40 }, ++ { CCI_REG8(0x3d83), 0x40 }, { CCI_REG8(0x3d84), 0x40 }, ++ { CCI_REG8(0x3d85), 0x40 }, { CCI_REG8(0x3d86), 0x40 }, ++ { CCI_REG8(0x3d87), 0x40 }, { CCI_REG8(0x3d88), 0x40 }, ++ { CCI_REG8(0x3d89), 0x40 }, { CCI_REG8(0x3d8a), 0x40 }, ++ { CCI_REG8(0x3d8b), 0x40 }, { CCI_REG8(0x3d8c), 0x40 }, ++ { CCI_REG8(0x3d8d), 0x40 }, { CCI_REG8(0x3d8e), 0x40 }, ++ { CCI_REG8(0x3d8f), 0x40 }, { CCI_REG8(0x3d90), 0x40 }, ++ { CCI_REG8(0x3d91), 0x40 }, { CCI_REG8(0x3d92), 0x40 }, ++ { CCI_REG8(0x3d93), 0x40 }, { CCI_REG8(0x3d94), 0x40 }, ++ { CCI_REG8(0x3d95), 0x40 }, { CCI_REG8(0x3d96), 0x40 }, ++ { CCI_REG8(0x3d97), 0x40 }, { CCI_REG8(0x3d98), 0x40 }, ++ { CCI_REG8(0x3d99), 0x40 }, { CCI_REG8(0x3d9a), 0x40 }, ++ { CCI_REG8(0x3d9b), 0x40 }, { CCI_REG8(0x3d9c), 0x40 }, ++ { CCI_REG8(0x3d9d), 0x40 }, { CCI_REG8(0x3d9e), 0x40 }, ++ { CCI_REG8(0x3d9f), 0x40 }, { CCI_REG8(0x3da0), 0x40 }, ++ { CCI_REG8(0x3da1), 0x40 }, { CCI_REG8(0x3da2), 0x40 }, ++ { CCI_REG8(0x3da3), 0x40 }, { CCI_REG8(0x3da4), 0x40 }, ++ { CCI_REG8(0x3da5), 0x40 }, { CCI_REG8(0x3da6), 0x40 }, ++ { CCI_REG8(0x3da7), 0x40 }, { CCI_REG8(0x3da8), 0x40 }, ++ { CCI_REG8(0x3da9), 0x40 }, { CCI_REG8(0x3daa), 0x40 }, ++ { CCI_REG8(0x3dab), 0x40 }, { CCI_REG8(0x3dac), 0x40 }, ++ { CCI_REG8(0x3dad), 0x40 }, { CCI_REG8(0x3dae), 0x40 }, ++ { CCI_REG8(0x3daf), 0x40 }, { CCI_REG8(0x3db0), 0x40 }, ++ { CCI_REG8(0x3db1), 0x40 }, { CCI_REG8(0x3db2), 0x40 }, ++ { CCI_REG8(0x3db3), 0x40 }, { CCI_REG8(0x3db4), 0x40 }, ++ { CCI_REG8(0x3db5), 0x40 }, { CCI_REG8(0x3db6), 0x40 }, ++ { CCI_REG8(0x3db7), 0x40 }, { CCI_REG8(0x3db8), 0x40 }, ++ { CCI_REG8(0x3db9), 0x40 }, { CCI_REG8(0x3dba), 0x40 }, ++ { CCI_REG8(0x3dbb), 0x40 }, { CCI_REG8(0x3dbc), 0x40 }, ++ { CCI_REG8(0x3dbd), 0x40 }, { CCI_REG8(0x3dbe), 0x40 }, ++ { CCI_REG8(0x3dbf), 0xcd }, { CCI_REG8(0x3dc0), 0xcd }, ++ { CCI_REG8(0x3dc1), 0xcd }, { CCI_REG8(0x3dc2), 0xcd }, ++ { CCI_REG8(0x3dc3), 0xcd }, { CCI_REG8(0x3dc4), 0xcd }, ++ { CCI_REG8(0x3dc5), 0xcd }, { CCI_REG8(0x3dc6), 0xcd }, ++ { CCI_REG8(0x3dc7), 0xcd }, { CCI_REG8(0x3dc8), 0xcd }, ++ { CCI_REG8(0x3dc9), 0xcd }, { CCI_REG8(0x3dca), 0xcd }, ++ { CCI_REG8(0x3dcb), 0xcd }, { CCI_REG8(0x3dcc), 0xcd }, ++ { CCI_REG8(0x3dcd), 0xcd }, { CCI_REG8(0x3dce), 0xcd }, ++ { CCI_REG8(0x3dcf), 0xcd }, { CCI_REG8(0x3dd0), 0xcd }, ++ { CCI_REG8(0x3dd1), 0xcd }, { CCI_REG8(0x3dd2), 0xcd }, ++ { CCI_REG8(0x3dd3), 0xcd }, { CCI_REG8(0x3dd4), 0xcd }, ++ { CCI_REG8(0x3dd5), 0xcd }, { CCI_REG8(0x3dd6), 0xcd }, ++ { CCI_REG8(0x3dd7), 0xcd }, { CCI_REG8(0x3dd8), 0xcd }, ++ { CCI_REG8(0x3dd9), 0xcd }, { CCI_REG8(0x3dda), 0xcd }, ++ { CCI_REG8(0x3ddb), 0xcd }, { CCI_REG8(0x3ddc), 0xcd }, ++ { CCI_REG8(0x3ddd), 0xcd }, { CCI_REG8(0x3dde), 0xcd }, ++ { CCI_REG8(0x3ddf), 0xcd }, { CCI_REG8(0x3de0), 0xcd }, ++ { CCI_REG8(0x3de1), 0xcd }, { CCI_REG8(0x3de2), 0xcd }, ++ { CCI_REG8(0x3de3), 0xcd }, { CCI_REG8(0x3de4), 0xcd }, ++ { CCI_REG8(0x3de5), 0xcd }, { CCI_REG8(0x3de6), 0xcd }, ++ { CCI_REG8(0x3de7), 0xcd }, { CCI_REG8(0x3de8), 0xcd }, ++ { CCI_REG8(0x3de9), 0xcd }, { CCI_REG8(0x3dea), 0xcd }, ++ { CCI_REG8(0x3deb), 0xcd }, { CCI_REG8(0x3dec), 0xcd }, ++ { CCI_REG8(0x3ded), 0xcd }, { CCI_REG8(0x3dee), 0xcd }, ++ { CCI_REG8(0x3def), 0xcd }, { CCI_REG8(0x3df0), 0xcd }, ++ { CCI_REG8(0x3df1), 0xcd }, { CCI_REG8(0x3df2), 0xcd }, ++ { CCI_REG8(0x3df3), 0xcd }, { CCI_REG8(0x3df4), 0xcd }, ++ { CCI_REG8(0x3df5), 0xcd }, { CCI_REG8(0x3df6), 0xcd }, ++ { CCI_REG8(0x3df7), 0xcd }, { CCI_REG8(0x3df8), 0xcd }, ++ { CCI_REG8(0x3df9), 0xcd }, { CCI_REG8(0x3dfa), 0xcd }, ++ { CCI_REG8(0x3dfb), 0xcd }, { CCI_REG8(0x3dfc), 0xcd }, ++ { CCI_REG8(0x3dfd), 0xcd }, { CCI_REG8(0x3dfe), 0xcd }, ++ { CCI_REG8(0x3dff), 0xcd }, { CCI_REG8(0x3e00), 0xcd }, ++ { CCI_REG8(0x3e01), 0xcd }, { CCI_REG8(0x3e02), 0xcd }, ++ { CCI_REG8(0x3e03), 0xcd }, { CCI_REG8(0x3e04), 0xcd }, ++ { CCI_REG8(0x3e05), 0xcd }, { CCI_REG8(0x3e06), 0xcd }, ++ { CCI_REG8(0x3e07), 0xcd }, { CCI_REG8(0x3e08), 0xcd }, ++ { CCI_REG8(0x3e09), 0xcd }, { CCI_REG8(0x3e0a), 0xcd }, ++ { CCI_REG8(0x3e0b), 0xcd }, { CCI_REG8(0x3e0c), 0xcd }, ++ { CCI_REG8(0x3e0d), 0xcd }, { CCI_REG8(0x3e0e), 0xcd }, ++ { CCI_REG8(0x3e0f), 0xcd }, { CCI_REG8(0x3e10), 0xcd }, ++ { CCI_REG8(0x3e11), 0xcd }, { CCI_REG8(0x3e12), 0xcd }, ++ { CCI_REG8(0x3e13), 0xcd }, { CCI_REG8(0x3e14), 0xcd }, ++ { CCI_REG8(0x3e15), 0xcd }, { CCI_REG8(0x3e16), 0xcd }, ++ { CCI_REG8(0x3e17), 0xcd }, { CCI_REG8(0x3e18), 0xcd }, ++ { CCI_REG8(0x3e19), 0xcd }, { CCI_REG8(0x3e1a), 0xcd }, ++ { CCI_REG8(0x3e1b), 0xcd }, { CCI_REG8(0x3e1c), 0xcd }, ++ { CCI_REG8(0x3e1d), 0xcd }, { CCI_REG8(0x3e1e), 0xcd }, ++ { CCI_REG8(0x3e1f), 0xcd }, { CCI_REG8(0x3e20), 0xcd }, ++ { CCI_REG8(0x3e21), 0xcd }, { CCI_REG8(0x3e22), 0xcd }, ++ { CCI_REG8(0x3e23), 0xcd }, { CCI_REG8(0x3e24), 0xcd }, ++ { CCI_REG8(0x3e25), 0xcd }, { CCI_REG8(0x3e26), 0xcd }, ++ { CCI_REG8(0x3e27), 0xcd }, { CCI_REG8(0x3e28), 0xcd }, ++ { CCI_REG8(0x3e29), 0xcd }, { CCI_REG8(0x3e2a), 0xcd }, ++ { CCI_REG8(0x3e2b), 0xcd }, { CCI_REG8(0x3e2c), 0xcd }, ++ { CCI_REG8(0x3e2d), 0xcd }, { CCI_REG8(0x3e2e), 0xcd }, ++ { CCI_REG8(0x3e2f), 0xcd }, { CCI_REG8(0x3e30), 0xcd }, ++ { CCI_REG8(0x3e31), 0xcd }, { CCI_REG8(0x3e32), 0xcd }, ++ { CCI_REG8(0x3e33), 0xcd }, { CCI_REG8(0x3e34), 0xcd }, ++ { CCI_REG8(0x3e35), 0xcd }, { CCI_REG8(0x3e36), 0xcd }, ++ { CCI_REG8(0x3e37), 0xcd }, { CCI_REG8(0x3e38), 0xcd }, ++ { CCI_REG8(0x3e39), 0xcd }, { CCI_REG8(0x3e3a), 0xcd }, ++ { CCI_REG8(0x3e3b), 0xcd }, { CCI_REG8(0x3e3c), 0xcd }, ++ { CCI_REG8(0x3e3d), 0xcd }, { CCI_REG8(0x3e3e), 0xcd }, ++ { CCI_REG8(0x3e3f), 0xcd }, { CCI_REG8(0x3e40), 0xcd }, ++ { CCI_REG8(0x3e41), 0xcd }, { CCI_REG8(0x3e42), 0xcd }, ++ { CCI_REG8(0x3e43), 0xcd }, { CCI_REG8(0x3e44), 0xcd }, ++ { CCI_REG8(0x3e45), 0xcd }, { CCI_REG8(0x3e46), 0xcd }, ++ { CCI_REG8(0x3e47), 0xcd }, { CCI_REG8(0x3e48), 0xcd }, ++ { CCI_REG8(0x3e49), 0xcd }, { CCI_REG8(0x3e4a), 0xcd }, ++ { CCI_REG8(0x3e4b), 0xcd }, { CCI_REG8(0x3e4c), 0xcd }, ++ { CCI_REG8(0x3e4d), 0xcd }, { CCI_REG8(0x3e4e), 0xcd }, ++ { CCI_REG8(0x3e4f), 0xcd }, { CCI_REG8(0x3e50), 0xcd }, ++ { CCI_REG8(0x3e51), 0xcd }, { CCI_REG8(0x3e52), 0xcd }, ++ { CCI_REG8(0x3e53), 0xcd }, { CCI_REG8(0x3e54), 0xcd }, ++ { CCI_REG8(0x3e55), 0xcd }, { CCI_REG8(0x3e56), 0xcd }, ++ { CCI_REG8(0x3e57), 0xcd }, { CCI_REG8(0x3e58), 0xcd }, ++ { CCI_REG8(0x3e59), 0xcd }, { CCI_REG8(0x3e5a), 0xcd }, ++ { CCI_REG8(0x3e5b), 0xcd }, { CCI_REG8(0x3e5c), 0xcd }, ++ { CCI_REG8(0x3e5d), 0xcd }, { CCI_REG8(0x3e5e), 0xcd }, ++ { CCI_REG8(0x3e5f), 0xcd }, { CCI_REG8(0x3e60), 0xcd }, ++ { CCI_REG8(0x3e61), 0xcd }, { CCI_REG8(0x3e62), 0xcd }, ++ { CCI_REG8(0x3e63), 0xcd }, { CCI_REG8(0x3e64), 0xcd }, ++ { CCI_REG8(0x3e65), 0xcd }, { CCI_REG8(0x3e66), 0xcd }, ++ { CCI_REG8(0x3e67), 0xcd }, { CCI_REG8(0x3e68), 0xcd }, ++ { CCI_REG8(0x3e69), 0xcd }, { CCI_REG8(0x3e6a), 0xcd }, ++ { CCI_REG8(0x3e6b), 0xcd }, { CCI_REG8(0x3e6c), 0xcd }, ++ { CCI_REG8(0x3e6d), 0xcd }, { CCI_REG8(0x3e6e), 0xcd }, ++ { CCI_REG8(0x3e6f), 0xcd }, { CCI_REG8(0x3e70), 0xcd }, ++ { CCI_REG8(0x3e71), 0xcd }, { CCI_REG8(0x3e72), 0xcd }, ++ { CCI_REG8(0x3e73), 0xcd }, { CCI_REG8(0x3e74), 0xcd }, ++ { CCI_REG8(0x3e75), 0xcd }, { CCI_REG8(0x3e76), 0xcd }, ++ { CCI_REG8(0x3e77), 0xcd }, { CCI_REG8(0x3e78), 0xcd }, ++ { CCI_REG8(0x3e79), 0xcd }, { CCI_REG8(0x3e7a), 0xcd }, ++ { CCI_REG8(0x3e7b), 0xcd }, { CCI_REG8(0x3e7c), 0xcd }, ++ { CCI_REG8(0x3e7d), 0xcd }, { CCI_REG8(0x3e7e), 0xcd }, ++ { CCI_REG8(0x3e7f), 0xcd }, { CCI_REG8(0x3e80), 0xcd }, ++ { CCI_REG8(0x3e81), 0xcd }, { CCI_REG8(0x3e82), 0xcd }, ++ { CCI_REG8(0x3e83), 0xcd }, { CCI_REG8(0x3e84), 0xcd }, ++ { CCI_REG8(0x3e85), 0xcd }, { CCI_REG8(0x3e86), 0xcd }, ++ { CCI_REG8(0x3e87), 0xcd }, { CCI_REG8(0x3e88), 0xcd }, ++ { CCI_REG8(0x3e89), 0xcd }, { CCI_REG8(0x3e8a), 0xcd }, ++ { CCI_REG8(0x3e8b), 0xcd }, { CCI_REG8(0x3e8c), 0xcd }, ++ { CCI_REG8(0x3e8d), 0xcd }, { CCI_REG8(0x3e8e), 0xcd }, ++ { CCI_REG8(0x3e8f), 0xcd }, { CCI_REG8(0x3e90), 0xcd }, ++ { CCI_REG8(0x3e91), 0xcd }, { CCI_REG8(0x3e92), 0xcd }, ++ { CCI_REG8(0x3e93), 0xcd }, { CCI_REG8(0x3e94), 0xcd }, ++ { CCI_REG8(0x3e95), 0xcd }, { CCI_REG8(0x3e96), 0xcd }, ++ { CCI_REG8(0x3e97), 0xcd }, { CCI_REG8(0x3e98), 0xcd }, ++ { CCI_REG8(0x3e99), 0xcd }, { CCI_REG8(0x3e9a), 0xcd }, ++ { CCI_REG8(0x3e9b), 0xcd }, { CCI_REG8(0x3e9c), 0xcd }, ++ { CCI_REG8(0x3e9d), 0xcd }, { CCI_REG8(0x3e9e), 0xcd }, ++ { CCI_REG8(0x3e9f), 0xcd }, { CCI_REG8(0xfff9), 0x06 }, ++ { CCI_REG8(0xc03f), 0x01 }, { CCI_REG8(0xc03e), 0x08 }, ++ { CCI_REG8(0xc02c), 0xff }, { CCI_REG8(0xc005), 0x06 }, ++ { CCI_REG8(0xc006), 0x30 }, { CCI_REG8(0xc007), 0xc0 }, ++ { CCI_REG8(0xc027), 0x01 }, { CCI_REG8(0x30c0), 0x05 }, ++ { CCI_REG8(0x30c1), 0x9f }, { CCI_REG8(0x30c2), 0x06 }, ++ { CCI_REG8(0x30c3), 0x5f }, { CCI_REG8(0x30c4), 0x80 }, ++ { CCI_REG8(0x30c5), 0x08 }, { CCI_REG8(0x30c6), 0x39 }, ++ { CCI_REG8(0x30c7), 0x00 }, { CCI_REG8(0xc046), 0x20 }, ++ { CCI_REG8(0xc043), 0x01 }, { CCI_REG8(0xc04b), 0x01 }, ++ { CCI_REG8(0x0102), 0x01 }, { CCI_REG8(0x0100), 0x00 }, ++ { CCI_REG8(0x0102), 0x00 }, { CCI_REG8(0x3015), 0xf0 }, ++ { CCI_REG8(0x3018), 0xf0 }, { CCI_REG8(0x301c), 0xf0 }, ++ { CCI_REG8(0x301d), 0xf6 }, { CCI_REG8(0x301e), 0xf1 } ++}; ++ ++static const struct cci_reg_sequence ov64a40_9248x6944 = { ++ { CCI_REG8(0x0305), 0x98 }, { CCI_REG8(0x0306), 0x04 }, ++ { CCI_REG8(0x0307), 0x01 }, { CCI_REG8(0x4837), 0x1a }, ++ { CCI_REG8(0x4888), 0x10 }, { CCI_REG8(0x4860), 0x00 }, ++ { CCI_REG8(0x4850), 0x43 }, { CCI_REG8(0x480C), 0x92 }, ++ { CCI_REG8(0x5001), 0x21 } ++}; ++ ++static const struct cci_reg_sequence ov64a40_8000x6000 = { ++ { CCI_REG8(0x0305), 0x98 }, { CCI_REG8(0x0306), 0x04 }, ++ { CCI_REG8(0x0307), 0x01 }, { CCI_REG8(0x4837), 0x1a }, ++ { CCI_REG8(0x4888), 0x10 }, { CCI_REG8(0x4860), 0x00 }, ++ { CCI_REG8(0x4850), 0x43 }, { CCI_REG8(0x480C), 0x92 }, ++ { CCI_REG8(0x5001), 0x21 } ++}; ++ ++static const struct cci_reg_sequence ov64a40_4624_3472 = { ++ { CCI_REG8(0x034b), 0x02 }, { CCI_REG8(0x3504), 0x08 }, ++ { CCI_REG8(0x360d), 0x82 }, { CCI_REG8(0x368a), 0x2e }, ++ { CCI_REG8(0x3712), 0x50 }, { CCI_REG8(0x3822), 0x00 }, ++ { CCI_REG8(0x3827), 0x40 }, { CCI_REG8(0x383d), 0x08 }, ++ { CCI_REG8(0x383f), 0x00 }, { CCI_REG8(0x384c), 0x02 }, ++ { CCI_REG8(0x384d), 0xba }, { CCI_REG8(0x3852), 0x00 }, ++ { CCI_REG8(0x3856), 0x08 }, { CCI_REG8(0x3857), 0x08 }, ++ { CCI_REG8(0x3858), 0x10 }, { CCI_REG8(0x3859), 0x10 }, ++ { CCI_REG8(0x4016), 0x0f }, { CCI_REG8(0x4018), 0x03 }, ++ { CCI_REG8(0x4504), 0x1e }, { CCI_REG8(0x4523), 0x41 }, ++ { CCI_REG8(0x45c0), 0x01 }, { CCI_REG8(0x4641), 0x12 }, ++ { CCI_REG8(0x4643), 0x0c }, { CCI_REG8(0x4915), 0x02 }, ++ { CCI_REG8(0x4916), 0x1d }, { CCI_REG8(0x4a15), 0x02 }, ++ { CCI_REG8(0x4a16), 0x1d }, { CCI_REG8(0x3703), 0x72 }, ++ { CCI_REG8(0x3709), 0xe6 }, { CCI_REG8(0x3a60), 0x68 }, ++ { CCI_REG8(0x3a6f), 0x68 }, { CCI_REG8(0x3a5e), 0xdc }, ++ { CCI_REG8(0x3a6d), 0xdc }, { CCI_REG8(0x3721), 0xc9 }, ++ { CCI_REG8(0x5250), 0x06 }, { CCI_REG8(0x527a), 0x00 }, ++ { CCI_REG8(0x527b), 0x65 }, { CCI_REG8(0x527c), 0x00 }, ++ { CCI_REG8(0x527d), 0x82 }, { CCI_REG8(0x5280), 0x24 }, ++ { CCI_REG8(0x5281), 0x40 }, { CCI_REG8(0x5282), 0x1b }, ++ { CCI_REG8(0x5283), 0x40 }, { CCI_REG8(0x5284), 0x24 }, ++ { CCI_REG8(0x5285), 0x40 }, { CCI_REG8(0x5286), 0x1b }, ++ { CCI_REG8(0x5287), 0x40 }, { CCI_REG8(0x5200), 0x24 }, ++ { CCI_REG8(0x5201), 0x40 }, { CCI_REG8(0x5202), 0x1b }, ++ { CCI_REG8(0x5203), 0x40 }, { CCI_REG8(0x481b), 0x35 }, ++ { CCI_REG8(0x4862), 0x25 }, { CCI_REG8(0x3400), 0x00 }, ++ { CCI_REG8(0x3421), 0x23 }, { CCI_REG8(0x3422), 0xfc }, ++ { CCI_REG8(0x3423), 0x07 }, { CCI_REG8(0x3424), 0x01 }, ++ { CCI_REG8(0x3425), 0x04 }, { CCI_REG8(0x3426), 0x50 }, ++ { CCI_REG8(0x3427), 0x55 }, { CCI_REG8(0x3428), 0x15 }, ++ { CCI_REG8(0x3429), 0x00 }, { CCI_REG8(0x3025), 0x03 }, ++ { CCI_REG8(0x5250), 0x06 }, { CCI_REG8(0x0305), 0x98 }, ++ { CCI_REG8(0x0306), 0x04 }, { CCI_REG8(0x0307), 0x01 }, ++ { CCI_REG8(0x4837), 0x1a }, { CCI_REG8(0x4888), 0x10 }, ++ { CCI_REG8(0x4860), 0x00 }, { CCI_REG8(0x4850), 0x43 }, ++ { CCI_REG8(0x480C), 0x92 }, { CCI_REG8(0x5001), 0x21 } ++}; ++ ++static const struct cci_reg_sequence ov64a40_3840x2160 = { ++ { CCI_REG8(0x034a), 0x05 }, { CCI_REG8(0x034b), 0x05 }, ++ { CCI_REG8(0x3504), 0x08 }, { CCI_REG8(0x360d), 0x82 }, ++ { CCI_REG8(0x368a), 0x2e }, { CCI_REG8(0x3712), 0x50 }, ++ { CCI_REG8(0x3822), 0x00 }, { CCI_REG8(0x3827), 0x40 }, ++ { CCI_REG8(0x383d), 0x08 }, { CCI_REG8(0x383f), 0x00 }, ++ { CCI_REG8(0x384c), 0x02 }, { CCI_REG8(0x384d), 0xba }, ++ { CCI_REG8(0x3852), 0x00 }, { CCI_REG8(0x3856), 0x08 }, ++ { CCI_REG8(0x3857), 0x08 }, { CCI_REG8(0x3858), 0x10 }, ++ { CCI_REG8(0x3859), 0x10 }, { CCI_REG8(0x4016), 0x0f }, ++ { CCI_REG8(0x4018), 0x03 }, { CCI_REG8(0x4504), 0x1e }, ++ { CCI_REG8(0x4523), 0x41 }, { CCI_REG8(0x45c0), 0x01 }, ++ { CCI_REG8(0x4641), 0x12 }, { CCI_REG8(0x4643), 0x0c }, ++ { CCI_REG8(0x4915), 0x02 }, { CCI_REG8(0x4916), 0x1d }, ++ { CCI_REG8(0x4a15), 0x02 }, { CCI_REG8(0x4a16), 0x1d }, ++ { CCI_REG8(0x3703), 0x72 }, { CCI_REG8(0x3709), 0xe6 }, ++ { CCI_REG8(0x3a60), 0x68 }, { CCI_REG8(0x3a6f), 0x68 }, ++ { CCI_REG8(0x3a5e), 0xdc }, { CCI_REG8(0x3a6d), 0xdc }, ++ { CCI_REG8(0x3721), 0xc9 }, { CCI_REG8(0x5250), 0x06 }, ++ { CCI_REG8(0x527a), 0x00 }, { CCI_REG8(0x527b), 0x65 }, ++ { CCI_REG8(0x527c), 0x00 }, { CCI_REG8(0x527d), 0x82 }, ++ { CCI_REG8(0x5280), 0x24 }, { CCI_REG8(0x5281), 0x40 }, ++ { CCI_REG8(0x5282), 0x1b }, { CCI_REG8(0x5283), 0x40 }, ++ { CCI_REG8(0x5284), 0x24 }, { CCI_REG8(0x5285), 0x40 }, ++ { CCI_REG8(0x5286), 0x1b }, { CCI_REG8(0x5287), 0x40 }, ++ { CCI_REG8(0x5200), 0x24 }, { CCI_REG8(0x5201), 0x40 }, ++ { CCI_REG8(0x5202), 0x1b }, { CCI_REG8(0x5203), 0x40 }, ++ { CCI_REG8(0x481b), 0x35 }, { CCI_REG8(0x4862), 0x25 }, ++ { CCI_REG8(0x3400), 0x00 }, { CCI_REG8(0x3421), 0x23 }, ++ { CCI_REG8(0x3422), 0xfc }, { CCI_REG8(0x3423), 0x07 }, ++ { CCI_REG8(0x3424), 0x01 }, { CCI_REG8(0x3425), 0x04 }, ++ { CCI_REG8(0x3426), 0x50 }, { CCI_REG8(0x3427), 0x55 }, ++ { CCI_REG8(0x3428), 0x15 }, { CCI_REG8(0x3429), 0x00 }, ++ { CCI_REG8(0x3025), 0x03 }, { CCI_REG8(0x5250), 0x06 }, ++ { CCI_REG8(0x0305), 0x98 }, { CCI_REG8(0x0306), 0x04 }, ++ { CCI_REG8(0x0345), 0x90 }, { CCI_REG8(0x0307), 0x01 }, ++ { CCI_REG8(0x4837), 0x1a }, { CCI_REG8(0x4888), 0x10 }, ++ { CCI_REG8(0x4860), 0x00 }, { CCI_REG8(0x4850), 0x43 }, ++ { CCI_REG8(0x480C), 0x92 }, { CCI_REG8(0x5001), 0x21 }, ++ { CCI_REG8(0x5000), 0x01 } ++}; ++ ++static const struct cci_reg_sequence ov64a40_2312_1736 = { ++ { CCI_REG8(0x034b), 0x02 }, { CCI_REG8(0x3504), 0x08 }, ++ { CCI_REG8(0x360d), 0x82 }, { CCI_REG8(0x368a), 0x2e }, ++ { CCI_REG8(0x3712), 0x00 }, { CCI_REG8(0x3822), 0x08 }, ++ { CCI_REG8(0x3827), 0x40 }, { CCI_REG8(0x383d), 0x04 }, ++ { CCI_REG8(0x383f), 0x00 }, { CCI_REG8(0x384c), 0x01 }, ++ { CCI_REG8(0x384d), 0x12 }, { CCI_REG8(0x3852), 0x00 }, ++ { CCI_REG8(0x3856), 0x04 }, { CCI_REG8(0x3857), 0x04 }, ++ { CCI_REG8(0x3858), 0x08 }, { CCI_REG8(0x3859), 0x08 }, ++ { CCI_REG8(0x4016), 0x07 }, { CCI_REG8(0x4018), 0x01 }, ++ { CCI_REG8(0x4504), 0x00 }, { CCI_REG8(0x4523), 0x00 }, ++ { CCI_REG8(0x45c0), 0x01 }, { CCI_REG8(0x4641), 0x24 }, ++ { CCI_REG8(0x4643), 0x0c }, { CCI_REG8(0x4837), 0x0b }, ++ { CCI_REG8(0x4915), 0x02 }, { CCI_REG8(0x4916), 0x1d }, ++ { CCI_REG8(0x4a15), 0x02 }, { CCI_REG8(0x4a16), 0x1d }, ++ { CCI_REG8(0x5000), 0x55 }, { CCI_REG8(0x5001), 0x00 }, ++ { CCI_REG8(0x5002), 0x35 }, { CCI_REG8(0x5004), 0xc0 }, ++ { CCI_REG8(0x5068), 0x02 }, { CCI_REG8(0x3703), 0x6a }, ++ { CCI_REG8(0x3709), 0xa3 }, { CCI_REG8(0x3a60), 0x60 }, ++ { CCI_REG8(0x3a6f), 0x60 }, { CCI_REG8(0x3a5e), 0x99 }, ++ { CCI_REG8(0x3a6d), 0x99 }, { CCI_REG8(0x3721), 0xc1 }, ++ { CCI_REG8(0x5250), 0x06 }, { CCI_REG8(0x527a), 0x00 }, ++ { CCI_REG8(0x527b), 0x65 }, { CCI_REG8(0x527c), 0x00 }, ++ { CCI_REG8(0x527d), 0x82 }, { CCI_REG8(0x5280), 0x24 }, ++ { CCI_REG8(0x5281), 0x40 }, { CCI_REG8(0x5282), 0x1b }, ++ { CCI_REG8(0x5283), 0x40 }, { CCI_REG8(0x5284), 0x24 }, ++ { CCI_REG8(0x5285), 0x40 }, { CCI_REG8(0x5286), 0x1b }, ++ { CCI_REG8(0x5287), 0x40 }, { CCI_REG8(0x5200), 0x24 }, ++ { CCI_REG8(0x5201), 0x40 }, { CCI_REG8(0x5202), 0x1b }, ++ { CCI_REG8(0x5203), 0x40 }, { CCI_REG8(0x3684), 0x05 }, ++ { CCI_REG8(0x481b), 0x20 }, { CCI_REG8(0x51b0), 0x38 }, ++ { CCI_REG8(0x51b3), 0x0e }, { CCI_REG8(0x51b5), 0x04 }, ++ { CCI_REG8(0x51b6), 0x00 }, { CCI_REG8(0x51b7), 0x00 }, ++ { CCI_REG8(0x51b9), 0x70 }, { CCI_REG8(0x51bb), 0x10 }, ++ { CCI_REG8(0x51bc), 0x00 }, { CCI_REG8(0x51bd), 0x00 }, ++ { CCI_REG8(0x51b0), 0x38 }, { CCI_REG8(0x54b0), 0x38 }, ++ { CCI_REG8(0x54b3), 0x0e }, { CCI_REG8(0x54b5), 0x04 }, ++ { CCI_REG8(0x54b6), 0x00 }, { CCI_REG8(0x54b7), 0x00 }, ++ { CCI_REG8(0x54b9), 0x70 }, { CCI_REG8(0x54bb), 0x10 }, ++ { CCI_REG8(0x54bc), 0x00 }, { CCI_REG8(0x54bd), 0x00 }, ++ { CCI_REG8(0x57b0), 0x38 }, { CCI_REG8(0x57b3), 0x0e }, ++ { CCI_REG8(0x57b5), 0x04 }, { CCI_REG8(0x57b6), 0x00 }, ++ { CCI_REG8(0x57b7), 0x00 }, { CCI_REG8(0x57b9), 0x70 }, ++ { CCI_REG8(0x57bb), 0x10 }, { CCI_REG8(0x57bc), 0x00 }, ++ { CCI_REG8(0x57bd), 0x00 }, { CCI_REG8(0x0305), 0x98 }, ++ { CCI_REG8(0x0306), 0x04 }, { CCI_REG8(0x0307), 0x01 }, ++ { CCI_REG8(0x4837), 0x1a }, { CCI_REG8(0x4888), 0x10 }, ++ { CCI_REG8(0x4860), 0x00 }, { CCI_REG8(0x4850), 0x43 }, ++ { CCI_REG8(0x480C), 0x92 } ++}; ++ ++static const struct cci_reg_sequence ov64a40_1920x1080 = { ++ { CCI_REG8(0x034b), 0x02 }, { CCI_REG8(0x3504), 0x08 }, ++ { CCI_REG8(0x360d), 0x82 }, { CCI_REG8(0x368a), 0x2e }, ++ { CCI_REG8(0x3712), 0x00 }, { CCI_REG8(0x3822), 0x08 }, ++ { CCI_REG8(0x3827), 0x40 }, { CCI_REG8(0x383d), 0x04 }, ++ { CCI_REG8(0x383f), 0x00 }, { CCI_REG8(0x384c), 0x01 }, ++ { CCI_REG8(0x384d), 0x12 }, { CCI_REG8(0x3852), 0x00 }, ++ { CCI_REG8(0x3856), 0x04 }, { CCI_REG8(0x3857), 0x04 }, ++ { CCI_REG8(0x3858), 0x08 }, { CCI_REG8(0x3859), 0x08 }, ++ { CCI_REG8(0x4016), 0x07 }, { CCI_REG8(0x4018), 0x01 }, ++ { CCI_REG8(0x4504), 0x00 }, { CCI_REG8(0x4523), 0x00 }, ++ { CCI_REG8(0x45c0), 0x01 }, { CCI_REG8(0x4641), 0x24 }, ++ { CCI_REG8(0x4643), 0x0c }, { CCI_REG8(0x4837), 0x0b }, ++ { CCI_REG8(0x4915), 0x02 }, { CCI_REG8(0x4916), 0x1d }, ++ { CCI_REG8(0x4a15), 0x02 }, { CCI_REG8(0x4a16), 0x1d }, ++ { CCI_REG8(0x5000), 0x55 }, { CCI_REG8(0x5001), 0x00 }, ++ { CCI_REG8(0x5002), 0x35 }, { CCI_REG8(0x5004), 0xc0 }, ++ { CCI_REG8(0x5068), 0x02 }, { CCI_REG8(0x3703), 0x6a }, ++ { CCI_REG8(0x3709), 0xa3 }, { CCI_REG8(0x3a60), 0x60 }, ++ { CCI_REG8(0x3a6f), 0x60 }, { CCI_REG8(0x3a5e), 0x99 }, ++ { CCI_REG8(0x3a6d), 0x99 }, { CCI_REG8(0x3721), 0xc1 }, ++ { CCI_REG8(0x5250), 0x06 }, { CCI_REG8(0x527a), 0x00 }, ++ { CCI_REG8(0x527b), 0x65 }, { CCI_REG8(0x527c), 0x00 }, ++ { CCI_REG8(0x527d), 0x82 }, { CCI_REG8(0x5280), 0x24 }, ++ { CCI_REG8(0x5281), 0x40 }, { CCI_REG8(0x5282), 0x1b }, ++ { CCI_REG8(0x5283), 0x40 }, { CCI_REG8(0x5284), 0x24 }, ++ { CCI_REG8(0x5285), 0x40 }, { CCI_REG8(0x5286), 0x1b }, ++ { CCI_REG8(0x5287), 0x40 }, { CCI_REG8(0x5200), 0x24 }, ++ { CCI_REG8(0x5201), 0x40 }, { CCI_REG8(0x5202), 0x1b }, ++ { CCI_REG8(0x5203), 0x40 }, { CCI_REG8(0x3684), 0x05 }, ++ { CCI_REG8(0x481b), 0x20 }, { CCI_REG8(0x51b0), 0x38 }, ++ { CCI_REG8(0x51b3), 0x0e }, { CCI_REG8(0x51b5), 0x04 }, ++ { CCI_REG8(0x51b6), 0x00 }, { CCI_REG8(0x51b7), 0x00 }, ++ { CCI_REG8(0x51b9), 0x70 }, { CCI_REG8(0x51bb), 0x10 }, ++ { CCI_REG8(0x51bc), 0x00 }, { CCI_REG8(0x51bd), 0x00 }, ++ { CCI_REG8(0x51b0), 0x38 }, { CCI_REG8(0x54b0), 0x38 }, ++ { CCI_REG8(0x54b3), 0x0e }, { CCI_REG8(0x54b5), 0x04 }, ++ { CCI_REG8(0x54b6), 0x00 }, { CCI_REG8(0x54b7), 0x00 }, ++ { CCI_REG8(0x54b9), 0x70 }, { CCI_REG8(0x54bb), 0x10 }, ++ { CCI_REG8(0x54bc), 0x00 }, { CCI_REG8(0x54bd), 0x00 }, ++ { CCI_REG8(0x57b0), 0x38 }, { CCI_REG8(0x57b3), 0x0e }, ++ { CCI_REG8(0x57b5), 0x04 }, { CCI_REG8(0x57b6), 0x00 }, ++ { CCI_REG8(0x57b7), 0x00 }, { CCI_REG8(0x57b9), 0x70 }, ++ { CCI_REG8(0x57bb), 0x10 }, { CCI_REG8(0x57bc), 0x00 }, ++ { CCI_REG8(0x57bd), 0x00 }, { CCI_REG8(0x0305), 0x98 }, ++ { CCI_REG8(0x0306), 0x04 }, { CCI_REG8(0x0307), 0x01 }, ++ { CCI_REG8(0x4837), 0x1a }, { CCI_REG8(0x4888), 0x10 }, ++ { CCI_REG8(0x4860), 0x00 }, { CCI_REG8(0x4850), 0x43 }, ++ { CCI_REG8(0x480C), 0x92 } ++}; ++ ++/* 456MHz MIPI link frequency with 24MHz input clock. */ ++static const struct cci_reg_sequence ov64a40_pll_config = { ++ { OV64A40_PLL1_PRE_DIV0, 0x88 }, ++ { OV64A40_PLL1_PRE_DIV, 0x02 }, ++ { OV64A40_PLL1_MULTIPLIER, 0x0098 }, ++ { OV64A40_PLL1_M_DIV, 0x01 }, ++ { OV64A40_PLL2_SEL_BAK_SA1, 0x00 }, ++ { OV64A40_PLL2_PRE_DIV, 0x12 }, ++ { OV64A40_PLL2_MULTIPLIER, 0x0190 }, ++ { OV64A40_PLL2_PRE_DIV0, 0xd7 }, ++ { OV64A40_PLL2_DIVSP, 0x00 }, ++ { OV64A40_PLL2_DIVDAC, 0x00 }, ++ { OV64A40_PLL2_DACPREDIV, 0x00 } ++}; ++ ++struct ov64a40_reglist { ++ unsigned int num_regs; ++ const struct cci_reg_sequence *regvals; ++}; ++ ++struct ov64a40_subsampling { ++ unsigned int x_odd_inc; ++ unsigned int x_even_inc; ++ unsigned int y_odd_inc; ++ unsigned int y_even_inc; ++ bool vbin; ++ bool hbin; +}; + -+static const struct ov9281_mode supported_modes = { ++static struct ov64a40_mode { ++ unsigned int width; ++ unsigned int height; ++ struct ov64a40_timings { ++ unsigned int vts; ++ unsigned int ppl; ++ } timings_defaultOV64A40_NUM_LINK_FREQ; ++ const struct ov64a40_reglist reglist; ++ struct v4l2_rect analogue_crop; ++ struct v4l2_rect digital_crop; ++ struct ov64a40_subsampling subsampling; ++} ov64a40_modes = { ++ /* Full resolution */ + { -+ .width = 1280, -+ .height = 800, -+ .exp_def = 0x0320, -+ .hts_def = 0x05b0, /* 0x2d8*2 */ -+ .vts_def = 0x038e, -+ .crop = { ++ .width = 9248, ++ .height = 6944, ++ .timings_default = { ++ /* 2.6 FPS */ ++ OV64A40_LINK_FREQ_456M_ID = { ++ .vts = 7072, ++ .ppl = 4072, ++ }, ++ /* 2 FPS */ ++ OV64A40_LINK_FREQ_360M_ID = { ++ .vts = 7072, ++ .ppl = 5248, ++ }, ++ }, ++ .reglist = { ++ .num_regs = ARRAY_SIZE(ov64a40_9248x6944), ++ .regvals = ov64a40_9248x6944, ++ }, ++ .analogue_crop = { + .left = 0, + .top = 0, -+ .width = 1280, -+ .height = 800 ++ .width = 9280, ++ .height = 6976, ++ }, ++ .digital_crop = { ++ .left = 17, ++ .top = 16, ++ .width = 9248, ++ .height = 6944, ++ }, ++ .subsampling = { ++ .x_odd_inc = 1, ++ .x_even_inc = 1, ++ .y_odd_inc = 1, ++ .y_even_inc = 1, ++ .vbin = false, ++ .hbin = false, + }, -+ .reg_list = ov9281_1280x800_regs, + }, ++ /* Analogue crop + digital crop */ + { -+ .width = 1280, -+ .height = 720, -+ .exp_def = 0x0320, -+ .hts_def = 0x05b0, -+ .vts_def = 761, -+ .crop = { ++ .width = 8000, ++ .height = 6000, ++ .timings_default = { ++ /* 3.0 FPS */ ++ OV64A40_LINK_FREQ_456M_ID = { ++ .vts = 6400, ++ .ppl = 3848, ++ }, ++ /* 2.5 FPS */ ++ OV64A40_LINK_FREQ_360M_ID = { ++ .vts = 6304, ++ .ppl = 4736, ++ }, ++ }, ++ .reglist = { ++ .num_regs = ARRAY_SIZE(ov64a40_8000x6000), ++ .regvals = ov64a40_8000x6000, ++ }, ++ .analogue_crop = { ++ .left = 624, ++ .top = 472, ++ .width = 8048, ++ .height = 6032, ++ }, ++ .digital_crop = { ++ .left = 17, ++ .top = 16, ++ .width = 8000, ++ .height = 6000, ++ }, ++ .subsampling = { ++ .x_odd_inc = 1, ++ .x_even_inc = 1, ++ .y_odd_inc = 1, ++ .y_even_inc = 1, ++ .vbin = false, ++ .hbin = false, ++ }, ++ }, ++ /* 2x2 downscaled */ ++ { ++ .width = 4624, ++ .height = 3472, ++ .timings_default = { ++ /* 10 FPS */ ++ OV64A40_LINK_FREQ_456M_ID = { ++ .vts = 3533, ++ .ppl = 2112, ++ }, ++ /* 7 FPS */ ++ OV64A40_LINK_FREQ_360M_ID = { ++ .vts = 3939, ++ .ppl = 2720, ++ }, ++ }, ++ .reglist = { ++ .num_regs = ARRAY_SIZE(ov64a40_4624_3472), ++ .regvals = ov64a40_4624_3472, ++ }, ++ .analogue_crop = { + .left = 0, -+ .top = 40, -+ .width = 1280, -+ .height = 720 ++ .top = 0, ++ .width = 9280, ++ .height = 6976, ++ }, ++ .digital_crop = { ++ .left = 9, ++ .top = 8, ++ .width = 4624, ++ .height = 3472, ++ }, ++ .subsampling = { ++ .x_odd_inc = 3, ++ .x_even_inc = 1, ++ .y_odd_inc = 1, ++ .y_even_inc = 1, ++ .vbin = true, ++ .hbin = false, + }, -+ .reg_list = ov9281_1280x720_regs, + }, ++ /* Analogue crop + 2x2 downscale + digital crop */ + { -+ .width = 640, -+ .height = 400, -+ .exp_def = 0x0320, -+ .hts_def = 0x05b0, -+ .vts_def = 421, -+ .crop = { ++ .width = 3840, ++ .height = 2160, ++ .timings_default = { ++ /* 20 FPS */ ++ OV64A40_LINK_FREQ_456M_ID = { ++ .vts = 2218, ++ .ppl = 1690, ++ }, ++ /* 15 FPS */ ++ OV64A40_LINK_FREQ_360M_ID = { ++ .vts = 2270, ++ .ppl = 2202, ++ }, ++ }, ++ .reglist = { ++ .num_regs = ARRAY_SIZE(ov64a40_3840x2160), ++ .regvals = ov64a40_3840x2160, ++ }, ++ .analogue_crop = { ++ .left = 784, ++ .top = 1312, ++ .width = 7712, ++ .height = 4352, ++ }, ++ .digital_crop = { ++ .left = 9, ++ .top = 8, ++ .width = 3840, ++ .height = 2160, ++ }, ++ .subsampling = { ++ .x_odd_inc = 3, ++ .x_even_inc = 1, ++ .y_odd_inc = 1, ++ .y_even_inc = 1, ++ .vbin = true, ++ .hbin = false, ++ }, ++ }, ++ /* 4x4 downscaled */ ++ { ++ .width = 2312, ++ .height = 1736, ++ .timings_default = { ++ /* 30 FPS */ ++ OV64A40_LINK_FREQ_456M_ID = { ++ .vts = 1998, ++ .ppl = 1248, ++ }, ++ /* 25 FPS */ ++ OV64A40_LINK_FREQ_360M_ID = { ++ .vts = 1994, ++ .ppl = 1504, ++ }, ++ }, ++ .reglist = { ++ .num_regs = ARRAY_SIZE(ov64a40_2312_1736), ++ .regvals = ov64a40_2312_1736, ++ }, ++ .analogue_crop = { + .left = 0, + .top = 0, -+ .width = 1280, -+ .height = 800 ++ .width = 9280, ++ .height = 6976, ++ }, ++ .digital_crop = { ++ .left = 5, ++ .top = 4, ++ .width = 2312, ++ .height = 1736, ++ }, ++ .subsampling = { ++ .x_odd_inc = 3, ++ .x_even_inc = 1, ++ .y_odd_inc = 3, ++ .y_even_inc = 1, ++ .vbin = true, ++ .hbin = true, ++ }, ++ }, ++ /* Analogue crop + 4x4 downscale + digital crop */ ++ { ++ .width = 1920, ++ .height = 1080, ++ .timings_default = { ++ /* 60 FPS */ ++ OV64A40_LINK_FREQ_456M_ID = { ++ .vts = 1397, ++ .ppl = 880, ++ }, ++ /* 45 FPS */ ++ OV64A40_LINK_FREQ_360M_ID = { ++ .vts = 1216, ++ .ppl = 1360, ++ }, ++ }, ++ .reglist = { ++ .num_regs = ARRAY_SIZE(ov64a40_1920x1080), ++ .regvals = ov64a40_1920x1080, ++ }, ++ .analogue_crop = { ++ .left = 784, ++ .top = 1312, ++ .width = 7712, ++ .height = 4352, ++ }, ++ .digital_crop = { ++ .left = 7, ++ .top = 6, ++ .width = 1920, ++ .height = 1080, ++ }, ++ .subsampling = { ++ .x_odd_inc = 3, ++ .x_even_inc = 1, ++ .y_odd_inc = 3, ++ .y_even_inc = 1, ++ .vbin = true, ++ .hbin = true, + }, -+ .reg_list = ov9281_640x400_regs, + }, +}; + -+static const s64 link_freq_menu_items = { -+ OV9281_LINK_FREQ_400MHZ -+}; ++struct ov64a40 { ++ struct device *dev; + -+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" -+}; ++ struct v4l2_subdev sd; ++ struct media_pad pad; + -+/* 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 buf6; -+ u8 *val_p; -+ __be32 val_be; ++ struct regmap *cci; + -+ if (len > 4) -+ return -EINVAL; ++ struct ov64a40_mode *mode; + -+ buf0 = reg >> 8; -+ buf1 = reg & 0xff; ++ struct clk *xclk; + -+ val_be = cpu_to_be32(val); -+ val_p = (u8 *)&val_be; -+ buf_i = 2; -+ val_i = 4 - len; ++ struct gpio_desc *reset_gpio; ++ struct regulator_bulk_data suppliesARRAY_SIZE(ov64a40_supply_names); + -+ while (val_i < 4) -+ bufbuf_i++ = val_pval_i++; ++ s64 *link_frequencies; ++ unsigned int num_link_frequencies; + -+ if (i2c_master_send(client, buf, len + 2) != len + 2) -+ return -EIO; ++ struct v4l2_ctrl_handler ctrl_handler; ++ struct v4l2_ctrl *exposure; ++ struct v4l2_ctrl *link_freq; ++ struct v4l2_ctrl *vblank; ++ struct v4l2_ctrl *hblank; ++ struct v4l2_ctrl *vflip; ++ struct v4l2_ctrl *hflip; ++}; + -+ return 0; ++static inline struct ov64a40 *sd_to_ov64a40(struct v4l2_subdev *sd) ++{ ++ return container_of_const(sd, struct ov64a40, sd); +} + -+static int ov9281_write_array(struct i2c_client *client, -+ const struct regval *regs) ++static const struct ov64a40_timings * ++ov64a40_get_timings(struct ov64a40 *ov64a40, unsigned int link_freq_index) +{ -+ u32 i; -+ int ret = 0; -+ -+ for (i = 0; ret == 0 && regsi.addr != REG_NULL; i++) -+ ret = ov9281_write_reg(client, regsi.addr, -+ OV9281_REG_VALUE_08BIT, regsi.val); ++ s64 link_freq = ov64a40->link_frequencieslink_freq_index; ++ unsigned int timings_index = link_freq == OV64A40_LINK_FREQ_360M ++ ? OV64A40_LINK_FREQ_360M_ID ++ : OV64A40_LINK_FREQ_456M_ID; + -+ return ret; ++ return &ov64a40->mode->timings_defaulttimings_index; +} + -+/* Read registers up to 4 at a time */ -+static int ov9281_read_reg(struct i2c_client *client, u16 reg, unsigned int len, -+ u32 *val) ++static int ov64a40_program_geometry(struct ov64a40 *ov64a40) +{ -+ struct i2c_msg msgs2; -+ 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 */ -+ msgs0.addr = client->addr; -+ msgs0.flags = 0; -+ msgs0.len = 2; -+ msgs0.buf = (u8 *)®_addr_be; -+ -+ /* Read data from register */ -+ msgs1.addr = client->addr; -+ msgs1.flags = I2C_M_RD; -+ msgs1.len = len; -+ msgs1.buf = &data_be_p4 - len; -+ -+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); -+ if (ret != ARRAY_SIZE(msgs)) -+ return -EIO; ++ struct ov64a40_mode *mode = ov64a40->mode; ++ struct v4l2_rect *anacrop = &mode->analogue_crop; ++ struct v4l2_rect *digicrop = &mode->digital_crop; ++ const struct ov64a40_timings *timings; ++ int ret = 0; + -+ *val = be32_to_cpu(data_be); ++ /* Analogue crop. */ ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL0, ++ anacrop->left, &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL2, ++ anacrop->top, &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL4, ++ anacrop->width + anacrop->left - 1, &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL6, ++ anacrop->height + anacrop->top - 1, &ret); ++ ++ /* ISP windowing. */ ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL10, ++ digicrop->left, &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL12, ++ digicrop->top, &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL8, ++ digicrop->width, &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRLA, ++ digicrop->height, &ret); ++ ++ /* Total timings. */ ++ timings = ov64a40_get_timings(ov64a40, ov64a40->link_freq->cur.val); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRLC, timings->ppl, &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRLE, timings->vts, &ret); + -+ return 0; ++ return ret; +} + -+static int ov9281_get_reso_dist(const struct ov9281_mode *mode, -+ struct v4l2_mbus_framefmt *framefmt) ++static int ov64a40_program_subsampling(struct ov64a40 *ov64a40) +{ -+ return abs(mode->width - framefmt->width) + -+ abs(mode->height - framefmt->height); -+} ++ struct ov64a40_subsampling *subsampling = &ov64a40->mode->subsampling; ++ int ret = 0; + -+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; ++ /* Skipping configuration */ ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL14, ++ OV64A40_SKIPPING_CONFIG(subsampling->x_odd_inc, ++ subsampling->x_even_inc), &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL15, ++ OV64A40_SKIPPING_CONFIG(subsampling->y_odd_inc, ++ subsampling->y_even_inc), &ret); + -+ for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { -+ dist = ov9281_get_reso_dist(&supported_modesi, framefmt); -+ if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { -+ cur_best_fit_dist = dist; -+ cur_best_fit = i; -+ } -+ } ++ /* Binning configuration */ ++ cci_update_bits(ov64a40->cci, OV64A40_REG_TIMING_CTRL_20, ++ OV64A40_TIMING_CTRL_20_VBIN, ++ subsampling->vbin ? OV64A40_TIMING_CTRL_20_VBIN : 0, ++ &ret); ++ cci_update_bits(ov64a40->cci, OV64A40_REG_TIMING_CTRL_21, ++ OV64A40_TIMING_CTRL_21_HBIN_CONF, ++ subsampling->hbin ? ++ OV64A40_TIMING_CTRL_21_HBIN_CONF : 0, &ret); + -+ return &supported_modescur_best_fit; ++ return ret; +} + -+static int ov9281_set_fmt(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_format *fmt) ++static int ov64a40_start_streaming(struct ov64a40 *ov64a40, ++ struct v4l2_subdev_state *state) +{ -+ struct ov9281 *ov9281 = to_ov9281(sd); -+ const struct ov9281_mode *mode; -+ s64 h_blank, vblank_def, pixel_rate; ++ const struct ov64a40_reglist *reglist = &ov64a40->mode->reglist; ++ const struct ov64a40_timings *timings; ++ unsigned long delay; ++ int ret; + -+ mutex_lock(&ov9281->mutex); ++ ret = pm_runtime_resume_and_get(ov64a40->dev); ++ if (ret < 0) ++ return ret; + -+ 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_RAW; -+ 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); ++ ret = cci_multi_reg_write(ov64a40->cci, ov64a40_init, ++ ARRAY_SIZE(ov64a40_init), NULL); ++ if (ret) ++ goto error_power_off; + -+ 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); ++ ret = cci_multi_reg_write(ov64a40->cci, reglist->regvals, ++ reglist->num_regs, NULL); ++ if (ret) ++ goto error_power_off; + -+ 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); -+ } ++ ret = ov64a40_program_geometry(ov64a40); ++ if (ret) ++ goto error_power_off; + -+ mutex_unlock(&ov9281->mutex); ++ ret = ov64a40_program_subsampling(ov64a40); ++ if (ret) ++ goto error_power_off; + -+ return 0; -+} ++ ret = __v4l2_ctrl_handler_setup(&ov64a40->ctrl_handler); ++ if (ret) ++ goto error_power_off; + -+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; ++ ret = cci_write(ov64a40->cci, OV64A40_REG_SMIA, ++ OV64A40_REG_SMIA_STREAMING, NULL); ++ if (ret) ++ goto error_power_off; + -+ 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_RAW; -+ 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); ++ /* Link frequency and flips cannot change while streaming. */ ++ __v4l2_ctrl_grab(ov64a40->link_freq, true); ++ __v4l2_ctrl_grab(ov64a40->vflip, true); ++ __v4l2_ctrl_grab(ov64a40->hflip, true); ++ ++ /* delay: max(4096 xclk pulses, 150usec) + exposure time */ ++ timings = ov64a40_get_timings(ov64a40, ov64a40->link_freq->cur.val); ++ delay = DIV_ROUND_UP(4096, OV64A40_XCLK_FREQ / 1000 / 1000); ++ delay = max(delay, 150ul); ++ ++ /* The sensor has an internal x4 multiplier on the line length. */ ++ delay += DIV_ROUND_UP(timings->ppl * 4 * ov64a40->exposure->cur.val, ++ OV64A40_PIXEL_RATE / 1000 / 1000); ++ fsleep(delay); + + return 0; -+} + -+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; -+ } ++error_power_off: ++ pm_runtime_mark_last_busy(ov64a40->dev); ++ pm_runtime_put_autosuspend(ov64a40->dev); + -+ return 0; ++ return ret; +} + -+static int ov9281_enum_frame_sizes(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_frame_size_enum *fse) ++static int ov64a40_stop_streaming(struct ov64a40 *ov64a40, ++ struct v4l2_subdev_state *state) +{ -+ 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; ++ cci_update_bits(ov64a40->cci, OV64A40_REG_SMIA, BIT(0), 0, NULL); ++ pm_runtime_mark_last_busy(ov64a40->dev); ++ pm_runtime_put_autosuspend(ov64a40->dev); + -+ fse->min_width = supported_modesfse->index.width; -+ fse->max_width = supported_modesfse->index.width; -+ fse->max_height = supported_modesfse->index.height; -+ fse->min_height = supported_modesfse->index.height; ++ __v4l2_ctrl_grab(ov64a40->link_freq, false); ++ __v4l2_ctrl_grab(ov64a40->vflip, false); ++ __v4l2_ctrl_grab(ov64a40->hflip, false); + + return 0; +} + -+static int ov9281_enable_test_pattern(struct ov9281 *ov9281, u32 pattern) ++static int ov64a40_set_stream(struct v4l2_subdev *sd, int enable) +{ -+ u32 val; ++ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd); ++ struct v4l2_subdev_state *state; ++ int ret; + -+ if (pattern) -+ val = (pattern - 1) | OV9281_TEST_PATTERN_ENABLE; ++ state = v4l2_subdev_lock_and_get_active_state(sd); ++ if (enable) ++ ret = ov64a40_start_streaming(ov64a40, state); + else -+ val = OV9281_TEST_PATTERN_DISABLE; -+ -+ return ov9281_write_reg(ov9281->client, OV9281_REG_TEST_PATTERN, -+ OV9281_REG_VALUE_08BIT, val); -+} ++ ret = ov64a40_stop_streaming(ov64a40, state); ++ v4l2_subdev_unlock_state(state); + -+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_subdev_video_ops ov64a40_video_ops = { ++ .s_stream = ov64a40_set_stream, ++}; + -+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) ++static u32 ov64a40_mbus_code(struct ov64a40 *ov64a40) +{ -+ 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; -+ } ++ unsigned int index = ov64a40->hflip->val << 1 | ov64a40->vflip->val; + -+ return NULL; ++ return ov64a40_mbus_codesindex; +} + -+static int ov9281_get_selection(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_selection *sel) ++static void ov64a40_update_pad_fmt(struct ov64a40 *ov64a40, ++ struct ov64a40_mode *mode, ++ struct v4l2_mbus_framefmt *fmt) +{ -+ 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; ++ fmt->code = ov64a40_mbus_code(ov64a40); ++ fmt->width = mode->width; ++ fmt->height = mode->height; ++ fmt->field = V4L2_FIELD_NONE; ++ fmt->colorspace = V4L2_COLORSPACE_RAW; ++ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; ++ fmt->xfer_func = V4L2_XFER_FUNC_NONE; ++ fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; +} + -+static int __ov9281_start_stream(struct ov9281 *ov9281) ++static int ov64a40_init_cfg(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state) +{ -+ 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; ++ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd); ++ struct v4l2_mbus_framefmt *format; ++ struct v4l2_rect *crop; + -+ /* 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; ++ format = v4l2_subdev_get_pad_format(sd, state, 0); ++ ov64a40_update_pad_fmt(ov64a40, &ov64a40_modes0, format); + -+ return ov9281_write_reg(ov9281->client, OV9281_REG_CTRL_MODE, -+ OV9281_REG_VALUE_08BIT, OV9281_MODE_STREAMING); -+} ++ crop = v4l2_subdev_get_pad_crop(sd, state, 0); ++ crop->top = OV64A40_PIXEL_ARRAY_TOP; ++ crop->left = OV64A40_PIXEL_ARRAY_LEFT; ++ crop->width = OV64A40_PIXEL_ARRAY_WIDTH; ++ crop->height = OV64A40_PIXEL_ARRAY_HEIGHT; + -+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); ++ return 0; +} + -+static int ov9281_s_stream(struct v4l2_subdev *sd, int on) ++static int ov64a40_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_mbus_code_enum *code) +{ -+ struct ov9281 *ov9281 = to_ov9281(sd); -+ struct i2c_client *client = ov9281->client; -+ int ret = 0; ++ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd); + -+ mutex_lock(&ov9281->mutex); -+ on = !!on; -+ if (on == ov9281->streaming) -+ goto unlock_and_return; ++ if (code->index) ++ return -EINVAL; + -+ if (on) { -+ ret = pm_runtime_get_sync(&client->dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(&client->dev); -+ goto unlock_and_return; -+ } ++ code->code = ov64a40_mbus_code(ov64a40); + -+ 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); -+ } ++ return 0; ++} + -+ ov9281->streaming = on; ++static int ov64a40_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd); ++ struct ov64a40_mode *mode; ++ u32 code; + -+unlock_and_return: -+ mutex_unlock(&ov9281->mutex); ++ if (fse->index >= ARRAY_SIZE(ov64a40_modes)) ++ return -EINVAL; + -+ return ret; ++ code = ov64a40_mbus_code(ov64a40); ++ if (fse->code != code) ++ return -EINVAL; ++ ++ mode = &ov64a40_modesfse->index; ++ fse->min_width = mode->width; ++ fse->max_width = mode->width; ++ fse->min_height = mode->height; ++ fse->max_height = mode->height; ++ ++ return 0; +} + -+static int ov9281_s_power(struct v4l2_subdev *sd, int on) ++static int ov64a40_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_selection *sel) +{ -+ struct ov9281 *ov9281 = to_ov9281(sd); -+ struct i2c_client *client = ov9281->client; -+ int ret = 0; ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP: ++ sel->r = *v4l2_subdev_get_pad_crop(sd, state, 0); + -+ mutex_lock(&ov9281->mutex); ++ return 0; + -+ /* If the power state is not modified - no work to do. */ -+ if (ov9281->power_on == !!on) -+ goto unlock_and_return; ++ case V4L2_SEL_TGT_NATIVE_SIZE: ++ sel->r.top = 0; ++ sel->r.left = 0; ++ sel->r.width = OV64A40_NATIVE_WIDTH; ++ sel->r.height = OV64A40_NATIVE_HEIGHT; + -+ 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; -+ } ++ return 0; + -+unlock_and_return: -+ mutex_unlock(&ov9281->mutex); ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.top = OV64A40_PIXEL_ARRAY_TOP; ++ sel->r.left = OV64A40_PIXEL_ARRAY_LEFT; ++ sel->r.width = OV64A40_PIXEL_ARRAY_WIDTH; ++ sel->r.height = OV64A40_PIXEL_ARRAY_HEIGHT; + -+ return ret; -+} ++ return 0; ++ } + -+/* 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); ++ return -EINVAL; +} + -+static int __ov9281_power_on(struct ov9281 *ov9281) ++static int ov64a40_set_format(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_format *fmt) +{ -+ int ret; -+ u32 delay_us; -+ struct device *dev = &ov9281->client->dev; ++ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd); ++ struct v4l2_mbus_framefmt *format; ++ struct ov64a40_mode *mode; + -+ 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)); ++ mode = v4l2_find_nearest_size(ov64a40_modes, ++ ARRAY_SIZE(ov64a40_modes), ++ width, height, ++ fmt->format.width, fmt->format.height); + -+ ret = clk_prepare_enable(ov9281->xvclk); -+ if (ret < 0) { -+ dev_err(dev, "Failed to enable xvclk\n"); -+ return ret; -+ } ++ ov64a40_update_pad_fmt(ov64a40, mode, &fmt->format); + -+ if (!IS_ERR(ov9281->reset_gpio)) -+ gpiod_set_value_cansleep(ov9281->reset_gpio, 0); ++ format = v4l2_subdev_get_pad_format(sd, state, 0); ++ if (ov64a40->mode == mode && format->code == fmt->format.code) ++ return 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 (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { ++ const struct ov64a40_timings *timings; ++ int vblank_max, vblank_def; ++ int hblank_val; ++ int exp_max; + -+ if (!IS_ERR(ov9281->reset_gpio)) -+ gpiod_set_value_cansleep(ov9281->reset_gpio, 1); ++ ov64a40->mode = mode; ++ *v4l2_subdev_get_pad_crop(sd, state, 0) = mode->analogue_crop; + -+ usleep_range(500, 1000); -+ if (!IS_ERR(ov9281->pwdn_gpio)) -+ gpiod_set_value_cansleep(ov9281->pwdn_gpio, 1); ++ /* Update control limits according to the new mode. */ ++ timings = ov64a40_get_timings(ov64a40, ++ ov64a40->link_freq->cur.val); ++ vblank_max = OV64A40_VTS_MAX - mode->height; ++ vblank_def = timings->vts - mode->height; ++ __v4l2_ctrl_modify_range(ov64a40->vblank, OV64A40_VBLANK_MIN, ++ vblank_max, 1, vblank_def); ++ __v4l2_ctrl_s_ctrl(ov64a40->vblank, vblank_def); + -+ /* 8192 cycles prior to first SCCB transaction */ -+ delay_us = ov9281_cal_delay(8192); -+ usleep_range(delay_us, delay_us * 2); ++ exp_max = timings->vts - OV64A40_EXPOSURE_MARGIN; ++ __v4l2_ctrl_modify_range(ov64a40->exposure, ++ OV64A40_EXPOSURE_MIN, exp_max, ++ 1, OV64A40_EXPOSURE_MIN); + -+ return 0; ++ hblank_val = timings->ppl * 4 - mode->width; ++ __v4l2_ctrl_modify_range(ov64a40->hblank, ++ hblank_val, hblank_val, 1, hblank_val); ++ } + -+disable_clk: -+ clk_disable_unprepare(ov9281->xvclk); ++ *format = fmt->format; + -+ return ret; ++ return 0; +} + -+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 const struct v4l2_subdev_pad_ops ov64a40_pad_ops = { ++ .init_cfg = ov64a40_init_cfg, ++ .enum_mbus_code = ov64a40_enum_mbus_code, ++ .enum_frame_size = ov64a40_enum_frame_size, ++ .get_fmt = v4l2_subdev_get_fmt, ++ .set_fmt = ov64a40_set_format, ++ .get_selection = ov64a40_get_selection, ++}; + -+static 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); ++static const struct v4l2_subdev_core_ops ov64a40_core_ops = { ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++}; + -+ return __ov9281_power_on(ov9281); -+} ++static const struct v4l2_subdev_ops ov64a40_subdev_ops = { ++ .core = &ov64a40_core_ops, ++ .video = &ov64a40_video_ops, ++ .pad = &ov64a40_pad_ops, ++}; + -+static int ov9281_runtime_suspend(struct device *dev) ++static int ov64a40_power_on(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); ++ struct v4l2_subdev *sd = dev_get_drvdata(dev); ++ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd); ++ int ret; ++ ++ ret = clk_prepare_enable(ov64a40->xclk); ++ if (ret) ++ return ret; ++ ++ ret = regulator_bulk_enable(ARRAY_SIZE(ov64a40_supply_names), ++ ov64a40->supplies); ++ if (ret) { ++ clk_disable_unprepare(ov64a40->xclk); ++ dev_err(dev, "Failed to enable regulators: %d\n", ret); ++ return ret; ++ } ++ ++ gpiod_set_value_cansleep(ov64a40->reset_gpio, 0); + -+ __ov9281_power_off(ov9281); ++ fsleep(5000); + + return 0; +} + -+static int ov9281_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) ++static int ov64a40_power_off(struct device *dev) +{ -+ 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_modes0; -+ -+ 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_RAW; -+ 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); ++ struct v4l2_subdev *sd = dev_get_drvdata(dev); ++ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd); + -+ mutex_unlock(&ov9281->mutex); -+ /* No crop or compose */ ++ gpiod_set_value_cansleep(ov64a40->reset_gpio, 1); ++ regulator_bulk_disable(ARRAY_SIZE(ov64a40_supply_names), ++ ov64a40->supplies); ++ clk_disable_unprepare(ov64a40->xclk); + + return 0; +} + -+static 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 int ov64a40_link_freq_config(struct ov64a40 *ov64a40, int link_freq_id) ++{ ++ s64 link_frequency; ++ int ret = 0; + -+static const struct v4l2_subdev_video_ops ov9281_video_ops = { -+ .s_stream = ov9281_s_stream, -+}; ++ /* Default 456MHz with 24MHz input clock. */ ++ cci_multi_reg_write(ov64a40->cci, ov64a40_pll_config, ++ ARRAY_SIZE(ov64a40_pll_config), &ret); + -+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, -+}; ++ /* Decrease the PLL1 multiplier to obtain 360MHz mipi link frequency. */ ++ link_frequency = ov64a40->link_frequencieslink_freq_id; ++ if (link_frequency == OV64A40_LINK_FREQ_360M) ++ cci_write(ov64a40->cci, OV64A40_PLL1_MULTIPLIER, 0x0078, &ret); + -+static const struct v4l2_subdev_ops ov9281_subdev_ops = { -+ .core = &ov9281_core_ops, -+ .video = &ov9281_video_ops, -+ .pad = &ov9281_pad_ops, -+}; ++ return ret; ++} + -+static int ov9281_set_ctrl(struct v4l2_ctrl *ctrl) ++static int ov64a40_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; ++ struct ov64a40 *ov64a40 = container_of(ctrl->handler, struct ov64a40, ++ ctrl_handler); ++ int pm_status; + 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 - OV9281_EXPOSURE_OFFSET; -+ __v4l2_ctrl_modify_range(ov9281->exposure, -+ ov9281->exposure->minimum, max, -+ ov9281->exposure->step, -+ ov9281->exposure->default_value); -+ break; ++ if (ctrl->id == V4L2_CID_VBLANK) { ++ int exp_max = ov64a40->mode->height + ctrl->val ++ - OV64A40_EXPOSURE_MARGIN; ++ int exp_val = min(ov64a40->exposure->cur.val, exp_max); ++ ++ __v4l2_ctrl_modify_range(ov64a40->exposure, ++ ov64a40->exposure->minimum, ++ exp_max, 1, exp_val); + } + -+ if (pm_runtime_get(&client->dev) <= 0) ++ pm_status = pm_runtime_get_if_active(ov64a40->dev, true); ++ if (!pm_status) + 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); ++ ret = cci_write(ov64a40->cci, OV64A40_REG_MEC_LONG_EXPO, ++ ctrl->val, NULL); + 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); ++ ret = cci_write(ov64a40->cci, OV64A40_REG_MEC_LONG_GAIN, ++ ctrl->val << 1, NULL); + break; -+ case V4L2_CID_VBLANK: -+ ret = ov9281_write_reg(ov9281->client, OV9281_REG_VTS, -+ OV9281_REG_VALUE_16BIT, -+ ctrl->val + ov9281->cur_mode->height); ++ case V4L2_CID_VBLANK: { ++ int vts = ctrl->val + ov64a40->mode->height; ++ ++ cci_write(ov64a40->cci, OV64A40_REG_TIMINGS_VTS_LOW, vts, &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMINGS_VTS_MID, ++ (vts >> 8), &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMINGS_VTS_HIGH, ++ (vts >> 16), &ret); ++ break; ++ } ++ case V4L2_CID_VFLIP: ++ ret = cci_update_bits(ov64a40->cci, OV64A40_REG_TIMING_CTRL_20, ++ OV64A40_TIMING_CTRL_20_VFLIP, ++ ctrl->val << 2, ++ NULL); ++ break; ++ case V4L2_CID_HFLIP: ++ ret = cci_update_bits(ov64a40->cci, OV64A40_REG_TIMING_CTRL_21, ++ OV64A40_TIMING_CTRL_21_HFLIP, ++ ctrl->val ? 0 ++ : OV64A40_TIMING_CTRL_21_HFLIP, ++ NULL); + break; + case V4L2_CID_TEST_PATTERN: -+ ret = ov9281_enable_test_pattern(ov9281, ctrl->val); ++ ret = cci_write(ov64a40->cci, OV64A40_REG_TEST_PATTERN, ++ ov64a40_test_pattern_valctrl->val, NULL); ++ break; ++ case V4L2_CID_LINK_FREQ: ++ ret = ov64a40_link_freq_config(ov64a40, ctrl->val); + break; + default: -+ dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", -+ __func__, ctrl->id, ctrl->val); ++ dev_err(ov64a40->dev, "Unhandled control: %#x\n", ctrl->id); ++ ret = -EINVAL; + break; + } + -+ pm_runtime_put(&client->dev); ++ if (pm_status > 0) { ++ pm_runtime_mark_last_busy(ov64a40->dev); ++ pm_runtime_put_autosuspend(ov64a40->dev); ++ } + + return ret; +} + -+static const struct v4l2_ctrl_ops ov9281_ctrl_ops = { -+ .s_ctrl = ov9281_set_ctrl, ++static const struct v4l2_ctrl_ops ov64a40_ctrl_ops = { ++ .s_ctrl = ov64a40_set_ctrl, +}; + -+static int ov9281_initialize_controls(struct ov9281 *ov9281) ++static int ov64a40_init_controls(struct ov64a40 *ov64a40) +{ ++ int exp_max, hblank_val, vblank_max, vblank_def; ++ struct v4l2_ctrl_handler *hdlr = &ov64a40->ctrl_handler; + struct v4l2_fwnode_device_properties props; -+ const struct ov9281_mode *mode; -+ struct v4l2_ctrl_handler *handler; -+ struct v4l2_ctrl *ctrl; -+ s64 exposure_max, vblank_def; -+ u32 h_blank; ++ const struct ov64a40_timings *timings; + int ret; + -+ handler = &ov9281->ctrl_handler; -+ mode = ov9281->cur_mode; -+ ret = v4l2_ctrl_handler_init(handler, 11); ++ ret = v4l2_ctrl_handler_init(hdlr, 11); + 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 - OV9281_EXPOSURE_OFFSET; -+ ov9281->exposure = v4l2_ctrl_new_std(handler, &ov9281_ctrl_ops, -+ V4L2_CID_EXPOSURE, -+ OV9281_EXPOSURE_MIN, exposure_max, -+ OV9281_EXPOSURE_STEP, -+ mode->exp_def); ++ v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops, V4L2_CID_PIXEL_RATE, ++ OV64A40_PIXEL_RATE, OV64A40_PIXEL_RATE, 1, ++ OV64A40_PIXEL_RATE); ++ ++ ov64a40->link_freq = ++ v4l2_ctrl_new_int_menu(hdlr, &ov64a40_ctrl_ops, ++ V4L2_CID_LINK_FREQ, ++ ov64a40->num_link_frequencies - 1, ++ 0, ov64a40->link_frequencies); + -+ 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); ++ v4l2_ctrl_new_std_menu_items(hdlr, &ov64a40_ctrl_ops, ++ V4L2_CID_TEST_PATTERN, ++ ARRAY_SIZE(ov64a40_test_pattern_menu) - 1, ++ 0, 0, ov64a40_test_pattern_menu); + -+ if (handler->error) { -+ ret = handler->error; -+ dev_err(&ov9281->client->dev, -+ "Failed to init controls(%d)\n", ret); -+ goto err_free_handler; ++ timings = ov64a40_get_timings(ov64a40, 0); ++ exp_max = timings->vts - OV64A40_EXPOSURE_MARGIN; ++ ov64a40->exposure = v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops, ++ V4L2_CID_EXPOSURE, ++ OV64A40_EXPOSURE_MIN, exp_max, 1, ++ OV64A40_EXPOSURE_MIN); ++ ++ hblank_val = timings->ppl * 4 - ov64a40->mode->width; ++ ov64a40->hblank = v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops, ++ V4L2_CID_HBLANK, hblank_val, ++ hblank_val, 1, hblank_val); ++ if (ov64a40->hblank) ++ ov64a40->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ ++ vblank_def = timings->vts - ov64a40->mode->height; ++ vblank_max = OV64A40_VTS_MAX - ov64a40->mode->height; ++ ov64a40->vblank = v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops, ++ V4L2_CID_VBLANK, OV64A40_VBLANK_MIN, ++ vblank_max, 1, vblank_def); ++ ++ v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, ++ OV64A40_ANA_GAIN_MIN, OV64A40_ANA_GAIN_MAX, 1, ++ OV64A40_ANA_GAIN_DEFAULT); ++ ++ ov64a40->hflip = v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ if (ov64a40->hflip) ++ ov64a40->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ ov64a40->vflip = v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ if (ov64a40->vflip) ++ ov64a40->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ if (hdlr->error) { ++ ret = hdlr->error; ++ dev_err(ov64a40->dev, "control init failed: %d\n", ret); ++ goto error_free_hdlr; + } + -+ ret = v4l2_fwnode_device_parse(&ov9281->client->dev, &props); ++ ret = v4l2_fwnode_device_parse(ov64a40->dev, &props); + if (ret) -+ goto err_free_handler; ++ goto error_free_hdlr; + -+ ret = v4l2_ctrl_new_fwnode_properties(handler, &ov9281_ctrl_ops, ++ ret = v4l2_ctrl_new_fwnode_properties(hdlr, &ov64a40_ctrl_ops, + &props); + if (ret) -+ goto err_free_handler; ++ goto error_free_hdlr; + -+ ov9281->subdev.ctrl_handler = handler; ++ ov64a40->sd.ctrl_handler = hdlr; + + return 0; + -+err_free_handler: -+ v4l2_ctrl_handler_free(handler); -+ ++error_free_hdlr: ++ v4l2_ctrl_handler_free(hdlr); + return ret; +} + -+static int ov9281_check_sensor_id(struct ov9281 *ov9281, -+ struct i2c_client *client) ++static int ov64a40_identify(struct ov64a40 *ov64a40) +{ -+ struct device *dev = &ov9281->client->dev; -+ u32 id = 0, id_msb; + int ret; ++ u64 id; + -+ 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); ++ ret = cci_read(ov64a40->cci, OV64A40_REG_CHIP_ID, &id, NULL); ++ if (ret) { ++ dev_err(ov64a40->dev, "Failed to read chip id: %d\n", ret); ++ return ret; ++ } ++ ++ if (id != OV64A40_CHIP_ID) { ++ dev_err(ov64a40->dev, "chip id mismatch: %#llx\n", id); + return -ENODEV; + } + -+ dev_info(dev, "Detected OV%06x sensor\n", CHIP_ID); ++ dev_dbg(ov64a40->dev, "OV64A40 chip identified: %#llx\n", id); ++ ++ return 0; ++} ++ ++static int ov64a40_parse_dt(struct ov64a40 *ov64a40) ++{ ++ struct v4l2_fwnode_endpoint v4l2_fwnode = { ++ .bus_type = V4L2_MBUS_CSI2_DPHY ++ }; ++ struct fwnode_handle *endpoint; ++ unsigned int i; ++ int ret; ++ ++ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(ov64a40->dev), ++ NULL); ++ if (!endpoint) { ++ dev_err(ov64a40->dev, "Failed to find endpoint\n"); ++ return -EINVAL; ++ } ++ ++ ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &v4l2_fwnode); ++ fwnode_handle_put(endpoint); ++ if (ret) { ++ dev_err(ov64a40->dev, "Failed to parse endpoint\n"); ++ return ret; ++ } ++ ++ if (v4l2_fwnode.bus.mipi_csi2.num_data_lanes != 2) { ++ dev_err(ov64a40->dev, "Unsupported number of data lanes: %u\n", ++ v4l2_fwnode.bus.mipi_csi2.num_data_lanes); ++ v4l2_fwnode_endpoint_free(&v4l2_fwnode); ++ return -EINVAL; ++ } ++ ++ if (!v4l2_fwnode.nr_of_link_frequencies) { ++ dev_warn(ov64a40->dev, "no link frequencies defined\n"); ++ v4l2_fwnode_endpoint_free(&v4l2_fwnode); ++ return -EINVAL; ++ } ++ ++ if (v4l2_fwnode.nr_of_link_frequencies > 2) { ++ dev_warn(ov64a40->dev, ++ "Unsupported number of link frequencies\n"); ++ v4l2_fwnode_endpoint_free(&v4l2_fwnode); ++ return -EINVAL; ++ } ++ ++ ov64a40->link_frequencies = ++ devm_kcalloc(ov64a40->dev, v4l2_fwnode.nr_of_link_frequencies, ++ sizeof(v4l2_fwnode.link_frequencies0), ++ GFP_KERNEL); ++ if (!ov64a40->link_frequencies) { ++ v4l2_fwnode_endpoint_free(&v4l2_fwnode); ++ return -ENOMEM; ++ } ++ ov64a40->num_link_frequencies = v4l2_fwnode.nr_of_link_frequencies; ++ ++ for (i = 0; i < v4l2_fwnode.nr_of_link_frequencies; ++i) { ++ if (v4l2_fwnode.link_frequenciesi != OV64A40_LINK_FREQ_360M && ++ v4l2_fwnode.link_frequenciesi != OV64A40_LINK_FREQ_456M) { ++ dev_err(ov64a40->dev, ++ "Unsupported link frequency %lld\n", ++ v4l2_fwnode.link_frequenciesi); ++ v4l2_fwnode_endpoint_free(&v4l2_fwnode); ++ return -EINVAL; ++ } ++ ++ ov64a40->link_frequenciesi = v4l2_fwnode.link_frequenciesi; ++ } ++ ++ v4l2_fwnode_endpoint_free(&v4l2_fwnode); + + return 0; +} + -+static int ov9281_configure_regulators(struct ov9281 *ov9281) ++static int ov64a40_get_regulators(struct ov64a40 *ov64a40) +{ ++ struct i2c_client *client = v4l2_get_subdevdata(&ov64a40->sd); + unsigned int i; + -+ for (i = 0; i < OV9281_NUM_SUPPLIES; i++) -+ ov9281->suppliesi.supply = ov9281_supply_namesi; ++ for (i = 0; i < ARRAY_SIZE(ov64a40_supply_names); i++) ++ ov64a40->suppliesi.supply = ov64a40_supply_namesi; + -+ return devm_regulator_bulk_get(&ov9281->client->dev, -+ OV9281_NUM_SUPPLIES, -+ ov9281->supplies); ++ return devm_regulator_bulk_get(&client->dev, ++ ARRAY_SIZE(ov64a40_supply_names), ++ ov64a40->supplies); +} + -+static int ov9281_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) ++static int ov64a40_probe(struct i2c_client *client) +{ -+ struct device *dev = &client->dev; -+ struct ov9281 *ov9281; -+ struct v4l2_subdev *sd; ++ struct ov64a40 *ov64a40; ++ u32 xclk_freq; + int ret; + -+ ov9281 = devm_kzalloc(dev, sizeof(*ov9281), GFP_KERNEL); -+ if (!ov9281) ++ ov64a40 = devm_kzalloc(&client->dev, sizeof(*ov64a40), GFP_KERNEL); ++ if (!ov64a40) + return -ENOMEM; + -+ ov9281->client = client; -+ ov9281->cur_mode = &supported_modes0; ++ ov64a40->dev = &client->dev; ++ v4l2_i2c_subdev_init(&ov64a40->sd, client, &ov64a40_subdev_ops); + -+ ov9281->xvclk = devm_clk_get(dev, "xvclk"); -+ if (IS_ERR(ov9281->xvclk)) { -+ dev_err(dev, "Failed to get xvclk\n"); ++ ov64a40->cci = devm_cci_regmap_init_i2c(client, 16); ++ if (IS_ERR(ov64a40->cci)) { ++ dev_err(&client->dev, "Failed to initialize CCI\n"); ++ return PTR_ERR(ov64a40->cci); ++ } ++ ++ ov64a40->xclk = devm_clk_get(&client->dev, NULL); ++ if (IS_ERR(ov64a40->xclk)) ++ return dev_err_probe(&client->dev, PTR_ERR(ov64a40->xclk), ++ "Failed to get clock\n"); ++ ++ xclk_freq = clk_get_rate(ov64a40->xclk); ++ if (xclk_freq != OV64A40_XCLK_FREQ) { ++ dev_err(&client->dev, "Unsupported xclk frequency %u\n", ++ xclk_freq); + return -EINVAL; + } + -+ 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"); ++ ret = ov64a40_get_regulators(ov64a40); ++ if (ret) + return ret; -+ } + -+ mutex_init(&ov9281->mutex); ++ ov64a40->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(ov64a40->reset_gpio)) ++ return dev_err_probe(&client->dev, PTR_ERR(ov64a40->reset_gpio), ++ "Failed to get reset gpio\n"); + -+ sd = &ov9281->subdev; -+ v4l2_i2c_subdev_init(sd, client, &ov9281_subdev_ops); -+ ret = ov9281_initialize_controls(ov9281); ++ ret = ov64a40_parse_dt(ov64a40); + if (ret) -+ goto err_destroy_mutex; ++ return ret; + -+ ret = __ov9281_power_on(ov9281); ++ ret = ov64a40_power_on(&client->dev); + if (ret) -+ goto err_free_handler; ++ return ret; + -+ ret = ov9281_check_sensor_id(ov9281, client); ++ ret = ov64a40_identify(ov64a40); + if (ret) -+ goto err_power_off; ++ goto error_poweroff; + -+ sd->internal_ops = &ov9281_internal_ops; -+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ov64a40->mode = &ov64a40_modes0; + -+ 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; ++ pm_runtime_set_active(&client->dev); ++ pm_runtime_get_noresume(&client->dev); ++ pm_runtime_enable(&client->dev); ++ pm_runtime_set_autosuspend_delay(&client->dev, 1000); ++ pm_runtime_use_autosuspend(&client->dev); ++ ++ ret = ov64a40_init_controls(ov64a40); ++ if (ret) ++ goto error_poweroff; ++ ++ /* Initialize subdev */ ++ ov64a40->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE ++ | V4L2_SUBDEV_FL_HAS_EVENTS; ++ ov64a40->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + -+ ret = v4l2_async_register_subdev_sensor_common(sd); ++ ov64a40->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&ov64a40->sd.entity, 1, &ov64a40->pad); + if (ret) { -+ dev_err(dev, "v4l2 async register subdev failed\n"); -+ goto err_clean_entity; ++ dev_err(&client->dev, "failed to init entity pads: %d\n", ret); ++ goto error_handler_free; + } + -+ pm_runtime_set_active(dev); -+ pm_runtime_enable(dev); -+ pm_runtime_idle(dev); ++ ov64a40->sd.state_lock = ov64a40->ctrl_handler.lock; ++ ret = v4l2_subdev_init_finalize(&ov64a40->sd); ++ if (ret < 0) { ++ dev_err(&client->dev, "subdev init error: %d\n", ret); ++ goto error_media_entity; ++ } ++ ++ ret = v4l2_async_register_subdev_sensor(&ov64a40->sd); ++ if (ret < 0) { ++ dev_err(&client->dev, ++ "failed to register sensor sub-device: %d\n", ret); ++ goto error_subdev_cleanup; ++ } ++ ++ pm_runtime_mark_last_busy(&client->dev); ++ pm_runtime_put_autosuspend(&client->dev); + + return 0; + -+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); ++error_subdev_cleanup: ++ v4l2_subdev_cleanup(&ov64a40->sd); ++error_media_entity: ++ media_entity_cleanup(&ov64a40->sd.entity); ++error_handler_free: ++ v4l2_ctrl_handler_free(ov64a40->sd.ctrl_handler); ++error_poweroff: ++ ov64a40_power_off(&client->dev); ++ pm_runtime_set_suspended(&client->dev); + + return ret; +} + -+static int ov9281_remove(struct i2c_client *client) ++static void ov64a40_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ struct ov9281 *ov9281 = to_ov9281(sd); + + v4l2_async_unregister_subdev(sd); ++ v4l2_subdev_cleanup(sd); + media_entity_cleanup(&sd->entity); -+ v4l2_ctrl_handler_free(&ov9281->ctrl_handler); -+ mutex_destroy(&ov9281->mutex); ++ v4l2_ctrl_handler_free(sd->ctrl_handler); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) -+ __ov9281_power_off(ov9281); ++ ov64a40_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); -+ -+ return 0; +} + -+static const struct of_device_id ov9281_of_match = { -+ { .compatible = "ovti,ov9281" }, -+ {}, ++static const struct of_device_id ov64a40_of_ids = { ++ { .compatible = "ovti,ov64a40" }, ++ { /* sentinel */ } +}; -+MODULE_DEVICE_TABLE(of, ov9281_of_match); ++MODULE_DEVICE_TABLE(of, ov64a40_of_ids); + -+static const struct i2c_device_id ov9281_match_id = { -+ { "ovti,ov9281", 0 }, -+ { }, ++static const struct dev_pm_ops ov64a40_pm_ops = { ++ SET_RUNTIME_PM_OPS(ov64a40_power_off, ov64a40_power_on, NULL) +}; + -+static struct i2c_driver ov9281_i2c_driver = { -+ .driver = { -+ .name = OV9281_NAME, -+ .pm = &ov9281_pm_ops, -+ .of_match_table = of_match_ptr(ov9281_of_match), ++static struct i2c_driver ov64a40_i2c_driver = { ++ .driver = { ++ .name = "ov64a40", ++ .of_match_table = ov64a40_of_ids, ++ .pm = &ov64a40_pm_ops, + }, -+ .probe = &ov9281_probe, -+ .remove = &ov9281_remove, -+ .id_table = ov9281_match_id, ++ .probe = ov64a40_probe, ++ .remove = ov64a40_remove, +}; + -+static int __init sensor_mod_init(void) -+{ -+ return i2c_add_driver(&ov9281_i2c_driver); -+} ++module_i2c_driver(ov64a40_i2c_driver); + -+static void __exit sensor_mod_exit(void) -+{ -+ i2c_del_driver(&ov9281_i2c_driver); -+} ++MODULE_AUTHOR("Jacopo Mondi <jacopo.mondi@ideasonboard.com>"); ++MODULE_DESCRIPTION("OmniVision OV64A40 sensor driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c +index 675fb37a6fea..fc26f2b6a604 100644 +--- a/drivers/media/i2c/ov7251.c ++++ b/drivers/media/i2c/ov7251.c +@@ -23,6 +23,10 @@ + #include <media/v4l2-fwnode.h> + #include <media/v4l2-subdev.h> + ++static int trigger_mode; ++module_param(trigger_mode, int, 0644); ++MODULE_PARM_DESC(trigger_mode, "Set vsync trigger mode: 0=standalone, (1=source - not implemented), 2=sink"); + -+device_initcall_sync(sensor_mod_init); -+module_exit(sensor_mod_exit); + #define OV7251_SC_MODE_SELECT 0x0100 + #define OV7251_SC_MODE_SELECT_SW_STANDBY 0x0 + #define OV7251_SC_MODE_SELECT_STREAMING 0x1 +@@ -525,7 +529,6 @@ static const struct reg_value ov7251_setting_vga_90fps = { + { 0x3662, 0x01 }, + { 0x3663, 0x70 }, + { 0x3664, 0x50 }, +- { 0x3666, 0x0a }, + { 0x3669, 0x1a }, + { 0x366a, 0x00 }, + { 0x366b, 0x50 }, +@@ -592,9 +595,8 @@ static const struct reg_value ov7251_setting_vga_90fps = { + { 0x3c00, 0x89 }, + { 0x3c01, 0x63 }, + { 0x3c02, 0x01 }, +- { 0x3c03, 0x00 }, + { 0x3c04, 0x00 }, +- { 0x3c05, 0x03 }, ++ { 0x3c05, 0x01 }, + { 0x3c06, 0x00 }, + { 0x3c07, 0x06 }, + { 0x3c0c, 0x01 }, +@@ -624,6 +626,16 @@ static const struct reg_value ov7251_setting_vga_90fps = { + { 0x5001, 0x80 }, + }; + ++static const struct reg_value ov7251_ext_trig_on = { ++ { 0x3666, 0x00 }, ++ { 0x3c03, 0x17 }, ++}; ++ ++static const struct reg_value ov7251_ext_trig_off = { ++ { 0x3666, 0x0a }, ++ { 0x3c03, 0x00 }, ++}; ++ + static const unsigned long supported_xclk_rates = { + OV7251_19_2_MHZ = 19200000, + OV7251_24_MHZ = 24000000, +@@ -1051,7 +1063,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_EXPOSURE: + ret = ov7251_set_exposure(ov7251, ctrl->val); + break; +- case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: + ret = ov7251_set_gain(ov7251, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: +@@ -1344,6 +1356,14 @@ static int ov7251_s_stream(struct v4l2_subdev *subdev, int enable) + if (ret < 0) + goto err_power_down; + ++ ret = ov7251_set_register_array(ov7251, ++ ov7251_global_init_setting, ++ ARRAY_SIZE(ov7251_global_init_setting)); ++ if (ret < 0) { ++ dev_err(ov7251->dev, "could not set global_init_setting\n"); ++ goto err_power_down; ++ } + -+MODULE_DESCRIPTION("OmniVision ov9281 sensor driver"); -+MODULE_LICENSE("GPL v2"); + ret = ov7251_pll_configure(ov7251); + if (ret) { + dev_err(ov7251->dev, "error configuring PLLs\n"); +@@ -1364,6 +1384,23 @@ static int ov7251_s_stream(struct v4l2_subdev *subdev, int enable) + dev_err(ov7251->dev, "could not sync v4l2 controls\n"); + goto err_power_down; + } ++ ++ /* Set vsync trigger mode */ ++ switch (trigger_mode) { ++ case 2: ++ ov7251_set_register_array(ov7251, ++ ov7251_ext_trig_on, ++ ARRAY_SIZE(ov7251_ext_trig_on)); ++ break; ++ case 0: ++ default: ++ /* case 1 for ext trig source currently not implemented */ ++ ov7251_set_register_array(ov7251, ++ ov7251_ext_trig_off, ++ ARRAY_SIZE(ov7251_ext_trig_off)); ++ break; ++ } ++ + ret = ov7251_write_reg(ov7251, OV7251_SC_MODE_SELECT, + OV7251_SC_MODE_SELECT_STREAMING); + if (ret) +@@ -1541,7 +1578,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) + s64 pixel_rate; + int hblank; + +- v4l2_ctrl_handler_init(&ov7251->ctrls, 7); ++ v4l2_ctrl_handler_init(&ov7251->ctrls, 9); + ov7251->ctrls.lock = &ov7251->lock; + + v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, +@@ -1551,7 +1588,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) + ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 32, 1, 32); + ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, +- V4L2_CID_GAIN, 16, 1023, 1, 16); ++ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); + v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov7251_test_pattern_menu) - 1, +@@ -1600,6 +1637,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) + + static int ov7251_probe(struct i2c_client *client) + { ++ struct v4l2_fwnode_device_properties props; + struct device *dev = &client->dev; + struct ov7251 *ov7251; + unsigned int rate = 0, clk_rate = 0; +@@ -1675,7 +1713,8 @@ static int ov7251_probe(struct i2c_client *client) + return PTR_ERR(ov7251->analog_regulator); + } + +- ov7251->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); ++ ov7251->enable_gpio = devm_gpiod_get_optional(dev, "enable", ++ GPIOD_OUT_HIGH); + if (IS_ERR(ov7251->enable_gpio)) { + dev_err(dev, "cannot get enable gpio\n"); + return PTR_ERR(ov7251->enable_gpio); +@@ -1690,6 +1729,15 @@ static int ov7251_probe(struct i2c_client *client) + goto destroy_mutex; + } + ++ ret = v4l2_fwnode_device_parse(&client->dev, &props); ++ if (ret) ++ goto free_ctrl; ++ ++ ret = v4l2_ctrl_new_fwnode_properties(&ov7251->ctrls, &ov7251_ctrl_ops, ++ &props); ++ if (ret) ++ goto free_ctrl; ++ + v4l2_i2c_subdev_init(&ov7251->sd, client, &ov7251_subdev_ops); + ov7251->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ov7251->pad.flags = MEDIA_PAD_FL_SOURCE; +diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c +index 068c7449f50e..0b092a425cfc 100644 +--- a/drivers/media/i2c/ov9282.c ++++ b/drivers/media/i2c/ov9282.c +@@ -1078,12 +1078,16 @@ static int ov9282_set_stream(struct v4l2_subdev *sd, int enable) + static int ov9282_detect(struct ov9282 *ov9282) + { + int ret; +- u32 val; ++ u32 val, msb; + +- ret = ov9282_read_reg(ov9282, OV9282_REG_ID, 2, &val); ++ ret = ov9282_read_reg(ov9282, OV9282_REG_ID + 1, 1, &val); ++ if (ret) ++ return ret; ++ ret = ov9282_read_reg(ov9282, OV9282_REG_ID, 1, &msb); + if (ret) + return ret; + ++ val |= (msb << 8); + if (val != OV9282_ID) { + dev_err(ov9282->dev, "chip id mismatch: %x!=%x", + OV9282_ID, val); diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c -index f21da11caf22..ce64c25c1511 100644 +index 2785935da497..5b6f74e56bde 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -110,7 +110,7 @@ static inline struct tc358743_state *to_state(struct v4l2_subdev *sd) @@ -81086,8 +123282,8 @@ struct tc358743_state *state = to_state(sd); struct i2c_client *client = state->i2c_client; @@ -136,6 +136,7 @@ static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) - v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n", - __func__, reg, client->addr); + v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed: %d\n", + __func__, reg, client->addr, err); } + return err != ARRAY_SIZE(msgs); } @@ -81134,30 +123330,7 @@ static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val) { i2c_wrreg(sd, reg, val, 2); -@@ -1609,11 +1626,20 @@ static int tc358743_get_mbus_config(struct v4l2_subdev *sd, - 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; -+ -+ /* 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 the driver */ -- cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; -+ /* 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: -@@ -1665,12 +1691,23 @@ static int tc358743_enum_mbus_code(struct v4l2_subdev *sd, +@@ -1651,12 +1668,23 @@ static int tc358743_enum_mbus_code(struct v4l2_subdev *sd, return 0; } @@ -81174,7 +123347,7 @@ +} + static int tc358743_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct tc358743_state *state = to_state(sd); @@ -81182,7 +123355,7 @@ if (format->pad != 0) return -EINVAL; -@@ -1680,23 +1717,7 @@ static int tc358743_get_fmt(struct v4l2_subdev *sd, +@@ -1666,23 +1694,7 @@ static int tc358743_get_fmt(struct v4l2_subdev *sd, format->format.height = state->timings.bt.height; format->format.field = V4L2_FIELD_NONE; @@ -81207,9 +123380,9 @@ return 0; } -@@ -1710,19 +1731,14 @@ static int tc358743_set_fmt(struct v4l2_subdev *sd, +@@ -1696,19 +1708,14 @@ static int tc358743_set_fmt(struct v4l2_subdev *sd, u32 code = format->format.code; /* is overwritten by get_fmt */ - int ret = tc358743_get_fmt(sd, cfg, format); + int ret = tc358743_get_fmt(sd, sd_state, format); - format->format.code = code; + if (code == MEDIA_BUS_FMT_RGB888_1X24 || @@ -81231,7 +123404,7 @@ if (format->which == V4L2_SUBDEV_FORMAT_TRY) return 0; -@@ -1950,7 +1966,7 @@ static int tc358743_probe_of(struct tc358743_state *state) +@@ -1933,7 +1940,7 @@ static int tc358743_probe_of(struct tc358743_state *state) 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. */ @@ -81240,7 +123413,7 @@ /* * 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. -@@ -1970,6 +1986,7 @@ static int tc358743_probe_of(struct tc358743_state *state) +@@ -1953,6 +1960,7 @@ static int tc358743_probe_of(struct tc358743_state *state) /* * 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. @@ -81248,7 +123421,7 @@ */ bps_pr_lane = 2 * endpoint.link_frequencies0; if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) { -@@ -1983,23 +2000,42 @@ static int tc358743_probe_of(struct tc358743_state *state) +@@ -1966,23 +1974,42 @@ static int tc358743_probe_of(struct tc358743_state *state) state->pdata.refclk_hz * state->pdata.pll_prd; /* @@ -81274,7 +123447,7 @@ - state->pdata.tclk_postcnt = 0x008; - state->pdata.ths_trailcnt = 0x2; - state->pdata.hstxvregcnt = 0; -+ /* fall through */ ++ fallthrough; + case 594000000U: + state->pdata.lineinitcnt = 0xe80; + state->pdata.lptxtimecnt = 0x003; @@ -81305,7 +123478,7 @@ state->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); -@@ -2038,6 +2074,7 @@ static int tc358743_probe(struct i2c_client *client) +@@ -2021,6 +2048,7 @@ static int tc358743_probe(struct i2c_client *client) struct tc358743_platform_data *pdata = client->dev.platform_data; struct v4l2_subdev *sd; u16 irq_mask = MASK_HDMI_MSK | MASK_CSI_MSK; @@ -81313,15 +123486,7 @@ int err; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) -@@ -2056,6 +2093,7 @@ static int tc358743_probe(struct i2c_client *client) - 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) -@@ -2069,7 +2107,8 @@ static int tc358743_probe(struct i2c_client *client) +@@ -2052,7 +2080,8 @@ static int tc358743_probe(struct i2c_client *client) sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; /* i2c access */ @@ -81332,10 +123497,10 @@ client->addr << 1); return -ENODEV; diff --git a/drivers/media/mc/mc-request.c b/drivers/media/mc/mc-request.c -index c0782fd96c59..88a167fc830e 100644 +index addb8f2d8939..ee5b77a1a2f3 100644 --- a/drivers/media/mc/mc-request.c +++ b/drivers/media/mc/mc-request.c -@@ -504,3 +504,38 @@ void media_request_object_complete(struct media_request_object *obj) +@@ -505,3 +505,38 @@ void media_request_object_complete(struct media_request_object *obj) media_request_put(req); } EXPORT_SYMBOL_GPL(media_request_object_complete); @@ -81375,31 +123540,48 @@ +} +EXPORT_SYMBOL_GPL(media_request_unpin); diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig -index 7e152bbb4fa6..e8c0dc223ba2 100644 +index ee579916f874..8f9acc325cc8 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig -@@ -152,6 +152,7 @@ source "drivers/media/platform/am437x/Kconfig" - source "drivers/media/platform/xilinx/Kconfig" - source "drivers/media/platform/rcar-vin/Kconfig" +@@ -67,6 +67,7 @@ source "drivers/media/platform/amlogic/Kconfig" + source "drivers/media/platform/amphion/Kconfig" + source "drivers/media/platform/aspeed/Kconfig" source "drivers/media/platform/atmel/Kconfig" +source "drivers/media/platform/bcm2835/Kconfig" - source "drivers/media/platform/sunxi/Kconfig" - - config VIDEO_TI_CAL + source "drivers/media/platform/cadence/Kconfig" + source "drivers/media/platform/chips-media/Kconfig" + source "drivers/media/platform/intel/Kconfig" +@@ -76,6 +77,7 @@ source "drivers/media/platform/microchip/Kconfig" + source "drivers/media/platform/nvidia/Kconfig" + source "drivers/media/platform/nxp/Kconfig" + source "drivers/media/platform/qcom/Kconfig" ++source "drivers/media/platform/raspberrypi/Kconfig" + source "drivers/media/platform/renesas/Kconfig" + source "drivers/media/platform/rockchip/Kconfig" + source "drivers/media/platform/samsung/Kconfig" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile -index 62b6cdc8c730..1fb1a67451e3 100644 +index 5453bb868e67..eab239b4466a 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile -@@ -79,4 +79,6 @@ obj-$(CONFIG_VIDEO_QCOM_CAMSS) += qcom/camss/ - - obj-$(CONFIG_VIDEO_QCOM_VENUS) += qcom/venus/ - -+obj-y += bcm2835/ -+ - obj-y += sunxi/ +@@ -10,6 +10,7 @@ obj-y += amlogic/ + obj-y += amphion/ + obj-y += aspeed/ + obj-y += atmel/ ++obj-y += bcm2835/ + obj-y += cadence/ + obj-y += chips-media/ + obj-y += intel/ +@@ -19,6 +20,7 @@ obj-y += microchip/ + obj-y += nvidia/ + obj-y += nxp/ + obj-y += qcom/ ++obj-y += raspberrypi/ + obj-y += renesas/ + obj-y += rockchip/ + obj-y += samsung/ diff --git a/drivers/media/platform/bcm2835/Kconfig b/drivers/media/platform/bcm2835/Kconfig new file mode 100644 -index 000000000000..bd1370199650 +index 000000000000..8fa00f0b2cea --- /dev/null +++ b/drivers/media/platform/bcm2835/Kconfig @@ -0,0 +1,21 @@ @@ -81407,7 +123589,7 @@ + +config VIDEO_BCM2835_UNICAM + tristate "Broadcom BCM283x/BCM271x Unicam video capture driver" -+ depends on VIDEO_V4L2 ++ depends on VIDEO_DEV + depends on ARCH_BCM2835 || COMPILE_TEST + select VIDEO_V4L2_SUBDEV_API + select MEDIA_CONTROLLER @@ -81435,10 +123617,10 @@ +obj-$(CONFIG_VIDEO_BCM2835_UNICAM) += bcm2835-unicam.o diff --git a/drivers/media/platform/bcm2835/bcm2835-unicam.c b/drivers/media/platform/bcm2835/bcm2835-unicam.c new file mode 100644 -index 000000000000..99edc044c934 +index 000000000000..65f66327c04f --- /dev/null +++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c -@@ -0,0 +1,3434 @@ +@@ -0,0 +1,3516 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * BCM283x / BCM271x Unicam Capture Driver @@ -81503,6 +123685,7 @@ +#include <linux/uaccess.h> +#include <linux/videodev2.h> + ++#include <media/mipi-csi2.h> +#include <media/v4l2-common.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-dev.h> @@ -81513,6 +123696,8 @@ +#include <media/v4l2-fwnode.h> +#include <media/videobuf2-dma-contig.h> + ++#include <media/v4l2-async.h> ++ +#include "vc4-regs-unicam.h" + +#define UNICAM_MODULE_NAME "unicam" @@ -81565,8 +123750,11 @@ +#define UNICAM_EMBEDDED_SIZE 16384 + +/* -+ * Size of the dummy buffer. Can be any size really, but the DMA -+ * allocation works in units of page sizes. ++ * Size of the dummy buffer allocation. ++ * ++ * Due to a HW bug causing buffer overruns in circular buffer mode under certain ++ * (not yet fully known) conditions, the dummy buffer allocation is set to a ++ * a single page size, but the hardware gets programmed with a buffer size of 0. + */ +#define DUMMY_BUF_SIZE (PAGE_SIZE) + @@ -81627,7 +123815,7 @@ + .fourcc = V4L2_PIX_FMT_YUYV, + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .depth = 16, -+ .csi_dt = 0x1e, ++ .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .check_variants = 1, + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 | + MASK_CS_JPEG, @@ -81635,7 +123823,7 @@ + .fourcc = V4L2_PIX_FMT_UYVY, + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .depth = 16, -+ .csi_dt = 0x1e, ++ .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .check_variants = 1, + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 | + MASK_CS_JPEG, @@ -81643,7 +123831,7 @@ + .fourcc = V4L2_PIX_FMT_YVYU, + .code = MEDIA_BUS_FMT_YVYU8_2X8, + .depth = 16, -+ .csi_dt = 0x1e, ++ .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .check_variants = 1, + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 | + MASK_CS_JPEG, @@ -81651,7 +123839,7 @@ + .fourcc = V4L2_PIX_FMT_VYUY, + .code = MEDIA_BUS_FMT_VYUY8_2X8, + .depth = 16, -+ .csi_dt = 0x1e, ++ .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .check_variants = 1, + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 | + MASK_CS_JPEG, @@ -81659,7 +123847,7 @@ + .fourcc = V4L2_PIX_FMT_YUYV, + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .depth = 16, -+ .csi_dt = 0x1e, ++ .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .mc_skip = 1, + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 | + MASK_CS_JPEG, @@ -81667,7 +123855,7 @@ + .fourcc = V4L2_PIX_FMT_UYVY, + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .depth = 16, -+ .csi_dt = 0x1e, ++ .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .mc_skip = 1, + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 | + MASK_CS_JPEG, @@ -81675,7 +123863,7 @@ + .fourcc = V4L2_PIX_FMT_YVYU, + .code = MEDIA_BUS_FMT_YVYU8_1X16, + .depth = 16, -+ .csi_dt = 0x1e, ++ .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .mc_skip = 1, + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 | + MASK_CS_JPEG, @@ -81683,7 +123871,7 @@ + .fourcc = V4L2_PIX_FMT_VYUY, + .code = MEDIA_BUS_FMT_VYUY8_1X16, + .depth = 16, -+ .csi_dt = 0x1e, ++ .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .mc_skip = 1, + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 | + MASK_CS_JPEG, @@ -81692,37 +123880,37 @@ + .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .depth = 16, -+ .csi_dt = 0x22, ++ .csi_dt = MIPI_CSI2_DT_RGB565, + .valid_colorspaces = MASK_CS_SRGB, + }, { + .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, + .depth = 16, -+ .csi_dt = 0x22, ++ .csi_dt = MIPI_CSI2_DT_RGB565, + .valid_colorspaces = MASK_CS_SRGB, + }, { + .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, + .depth = 16, -+ .csi_dt = 0x21, ++ .csi_dt = MIPI_CSI2_DT_RGB555, + .valid_colorspaces = MASK_CS_SRGB, + }, { + .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, + .depth = 16, -+ .csi_dt = 0x21, ++ .csi_dt = MIPI_CSI2_DT_RGB555, + .valid_colorspaces = MASK_CS_SRGB, + }, { + .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ + .code = MEDIA_BUS_FMT_RGB888_1X24, + .depth = 24, -+ .csi_dt = 0x24, ++ .csi_dt = MIPI_CSI2_DT_RGB888, + .valid_colorspaces = MASK_CS_SRGB, + }, { + .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ + .code = MEDIA_BUS_FMT_BGR888_1X24, + .depth = 24, -+ .csi_dt = 0x24, ++ .csi_dt = MIPI_CSI2_DT_RGB888, + .valid_colorspaces = MASK_CS_SRGB, + }, { + .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ @@ -81735,143 +123923,168 @@ + .fourcc = V4L2_PIX_FMT_SBGGR8, + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .depth = 8, -+ .csi_dt = 0x2a, ++ .csi_dt = MIPI_CSI2_DT_RAW8, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .depth = 8, -+ .csi_dt = 0x2a, ++ .csi_dt = MIPI_CSI2_DT_RAW8, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .depth = 8, -+ .csi_dt = 0x2a, ++ .csi_dt = MIPI_CSI2_DT_RAW8, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .depth = 8, -+ .csi_dt = 0x2a, ++ .csi_dt = MIPI_CSI2_DT_RAW8, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR10P, + .repacked_fourcc = V4L2_PIX_FMT_SBGGR10, + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .depth = 10, -+ .csi_dt = 0x2b, ++ .csi_dt = MIPI_CSI2_DT_RAW10, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG10P, + .repacked_fourcc = V4L2_PIX_FMT_SGBRG10, + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .depth = 10, -+ .csi_dt = 0x2b, ++ .csi_dt = MIPI_CSI2_DT_RAW10, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG10P, + .repacked_fourcc = V4L2_PIX_FMT_SGRBG10, + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .depth = 10, -+ .csi_dt = 0x2b, ++ .csi_dt = MIPI_CSI2_DT_RAW10, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB10P, + .repacked_fourcc = V4L2_PIX_FMT_SRGGB10, + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .depth = 10, -+ .csi_dt = 0x2b, ++ .csi_dt = MIPI_CSI2_DT_RAW10, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR12P, + .repacked_fourcc = V4L2_PIX_FMT_SBGGR12, + .code = MEDIA_BUS_FMT_SBGGR12_1X12, + .depth = 12, -+ .csi_dt = 0x2c, ++ .csi_dt = MIPI_CSI2_DT_RAW12, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG12P, + .repacked_fourcc = V4L2_PIX_FMT_SGBRG12, + .code = MEDIA_BUS_FMT_SGBRG12_1X12, + .depth = 12, -+ .csi_dt = 0x2c, ++ .csi_dt = MIPI_CSI2_DT_RAW12, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG12P, + .repacked_fourcc = V4L2_PIX_FMT_SGRBG12, + .code = MEDIA_BUS_FMT_SGRBG12_1X12, + .depth = 12, -+ .csi_dt = 0x2c, ++ .csi_dt = MIPI_CSI2_DT_RAW12, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB12P, + .repacked_fourcc = V4L2_PIX_FMT_SRGGB12, + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .depth = 12, -+ .csi_dt = 0x2c, ++ .csi_dt = MIPI_CSI2_DT_RAW12, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR14P, + .repacked_fourcc = V4L2_PIX_FMT_SBGGR14, + .code = MEDIA_BUS_FMT_SBGGR14_1X14, + .depth = 14, -+ .csi_dt = 0x2d, ++ .csi_dt = MIPI_CSI2_DT_RAW14, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG14P, + .repacked_fourcc = V4L2_PIX_FMT_SGBRG14, + .code = MEDIA_BUS_FMT_SGBRG14_1X14, + .depth = 14, -+ .csi_dt = 0x2d, ++ .csi_dt = MIPI_CSI2_DT_RAW14, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG14P, + .repacked_fourcc = V4L2_PIX_FMT_SGRBG14, + .code = MEDIA_BUS_FMT_SGRBG14_1X14, + .depth = 14, -+ .csi_dt = 0x2d, ++ .csi_dt = MIPI_CSI2_DT_RAW14, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB14P, + .repacked_fourcc = V4L2_PIX_FMT_SRGGB14, + .code = MEDIA_BUS_FMT_SRGGB14_1X14, + .depth = 14, -+ .csi_dt = 0x2d, ++ .csi_dt = MIPI_CSI2_DT_RAW14, ++ .valid_colorspaces = MASK_CS_RAW, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SBGGR16, ++ .code = MEDIA_BUS_FMT_SBGGR16_1X16, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_RAW16, ++ .valid_colorspaces = MASK_CS_RAW, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGBRG16, ++ .code = MEDIA_BUS_FMT_SGBRG16_1X16, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_RAW16, ++ .valid_colorspaces = MASK_CS_RAW, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGRBG16, ++ .code = MEDIA_BUS_FMT_SGRBG16_1X16, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_RAW16, ++ .valid_colorspaces = MASK_CS_RAW, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SRGGB16, ++ .code = MEDIA_BUS_FMT_SRGGB16_1X16, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_RAW16, + .valid_colorspaces = MASK_CS_RAW, + }, { -+ /* -+ * 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, ++ .csi_dt = MIPI_CSI2_DT_RAW8, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_Y10P, + .repacked_fourcc = V4L2_PIX_FMT_Y10, + .code = MEDIA_BUS_FMT_Y10_1X10, + .depth = 10, -+ .csi_dt = 0x2b, ++ .csi_dt = MIPI_CSI2_DT_RAW10, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_Y12P, + .repacked_fourcc = V4L2_PIX_FMT_Y12, + .code = MEDIA_BUS_FMT_Y12_1X12, + .depth = 12, -+ .csi_dt = 0x2c, ++ .csi_dt = MIPI_CSI2_DT_RAW12, + .valid_colorspaces = MASK_CS_RAW, + }, { + .fourcc = V4L2_PIX_FMT_Y14P, + .repacked_fourcc = V4L2_PIX_FMT_Y14, + .code = MEDIA_BUS_FMT_Y14_1X14, + .depth = 14, -+ .csi_dt = 0x2d, ++ .csi_dt = MIPI_CSI2_DT_RAW14, ++ .valid_colorspaces = MASK_CS_RAW, ++ }, { ++ .fourcc = V4L2_PIX_FMT_Y16, ++ .code = MEDIA_BUS_FMT_Y16_1X16, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_RAW16, + .valid_colorspaces = MASK_CS_RAW, + }, + /* Embedded data format */ @@ -81937,7 +124150,7 @@ + struct kref kref; + + /* V4l2 specific parameters */ -+ struct v4l2_async_subdev asd; ++ struct v4l2_async_connection *asd; + + /* peripheral base address */ + void __iomem *base; @@ -81947,8 +124160,6 @@ + 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 */ @@ -81960,11 +124171,12 @@ + /* subdevice async Notifier */ + struct v4l2_async_notifier notifier; + unsigned int sequence; ++ bool frame_started; + + /* ptr to sub device */ + struct v4l2_subdev *sensor; + /* Pad config for the sensor */ -+ struct v4l2_subdev_pad_config *sensor_config; ++ struct v4l2_subdev_state *sensor_state; + + enum v4l2_mbus_type bus_type; + /* @@ -82117,7 +124329,7 @@ + }; + int ret; + -+ ret = v4l2_subdev_call(dev->sensor, pad, get_fmt, dev->sensor_config, ++ ret = v4l2_subdev_call(dev->sensor, pad, get_fmt, dev->sensor_state, + &sd_fmt); + if (ret < 0) + return ret; @@ -82141,7 +124353,7 @@ + + sd_fmt.format = *fmt; + -+ ret = v4l2_subdev_call(dev->sensor, pad, set_fmt, dev->sensor_config, ++ ret = v4l2_subdev_call(dev->sensor, pad, set_fmt, dev->sensor_state, + &sd_fmt); + if (ret < 0) + return ret; @@ -82284,8 +124496,7 @@ + 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); ++ unicam_wr_dma_addr(dev, node->dummy_buf_dma_addr, 0, node->pad_id); + node->next_frm = NULL; +} + @@ -82353,6 +124564,8 @@ + * buffer forever. + */ + if (fe) { ++ bool inc_seq = unicam->frame_started; ++ + /* + * Ensure we have swapped buffers already as we can't + * stop the peripheral. If no buffer is available, use a @@ -82360,7 +124573,9 @@ + * to use. + */ + for (i = 0; i < ARRAY_SIZE(unicam->node); i++) { -+ if (!unicam->nodei.streaming) ++ struct unicam_node *node = &unicam->nodei; ++ ++ if (!node->streaming) + continue; + + /* @@ -82370,13 +124585,39 @@ + * + FS + LS). In this case, we cannot signal the buffer + * as complete, as the HW will reuse that buffer. + */ -+ if (unicam->nodei.cur_frm && -+ unicam->nodei.cur_frm != unicam->nodei.next_frm) -+ unicam_process_buffer_complete(&unicam->nodei, -+ sequence); -+ unicam->nodei.cur_frm = unicam->nodei.next_frm; ++ if (node->cur_frm && node->cur_frm != node->next_frm) { ++ /* ++ * This condition checks if FE + FS for the same ++ * frame has occurred. In such cases, we cannot ++ * return out the frame, as no buffer handling ++ * or timestamping has yet been done as part of ++ * the FS handler. ++ */ ++ if (!node->cur_frm->vb.vb2_buf.timestamp) { ++ unicam_dbg(2, unicam, "ISR: FE without FS, dropping frame\n"); ++ continue; ++ } ++ ++ unicam_process_buffer_complete(node, sequence); ++ node->cur_frm = node->next_frm; ++ node->next_frm = NULL; ++ inc_seq = true; ++ } else { ++ node->cur_frm = node->next_frm; ++ } ++ } ++ ++ /* ++ * Increment the sequence number conditionally on either a FS ++ * having already occurred, or in the FE + FS condition as ++ * caught in the FE handler above. This ensures the sequence ++ * number corresponds to the frames generated by the sensor, not ++ * the frames dequeued to userland. ++ */ ++ if (inc_seq) { ++ unicam->sequence++; ++ unicam->frame_started = false; + } -+ unicam->sequence++; + } + + if (ista & UNICAM_FSI) { @@ -82397,13 +124638,29 @@ + i); + /* + * Set the next frame output to go to a dummy frame -+ * if we have not managed to obtain another frame -+ * from the queue. ++ * if no buffer currently queued. + */ -+ unicam_schedule_dummy_buffer(&unicam->nodei); ++ if (!unicam->nodei.next_frm || ++ unicam->nodei.next_frm == unicam->nodei.cur_frm) { ++ unicam_schedule_dummy_buffer(&unicam->nodei); ++ } else if (unicam->nodei.cur_frm) { ++ /* ++ * Repeated FS without FE. Hardware will have ++ * swapped buffers, but the cur_frm doesn't ++ * contain valid data. Return cur_frm to the ++ * queue. ++ */ ++ spin_lock(&unicam->nodei.dma_queue_lock); ++ list_add_tail(&unicam->nodei.cur_frm->list, ++ &unicam->nodei.dma_queue); ++ spin_unlock(&unicam->nodei.dma_queue_lock); ++ unicam->nodei.cur_frm = unicam->nodei.next_frm; ++ unicam->nodei.next_frm = NULL; ++ } + } + + unicam_queue_event_sof(unicam); ++ unicam->frame_started = true; + } + + /* @@ -82648,7 +124905,7 @@ + */ + mbus_fmt->field = V4L2_FIELD_NONE; + -+ ret = v4l2_subdev_call(dev->sensor, pad, set_fmt, dev->sensor_config, ++ ret = v4l2_subdev_call(dev->sensor, pad, set_fmt, dev->sensor_state, + &sd_fmt); + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) + return ret; @@ -82670,7 +124927,7 @@ + mbus_fmt->code = fmt->code; + + ret = v4l2_subdev_call(dev->sensor, pad, set_fmt, -+ dev->sensor_config, &sd_fmt); ++ dev->sensor_state, &sd_fmt); + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) + return ret; + @@ -83486,7 +125743,7 @@ + struct v4l2_subdev_format source_fmt; + int ret; + -+ if (!media_entity_remote_pad(link->sink->entity->pads)) { ++ if (!media_entity_remote_source_pad_unique(link->sink->entity)) { + unicam_dbg(1, unicam, + "video node %s pad not connected\n", vd->name); + return -ENOTCONN; @@ -83767,7 +126024,7 @@ + /* CSI2 */ + set_field(&val, 1, UNICAM_CLE); + set_field(&val, 1, UNICAM_CLLPE); -+ if (dev->bus_flags & V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) { ++ if (!(dev->bus_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)) { + set_field(&val, 1, UNICAM_CLTRE); + set_field(&val, 1, UNICAM_CLHSE); + } @@ -83789,7 +126046,7 @@ + /* CSI2 */ + set_field(&val, 1, UNICAM_DLE); + set_field(&val, 1, UNICAM_DLLPE); -+ if (dev->bus_flags & V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) { ++ if (!(dev->bus_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)) { + set_field(&val, 1, UNICAM_DLTRE); + set_field(&val, 1, UNICAM_DLHSE); + } @@ -83837,1306 +126094,9699 @@ + unicam_wr_dma_addr(dev, addrMETADATA_PAD, size, METADATA_PAD); + } + -+ /* Enable peripheral */ -+ reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_CPE); ++ /* 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->nodeMETADATA_PAD.streaming && dev->sensor_embedded_data) ++ reg_write_field(dev, UNICAM_DCS, 1, UNICAM_LDP); ++} ++ ++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_addrMAX_NODES = { 0 }; ++ unsigned long flags; ++ unsigned int i; ++ int ret; ++ ++ node->streaming = true; ++ if (!(dev->nodeIMAGE_PAD.open && dev->nodeIMAGE_PAD.streaming && ++ (!dev->nodeMETADATA_PAD.open || ++ dev->nodeMETADATA_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; ++ } ++ ++ ret = media_pipeline_start(dev->nodeIMAGE_PAD.video_dev.entity.pads, ++ &dev->nodeIMAGE_PAD.pipe); ++ if (ret < 0) { ++ unicam_err(dev, "Failed to start media pipeline: %d\n", ret); ++ goto err_pm_put; ++ } ++ ++ 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 error_pipeline; ++ } ++ ++ dev->active_data_lanes = mbus_config.bus.mipi_csi2.num_data_lanes; ++ 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 error_pipeline; ++ } ++ } ++ ++ unicam_dbg(1, dev, "Running with %u data lanes\n", ++ dev->active_data_lanes); ++ ++ ret = clk_set_min_rate(dev->vpu_clock, MIN_VPU_CLOCK_RATE); ++ if (ret) { ++ unicam_err(dev, "failed to set up VPU clock\n"); ++ goto error_pipeline; ++ } ++ ++ ret = clk_prepare_enable(dev->vpu_clock); ++ if (ret) { ++ unicam_err(dev, "Failed to enable VPU clock: %d\n", ret); ++ goto error_pipeline; ++ } ++ ++ 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->nodei.streaming) ++ continue; ++ ++ spin_lock_irqsave(&dev->nodei.dma_queue_lock, flags); ++ buf = list_first_entry(&dev->nodei.dma_queue, ++ struct unicam_buffer, list); ++ dev->nodei.cur_frm = buf; ++ dev->nodei.next_frm = buf; ++ list_del(&buf->list); ++ spin_unlock_irqrestore(&dev->nodei.dma_queue_lock, flags); ++ ++ buffer_addri = ++ vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); ++ } ++ ++ dev->frame_started = false; ++ unicam_start_rx(dev, buffer_addr); ++ ++ ret = v4l2_subdev_call(dev->sensor, video, s_stream, 1); ++ 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: ++ if (clk_set_min_rate(dev->vpu_clock, 0)) ++ unicam_err(dev, "failed to reset the VPU clock\n"); ++ clk_disable_unprepare(dev->vpu_clock); ++error_pipeline: ++ if (node->pad_id == IMAGE_PAD) ++ media_pipeline_stop(dev->nodeIMAGE_PAD.video_dev.entity.pads); ++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); ++ ++ media_pipeline_stop(node->video_dev.entity.pads); ++ ++ if (dev->clocks_enabled) { ++ if (clk_set_min_rate(dev->vpu_clock, 0)) ++ unicam_err(dev, "failed to reset the min VPU clock\n"); ++ ++ 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, 0, ++ METADATA_PAD); ++ } ++ ++ /* Clear all queued buffers for the node */ ++ unicam_return_buffers(node, VB2_BUF_STATE_ERROR); ++} ++ ++ ++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, ++}; ++ ++static int ++unicam_async_bound(struct v4l2_async_notifier *notifier, ++ struct v4l2_subdev *subdev, ++ struct v4l2_async_connection *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_state) ++ __v4l2_subdev_state_free(unicam->sensor_state); ++ ++ 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 unicam_set_default_format(struct unicam_device *unicam, ++ struct unicam_node *node, ++ int pad_id, ++ const struct unicam_fmt **ret_fmt) ++{ ++ 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) { ++ 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; ++ } ++ ++ if (fmt) ++ 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; ++ } ++ ++ *ret_fmt = fmt; ++ ++ return 0; ++} ++ ++static void unicam_mc_set_default_format(struct unicam_node *node, int pad_id) ++{ ++ if (pad_id == IMAGE_PAD) { ++ struct v4l2_pix_format *pix_fmt = &node->v_fmt.fmt.pix; ++ ++ pix_fmt->width = 640; ++ pix_fmt->height = 480; ++ pix_fmt->field = V4L2_FIELD_NONE; ++ pix_fmt->colorspace = V4L2_COLORSPACE_SRGB; ++ pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; ++ pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; ++ pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; ++ pix_fmt->pixelformat = formats0.fourcc; ++ unicam_calc_format_size_bpl(node->dev, &formats0, ++ &node->v_fmt); ++ node->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ ++ node->fmt = &formats0; ++ } else { ++ const struct unicam_fmt *fmt; ++ ++ /* 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->fmt = fmt; ++ ++ node->v_fmt.fmt.meta.buffersize = UNICAM_EMBEDDED_SIZE; ++ node->embedded_lines = 1; ++ node->v_fmt.type = V4L2_BUF_TYPE_META_CAPTURE; ++ } ++} ++ ++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; ++ int ret; ++ ++ node->dev = unicam; ++ node->pad_id = pad_id; ++ ++ if (!unicam->mc_api) { ++ const struct unicam_fmt *fmt; ++ ++ ret = unicam_set_default_format(unicam, node, pad_id, &fmt); ++ if (ret) ++ return ret; ++ node->fmt = fmt; ++ /* Read current subdev format */ ++ if (fmt) ++ unicam_reset_format(node); ++ } else { ++ unicam_mc_set_default_format(node, pad_id); ++ } ++ ++ if (!unicam->mc_api && ++ 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) { ++ if (!unicam->mc_api) { ++ /* 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->mc_api ? &unicam_mc_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; ++ if (unicam->mc_api) { ++ vdev->device_caps |= V4L2_CAP_IO_MC; ++ vdev->entity.ops = &unicam_mc_entity_ops; ++ } ++ ++ /* 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 (!unicam->mc_api) { ++ 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, ++ node->src_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->nodei; ++ ++ 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_async_complete(struct v4l2_async_notifier *notifier) ++{ ++ static struct lock_class_key key; ++ struct unicam_device *unicam = to_unicam_device(notifier->v4l2_dev); ++ unsigned int i, source_pads = 0; ++ int ret; ++ ++ unicam->v4l2_dev.notify = unicam_notify; ++ ++ unicam->sensor_state = __v4l2_subdev_state_alloc(unicam->sensor, ++ "unicam:async->lock", &key); ++ if (!unicam->sensor_state) ++ return -ENOMEM; ++ ++ for (i = 0; i < unicam->sensor->entity.num_pads; i++) { ++ if (unicam->sensor->entity.padsi.flags & MEDIA_PAD_FL_SOURCE) { ++ if (source_pads < MAX_NODES) { ++ unicam->nodesource_pads.src_pad_id = i; ++ unicam_dbg(3, unicam, "source pad %u is index %u\n", ++ source_pads, i); ++ } ++ source_pads++; ++ } ++ } ++ if (!source_pads) { ++ unicam_err(unicam, "No source pads on sensor.\n"); ++ ret = -ENODEV; ++ goto unregister; ++ } ++ ++ ret = register_node(unicam, &unicam->nodeIMAGE_PAD, ++ V4L2_BUF_TYPE_VIDEO_CAPTURE, IMAGE_PAD); ++ if (ret) { ++ unicam_err(unicam, "Unable to register image video device.\n"); ++ goto unregister; ++ } ++ ++ if (source_pads >= 2) { ++ unicam->sensor_embedded_data = true; ++ ++ ret = register_node(unicam, &unicam->nodeMETADATA_PAD, ++ V4L2_BUF_TYPE_META_CAPTURE, METADATA_PAD); ++ if (ret) { ++ unicam_err(unicam, "Unable to register metadata video device.\n"); ++ goto unregister; ++ } ++ } ++ ++ if (unicam->mc_api) ++ ret = v4l2_device_register_subdev_nodes(&unicam->v4l2_dev); ++ else ++ 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 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_laneslane != 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_nf_init(&dev->notifier, &dev->v4l2_dev); ++ dev->notifier.ops = &unicam_async_ops; ++ ++ dev->asd = v4l2_async_nf_add_fwnode(&dev->notifier, ++ of_fwnode_handle(sensor_node), ++ struct v4l2_async_connection); ++ if (IS_ERR(dev->asd)) { ++ unicam_err(dev, "Error adding subdevice: %d\n", ret); ++ goto cleanup_exit; ++ } ++ ++ ret = v4l2_async_nf_register(&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; ++ ++ /* ++ * Adopt the current setting of the module parameter, and check if ++ * device tree requests it. ++ */ ++ unicam->mc_api = media_controller; ++ if (of_property_read_bool(pdev->dev.of_node, "brcm,media-controller")) ++ unicam->mc_api = true; ++ ++ 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_nf_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 --git a/drivers/media/platform/bcm2835/vc4-regs-unicam.h b/drivers/media/platform/bcm2835/vc4-regs-unicam.h +new file mode 100644 +index 000000000000..ae059a171d0f +--- /dev/null ++++ b/drivers/media/platform/bcm2835/vc4-regs-unicam.h +@@ -0,0 +1,253 @@ ++/* 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_CMP0,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 --git a/drivers/media/platform/raspberrypi/Kconfig b/drivers/media/platform/raspberrypi/Kconfig +new file mode 100644 +index 000000000000..a1850c559dbb +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/Kconfig +@@ -0,0 +1,6 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++ ++comment "Raspberry Pi media platform drivers" ++ ++source "drivers/media/platform/raspberrypi/pisp_be/Kconfig" ++source "drivers/media/platform/raspberrypi/rp1_cfe/Kconfig" +diff --git a/drivers/media/platform/raspberrypi/Makefile b/drivers/media/platform/raspberrypi/Makefile +new file mode 100644 +index 000000000000..4ce6c998927c +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/Makefile +@@ -0,0 +1,4 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++obj-y += pisp_be/ ++obj-y += rp1_cfe/ +diff --git a/drivers/media/platform/raspberrypi/pisp_be/Kconfig b/drivers/media/platform/raspberrypi/pisp_be/Kconfig +new file mode 100644 +index 000000000000..f70ccbc0a07e +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/pisp_be/Kconfig +@@ -0,0 +1,12 @@ ++config VIDEO_RASPBERRYPI_PISP_BE ++ tristate "Raspberry Pi PiSP Backend (BE) ISP driver" ++ depends on VIDEO_DEV && PM ++ select VIDEO_V4L2_SUBDEV_API ++ select MEDIA_CONTROLLER ++ select VIDEOBUF2_DMA_CONTIG ++ select V4L2_FWNODE ++ help ++ Say Y here to enable support for the PiSP Backend (BE) ISP driver. ++ ++ To compile this driver as a module, choose M here. The module will be ++ called pisp-be. +diff --git a/drivers/media/platform/raspberrypi/pisp_be/Makefile b/drivers/media/platform/raspberrypi/pisp_be/Makefile +new file mode 100644 +index 000000000000..a70bf5716824 +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/pisp_be/Makefile +@@ -0,0 +1,6 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Makefile for Raspberry Pi PiSP Backend driver ++# ++pisp-be-objs := pisp_be.o ++obj-$(CONFIG_VIDEO_RASPBERRYPI_PISP_BE) += pisp-be.o +diff --git a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c +new file mode 100644 +index 000000000000..073b0e387473 +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c +@@ -0,0 +1,1993 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * PiSP Back End driver. ++ * Copyright (c) 2021-2022 Raspberry Pi Limited. ++ * ++ */ ++#include <linux/clk.h> ++#include <linux/interrupt.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/pm_runtime.h> ++#include <media/v4l2-device.h> ++#include <media/v4l2-ioctl.h> ++#include <media/videobuf2-dma-contig.h> ++#include <media/videobuf2-vmalloc.h> ++ ++#include "pisp_be_config.h" ++#include "pisp_be_formats.h" ++ ++MODULE_DESCRIPTION("PiSP Back End driver"); ++MODULE_AUTHOR("David Plowman <david.plowman@raspberrypi.com>"); ++MODULE_AUTHOR("Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>"); ++MODULE_LICENSE("GPL v2"); ++ ++/* Offset to use when registering the /dev/videoX node */ ++#define PISPBE_VIDEO_NODE_OFFSET 20 ++ ++/* Maximum number of config buffers possible */ ++#define PISP_BE_NUM_CONFIG_BUFFERS VB2_MAX_FRAME ++ ++/* ++ * We want to support 2 independent instances allowing 2 simultaneous users ++ * of the ISP-BE (of course they share hardware, platform resources and mutex). ++ * Each such instance comprises a group of device nodes representing input ++ * and output queues, and a media controller device node to describe them. ++ */ ++#define PISPBE_NUM_NODE_GROUPS 2 ++ ++#define PISPBE_NAME "pispbe" ++ ++/* Some ISP-BE registers */ ++#define PISP_BE_VERSION_OFFSET (0x0) ++#define PISP_BE_CONTROL_OFFSET (0x4) ++#define PISP_BE_TILE_ADDR_LO_OFFSET (0x8) ++#define PISP_BE_TILE_ADDR_HI_OFFSET (0xc) ++#define PISP_BE_STATUS_OFFSET (0x10) ++#define PISP_BE_BATCH_STATUS_OFFSET (0x14) ++#define PISP_BE_INTERRUPT_EN_OFFSET (0x18) ++#define PISP_BE_INTERRUPT_STATUS_OFFSET (0x1c) ++#define PISP_BE_AXI_OFFSET (0x20) ++#define PISP_BE_CONFIG_BASE_OFFSET (0x40) ++#define PISP_BE_IO_INPUT_ADDR0_LO_OFFSET (PISP_BE_CONFIG_BASE_OFFSET) ++#define PISP_BE_GLOBAL_BAYER_ENABLE_OFFSET (PISP_BE_CONFIG_BASE_OFFSET + 0x70) ++#define PISP_BE_GLOBAL_RGB_ENABLE_OFFSET (PISP_BE_CONFIG_BASE_OFFSET + 0x74) ++#define N_HW_ADDRESSES 14 ++#define N_HW_ENABLES 2 ++ ++#define PISP_BE_VERSION_2712C1 0x02252700 ++#define PISP_BE_VERSION_MINOR_BITS 0xF ++ ++/* ++ * This maps our nodes onto the inputs/outputs of the actual PiSP Back End. ++ * Be wary of the word "OUTPUT" which is used ambiguously here. In a V4L2 ++ * context it means an input to the hardware (source image or metadata). ++ * Elsewhere it means an output from the hardware. ++ */ ++enum node_ids { ++ MAIN_INPUT_NODE, ++ TDN_INPUT_NODE, ++ STITCH_INPUT_NODE, ++ HOG_OUTPUT_NODE, ++ OUTPUT0_NODE, ++ OUTPUT1_NODE, ++ TDN_OUTPUT_NODE, ++ STITCH_OUTPUT_NODE, ++ CONFIG_NODE, ++ PISPBE_NUM_NODES ++}; ++ ++struct node_description { ++ const char *ent_name; ++ enum v4l2_buf_type buf_type; ++ unsigned int caps; ++}; ++ ++static const struct node_description node_descPISPBE_NUM_NODES = { ++ /* MAIN_INPUT_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-input", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, ++ .caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE, ++ }, ++ /* TDN_INPUT_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-tdn_input", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, ++ .caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE, ++ }, ++ /* STITCH_INPUT_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-stitch_input", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, ++ .caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE, ++ }, ++ /* HOG_OUTPUT_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-hog_output", ++ .buf_type = V4L2_BUF_TYPE_META_CAPTURE, ++ .caps = V4L2_CAP_META_CAPTURE, ++ }, ++ /* OUTPUT0_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-output0", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, ++ .caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE, ++ }, ++ /* OUTPUT1_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-output1", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, ++ .caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE, ++ }, ++ /* TDN_OUTPUT_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-tdn_output", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, ++ .caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE, ++ }, ++ /* STITCH_OUTPUT_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-stitch_output", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, ++ .caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE, ++ }, ++ /* CONFIG_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-config", ++ .buf_type = V4L2_BUF_TYPE_META_OUTPUT, ++ .caps = V4L2_CAP_META_OUTPUT, ++ } ++}; ++ ++#define NODE_DESC_IS_OUTPUT(desc) ( \ ++ ((desc)->buf_type == V4L2_BUF_TYPE_META_OUTPUT) || \ ++ ((desc)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT) || \ ++ ((desc)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) ++ ++#define NODE_IS_META(node) ( \ ++ ((node)->buf_type == V4L2_BUF_TYPE_META_OUTPUT) || \ ++ ((node)->buf_type == V4L2_BUF_TYPE_META_CAPTURE)) ++#define NODE_IS_OUTPUT(node) ( \ ++ ((node)->buf_type == V4L2_BUF_TYPE_META_OUTPUT) || \ ++ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT) || \ ++ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) ++#define NODE_IS_CAPTURE(node) ( \ ++ ((node)->buf_type == V4L2_BUF_TYPE_META_CAPTURE) || \ ++ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) || \ ++ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) ++#define NODE_IS_MPLANE(node) ( \ ++ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) || \ ++ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) ++ ++/* ++ * Structure to describe a single node /dev/video<N> which represents a single ++ * input or output queue to the PiSP Back End device. ++ */ ++struct pispbe_node { ++ unsigned int id; ++ int vfl_dir; ++ enum v4l2_buf_type buf_type; ++ struct video_device vfd; ++ struct media_pad pad; ++ struct media_intf_devnode *intf_devnode; ++ struct media_link *intf_link; ++ struct pispbe_node_group *node_group; ++ struct mutex node_lock; ++ struct mutex queue_lock; ++ spinlock_t ready_lock; ++ struct list_head ready_queue; ++ struct vb2_queue queue; ++ struct v4l2_format format; ++ const struct pisp_be_format *pisp_format; ++}; ++ ++/* For logging only, use the entity name with "pispbe" and separator removed */ ++#define NODE_NAME(node) \ ++ (node_desc(node)->id.ent_name + sizeof(PISPBE_NAME)) ++#define NODE_GET_V4L2(node) ((node)->node_group->v4l2_dev) ++ ++/* ++ * Node group structure, which comprises all the input and output nodes that a ++ * single PiSP client will need, along with its own v4l2 and media devices. ++ */ ++struct pispbe_node_group { ++ unsigned int id; ++ struct v4l2_device v4l2_dev; ++ struct v4l2_subdev sd; ++ struct pispbe_dev *pispbe; ++ struct media_device mdev; ++ struct pispbe_node nodePISPBE_NUM_NODES; ++ u32 streaming_map; /* bitmap of which nodes are streaming */ ++ struct media_pad padPISPBE_NUM_NODES; /* output pads first */ ++ struct pisp_be_tiles_config *config; ++ dma_addr_t config_dma_addr; ++ unsigned int sequence; ++}; ++ ++/* Records details of the jobs currently running or queued on the h/w. */ ++struct pispbe_job { ++ struct pispbe_node_group *node_group; ++ /* ++ * An array of buffer pointers - remember it's source buffers first, ++ * then captures, then metadata last. ++ */ ++ struct pispbe_buffer *bufPISPBE_NUM_NODES; ++}; ++ ++/* ++ * Structure representing the entire PiSP Back End device, comprising several ++ * node groups which share platform resources and a mutex for the actual HW. ++ */ ++struct pispbe_dev { ++ struct device *dev; ++ struct pispbe_node_group node_groupPISPBE_NUM_NODE_GROUPS; ++ int hw_busy; /* non-zero if a job is queued or is being started */ ++ struct pispbe_job queued_job, running_job; ++ void __iomem *be_reg_base; ++ struct clk *clk; ++ int irq; ++ u32 hw_version; ++ u8 done, started; ++ spinlock_t hw_lock; /* protects "hw_busy" flag and streaming_map */ ++}; ++ ++static inline u32 read_reg(struct pispbe_dev *pispbe, unsigned int offset) ++{ ++ return readl(pispbe->be_reg_base + offset); ++} ++ ++static inline void write_reg(struct pispbe_dev *pispbe, unsigned int offset, ++ u32 val) ++{ ++ writel(val, pispbe->be_reg_base + offset); ++} ++ ++/* Check and initialize hardware. */ ++static int hw_init(struct pispbe_dev *pispbe) ++{ ++ u32 u; ++ ++ /* Check the HW is present and has a known version */ ++ u = read_reg(pispbe, PISP_BE_VERSION_OFFSET); ++ dev_info(pispbe->dev, "pispbe_probe: HW version: 0x%08x", u); ++ pispbe->hw_version = u; ++ if ((u & ~PISP_BE_VERSION_MINOR_BITS) != PISP_BE_VERSION_2712C1) ++ return -ENODEV; ++ ++ /* Clear leftover interrupts */ ++ write_reg(pispbe, PISP_BE_INTERRUPT_STATUS_OFFSET, 0xFFFFFFFFu); ++ u = read_reg(pispbe, PISP_BE_BATCH_STATUS_OFFSET); ++ dev_info(pispbe->dev, "pispbe_probe: BatchStatus: 0x%08x", u); ++ pispbe->done = (uint8_t)u; ++ pispbe->started = (uint8_t)(u >> 8); ++ u = read_reg(pispbe, PISP_BE_STATUS_OFFSET); ++ dev_info(pispbe->dev, "pispbe_probe: Status: 0x%08x", u); ++ if (u != 0 || pispbe->done != pispbe->started) { ++ dev_err(pispbe->dev, "pispbe_probe: HW is stuck or busy\n"); ++ return -EBUSY; ++ } ++ /* ++ * AXI QOS=0, CACHE=4'b0010, PROT=3'b011 ++ * Also set "chicken bits" 22:20 which enable sub-64-byte bursts ++ * and AXI AWID/BID variability (on versions which support this). ++ */ ++ write_reg(pispbe, PISP_BE_AXI_OFFSET, 0x32703200u); ++ ++ /* Enable both interrupt flags */ ++ write_reg(pispbe, PISP_BE_INTERRUPT_EN_OFFSET, 0x00000003u); ++ return 0; ++} ++ ++/* ++ * Queue a job to the h/w. If the h/w is idle it will begin immediately. ++ * Caller must ensure it is "safe to queue", i.e. we don't already have a ++ * queued, unstarted job. ++ */ ++static void hw_queue_job(struct pispbe_dev *pispbe, ++ dma_addr_t hw_dma_addrsN_HW_ADDRESSES, ++ u32 hw_enablesN_HW_ENABLES, ++ struct pisp_be_config *config, dma_addr_t tiles, ++ unsigned int num_tiles) ++{ ++ unsigned int begin, end; ++ unsigned int u; ++ ++ if (read_reg(pispbe, PISP_BE_STATUS_OFFSET) & 1) ++ dev_err(pispbe->dev, "ERROR: not safe to queue new job!\n"); ++ ++ /* ++ * Write configuration to hardware. DMA addresses and enable flags ++ * are passed separately, because the driver needs to sanitize them, ++ * and we don't want to modify (or be vulnerable to modifications of) ++ * the mmap'd buffer. ++ */ ++ for (u = 0; u < N_HW_ADDRESSES; ++u) { ++ write_reg(pispbe, PISP_BE_IO_INPUT_ADDR0_LO_OFFSET + 8 * u, ++ (u32)(hw_dma_addrsu)); ++ write_reg(pispbe, PISP_BE_IO_INPUT_ADDR0_LO_OFFSET + 8 * u + 4, ++ (u32)(hw_dma_addrsu >> 32)); ++ } ++ write_reg(pispbe, PISP_BE_GLOBAL_BAYER_ENABLE_OFFSET, hw_enables0); ++ write_reg(pispbe, PISP_BE_GLOBAL_RGB_ENABLE_OFFSET, hw_enables1); ++ ++ /* ++ * Everything else is as supplied by the user. XXX Buffer sizes not ++ * checked! ++ */ ++ begin = offsetof(struct pisp_be_config, global.bayer_order) / ++ sizeof(u32); ++ end = offsetof(struct pisp_be_config, axi) / sizeof(u32); ++ for (u = begin; u < end; u++) { ++ unsigned int val = ((u32 *)config)u; ++ ++ write_reg(pispbe, PISP_BE_CONFIG_BASE_OFFSET + 4 * u, val); ++ } ++ ++ /* Read back the addresses -- an error here could be fatal */ ++ for (u = 0; u < N_HW_ADDRESSES; ++u) { ++ unsigned int offset = PISP_BE_IO_INPUT_ADDR0_LO_OFFSET + 8 * u; ++ u64 along = read_reg(pispbe, offset); ++ ++ along += ((u64)read_reg(pispbe, offset + 4)) << 32; ++ if (along != (u64)(hw_dma_addrsu)) { ++ dev_err(pispbe->dev, ++ "ISP BE config error: check if ISP RAMs enabled?\n"); ++ return; ++ } ++ } ++ ++ /* ++ * Write tile pointer to hardware. XXX Tile offsets and sizes not ++ * checked (and even if checked, the user could subsequently modify ++ * them)! ++ */ ++ write_reg(pispbe, PISP_BE_TILE_ADDR_LO_OFFSET, (u32)tiles); ++ write_reg(pispbe, PISP_BE_TILE_ADDR_HI_OFFSET, (u32)(tiles >> 32)); ++ ++ /* Enqueue the job */ ++ write_reg(pispbe, PISP_BE_CONTROL_OFFSET, 3 + 65536 * num_tiles); ++} ++ ++struct pispbe_buffer { ++ struct vb2_v4l2_buffer vb; ++ struct list_head ready_list; ++ unsigned int config_index; ++}; ++ ++static int get_addr_3(dma_addr_t addr3, struct pispbe_buffer *buf, ++ struct pispbe_node *node) ++{ ++ unsigned int num_planes = node->format.fmt.pix_mp.num_planes; ++ unsigned int plane_factor = 0; ++ unsigned int size; ++ unsigned int p; ++ ++ if (!buf || !node->pisp_format) ++ return 0; ++ ++ WARN_ON(!NODE_IS_MPLANE(node)); ++ ++ /* ++ * Determine the base plane size. This will not be the same ++ * as node->format.fmt.pix_mp.plane_fmt0.sizeimage for a single ++ * plane buffer in an mplane format. ++ */ ++ size = node->format.fmt.pix_mp.plane_fmt0.bytesperline * ++ node->format.fmt.pix_mp.height; ++ ++ for (p = 0; p < num_planes && p < 3; p++) { ++ addrp = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, p); ++ plane_factor += node->pisp_format->plane_factorp; ++ } ++ ++ for (; p < MAX_PLANES && node->pisp_format->plane_factorp; p++) { ++ /* ++ * Calculate the address offset of this plane as needed ++ * by the hardware. This is specifically for non-mplane ++ * buffer formats, where there are 3 image planes, e.g. ++ * for the V4L2_PIX_FMT_YUV420 format. ++ */ ++ addrp = addr0 + ((size * plane_factor) >> 3); ++ plane_factor += node->pisp_format->plane_factorp; ++ } ++ ++ return num_planes; ++} ++ ++static dma_addr_t get_addr(struct pispbe_buffer *buf) ++{ ++ if (buf) ++ return vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); ++ return 0; ++} ++ ++static void ++fixup_addrs_enables(dma_addr_t addrsN_HW_ADDRESSES, ++ u32 hw_enablesN_HW_ENABLES, ++ struct pisp_be_tiles_config *config, ++ struct pispbe_buffer *bufPISPBE_NUM_NODES, ++ struct pispbe_node_group *node_group) ++{ ++ int ret, i; ++ ++ /* Take a copy of the "enable" bitmaps so we can modify them. */ ++ hw_enables0 = config->config.global.bayer_enables; ++ hw_enables1 = config->config.global.rgb_enables; ++ ++ /* ++ * Main input first. There are 3 address pointers, corresponding to up ++ * to 3 planes. ++ */ ++ ret = get_addr_3(addrs, bufMAIN_INPUT_NODE, ++ &node_group->nodeMAIN_INPUT_NODE); ++ if (ret <= 0) { ++ /* ++ * This shouldn't happen; pispbe_schedule_internal should insist ++ * on an input. ++ */ ++ dev_warn(node_group->pispbe->dev, ++ "ISP-BE missing input\n"); ++ hw_enables0 = 0; ++ hw_enables1 = 0; ++ return; ++ } ++ ++ /* ++ * Now TDN/Stitch inputs and outputs. These are single-plane and only ++ * used with Bayer input. Input enables must match the requirements ++ * of the processing stages, otherwise the hardware can lock up! ++ */ ++ if (hw_enables0 & PISP_BE_BAYER_ENABLE_INPUT) { ++ addrs3 = get_addr(bufTDN_INPUT_NODE); ++ if (addrs3 == 0 || ++ !(hw_enables0 & PISP_BE_BAYER_ENABLE_TDN_INPUT) || ++ !(hw_enables0 & PISP_BE_BAYER_ENABLE_TDN) || ++ (config->config.tdn.reset & 1)) { ++ hw_enables0 &= ~(PISP_BE_BAYER_ENABLE_TDN_INPUT | ++ PISP_BE_BAYER_ENABLE_TDN_DECOMPRESS); ++ if (!(config->config.tdn.reset & 1)) ++ hw_enables0 &= ~PISP_BE_BAYER_ENABLE_TDN; ++ } ++ ++ addrs4 = get_addr(bufSTITCH_INPUT_NODE); ++ if (addrs4 == 0 || ++ !(hw_enables0 & PISP_BE_BAYER_ENABLE_STITCH_INPUT) || ++ !(hw_enables0 & PISP_BE_BAYER_ENABLE_STITCH)) { ++ hw_enables0 &= ++ ~(PISP_BE_BAYER_ENABLE_STITCH_INPUT | ++ PISP_BE_BAYER_ENABLE_STITCH_DECOMPRESS | ++ PISP_BE_BAYER_ENABLE_STITCH); ++ } ++ ++ addrs5 = get_addr(bufTDN_OUTPUT_NODE); ++ if (addrs5 == 0) ++ hw_enables0 &= ~(PISP_BE_BAYER_ENABLE_TDN_COMPRESS | ++ PISP_BE_BAYER_ENABLE_TDN_OUTPUT); ++ ++ addrs6 = get_addr(bufSTITCH_OUTPUT_NODE); ++ if (addrs6 == 0) ++ hw_enables0 &= ++ ~(PISP_BE_BAYER_ENABLE_STITCH_COMPRESS | ++ PISP_BE_BAYER_ENABLE_STITCH_OUTPUT); ++ } else { ++ /* No Bayer input? Disable entire Bayer pipe (else lockup) */ ++ hw_enables0 = 0; ++ } ++ ++ /* Main image output channels. */ ++ for (i = 0; i < PISP_BACK_END_NUM_OUTPUTS; i++) { ++ ret = get_addr_3(addrs + 7 + 3 * i, bufOUTPUT0_NODE + i, ++ &node_group->nodeOUTPUT0_NODE + i); ++ if (ret <= 0) ++ hw_enables1 &= ~(PISP_BE_RGB_ENABLE_OUTPUT0 << i); ++ } ++ ++ /* HoG output (always single plane). */ ++ addrs13 = get_addr(bufHOG_OUTPUT_NODE); ++ if (addrs13 == 0) ++ hw_enables1 &= ~PISP_BE_RGB_ENABLE_HOG; ++} ++ ++/* ++ * Internal function. Called from pispbe_schedule_one/all. Returns non-zero if ++ * we started a job. ++ * ++ * Warning: needs to be called with hw_lock taken, and releases it if it ++ * schedules a job. ++ */ ++static int pispbe_schedule_internal(struct pispbe_node_group *node_group, ++ unsigned long flags) ++{ ++ struct pisp_be_tiles_config *config_tiles_buffer; ++ struct pispbe_dev *pispbe = node_group->pispbe; ++ struct pispbe_buffer *bufPISPBE_NUM_NODES; ++ dma_addr_t hw_dma_addrsN_HW_ADDRESSES; ++ dma_addr_t tiles; ++ u32 hw_enablesN_HW_ENABLES; ++ struct pispbe_node *node; ++ unsigned long flags1; ++ unsigned int config_index; ++ int i; ++ ++ /* ++ * To schedule a job, we need all streaming nodes (apart from Output0, ++ * Output1, Tdn and Stitch) to have a buffer ready, which must ++ * include at least a config buffer and a main input image. ++ * ++ * For Output0, Output1, Tdn and Stitch, a buffer only needs to be ++ * available if the blocks are enabled in the config. ++ * ++ * (Note that streaming_map is protected by hw_lock, which is held.) ++ */ ++ if (((BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE)) & ++ node_group->streaming_map) != ++ (BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE))) { ++ dev_dbg(pispbe->dev, "Nothing to do\n"); ++ return 0; ++ } ++ ++ node = &node_group->nodeCONFIG_NODE; ++ spin_lock_irqsave(&node->ready_lock, flags1); ++ bufCONFIG_NODE = ++ list_first_entry_or_null(&node->ready_queue, struct pispbe_buffer, ++ ready_list); ++ spin_unlock_irqrestore(&node->ready_lock, flags1); ++ ++ /* Exit early if no config buffer has been queued. */ ++ if (!bufCONFIG_NODE) ++ return 0; ++ ++ config_index = bufCONFIG_NODE->vb.vb2_buf.index; ++ config_tiles_buffer = &node_group->configconfig_index; ++ tiles = (dma_addr_t)node_group->config_dma_addr + ++ config_index * sizeof(struct pisp_be_tiles_config) + ++ offsetof(struct pisp_be_tiles_config, tiles); ++ ++ /* remember: srcimages, captures then metadata */ ++ for (i = 0; i < PISPBE_NUM_NODES; i++) { ++ unsigned int bayer_en = ++ config_tiles_buffer->config.global.bayer_enables; ++ unsigned int rgb_en = ++ config_tiles_buffer->config.global.rgb_enables; ++ bool ignore_buffers = false; ++ ++ /* Config node is handled outside the loop above. */ ++ if (i == CONFIG_NODE) ++ continue; ++ ++ bufi = NULL; ++ if (!(node_group->streaming_map & BIT(i))) ++ continue; ++ ++ if ((!(rgb_en & PISP_BE_RGB_ENABLE_OUTPUT0) && ++ i == OUTPUT0_NODE) || ++ (!(rgb_en & PISP_BE_RGB_ENABLE_OUTPUT1) && ++ i == OUTPUT1_NODE) || ++ (!(bayer_en & PISP_BE_BAYER_ENABLE_TDN_INPUT) && ++ i == TDN_INPUT_NODE) || ++ (!(bayer_en & PISP_BE_BAYER_ENABLE_TDN_OUTPUT) && ++ i == TDN_OUTPUT_NODE) || ++ (!(bayer_en & PISP_BE_BAYER_ENABLE_STITCH_INPUT) && ++ i == STITCH_INPUT_NODE) || ++ (!(bayer_en & PISP_BE_BAYER_ENABLE_STITCH_OUTPUT) && ++ i == STITCH_OUTPUT_NODE)) { ++ /* ++ * Ignore Output0/Output1/Tdn/Stitch buffer check if the ++ * global enables aren't set for these blocks. If a ++ * buffer has been provided, we dequeue it back to the ++ * user with the other in-use buffers. ++ * ++ */ ++ ignore_buffers = true; ++ } ++ ++ node = &node_group->nodei; ++ ++ spin_lock_irqsave(&node->ready_lock, flags1); ++ bufi = list_first_entry_or_null(&node->ready_queue, ++ struct pispbe_buffer, ++ ready_list); ++ spin_unlock_irqrestore(&node->ready_lock, flags1); ++ if (!bufi && !ignore_buffers) { ++ dev_dbg(pispbe->dev, "Nothing to do\n"); ++ return 0; ++ } ++ } ++ ++ /* Pull a buffer from each V4L2 queue to form the queued job */ ++ for (i = 0; i < PISPBE_NUM_NODES; i++) { ++ if (bufi) { ++ node = &node_group->nodei; ++ ++ spin_lock_irqsave(&node->ready_lock, flags1); ++ list_del(&bufi->ready_list); ++ spin_unlock_irqrestore(&node->ready_lock, ++ flags1); ++ } ++ pispbe->queued_job.bufi = bufi; ++ } ++ ++ pispbe->queued_job.node_group = node_group; ++ pispbe->hw_busy = 1; ++ spin_unlock_irqrestore(&pispbe->hw_lock, flags); ++ ++ /* ++ * We can kick the job off without the hw_lock, as this can ++ * never run again until hw_busy is cleared, which will happen ++ * only when the following job has been queued. ++ */ ++ dev_dbg(pispbe->dev, "Have buffers - starting hardware\n"); ++ ++ /* Convert buffers to DMA addresses for the hardware */ ++ fixup_addrs_enables(hw_dma_addrs, hw_enables, ++ config_tiles_buffer, buf, node_group); ++ /* ++ * This could be a spot to fill in the ++ * bufi->vb.vb2_buf.planesj.bytesused fields? ++ */ ++ i = config_tiles_buffer->num_tiles; ++ if (i <= 0 || i > PISP_BACK_END_NUM_TILES || ++ !((hw_enables0 | hw_enables1) & ++ PISP_BE_BAYER_ENABLE_INPUT)) { ++ /* ++ * Bad job. We can't let it proceed as it could lock up ++ * the hardware, or worse! ++ * ++ * XXX How to deal with this most cleanly? For now, just ++ * force num_tiles to 0, which causes the H/W to do ++ * something bizarre but survivable. It increments ++ * (started,done) counters by more than 1, but we seem ++ * to survive... ++ */ ++ dev_err(pispbe->dev, "PROBLEM: Bad job"); ++ i = 0; ++ } ++ hw_queue_job(pispbe, hw_dma_addrs, hw_enables, ++ &config_tiles_buffer->config, tiles, i); ++ ++ return 1; ++} ++ ++/* Try and schedule a job for just a single node group. */ ++static void pispbe_schedule_one(struct pispbe_node_group *node_group) ++{ ++ struct pispbe_dev *pispbe = node_group->pispbe; ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&pispbe->hw_lock, flags); ++ if (pispbe->hw_busy) { ++ spin_unlock_irqrestore(&pispbe->hw_lock, flags); ++ return; ++ } ++ ++ /* A non-zero return means the lock was released. */ ++ ret = pispbe_schedule_internal(node_group, flags); ++ if (!ret) ++ spin_unlock_irqrestore(&pispbe->hw_lock, flags); ++} ++ ++/* Try and schedule a job for any of the node groups. */ ++static void pispbe_schedule_any(struct pispbe_dev *pispbe, int clear_hw_busy) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pispbe->hw_lock, flags); ++ ++ if (clear_hw_busy) ++ pispbe->hw_busy = 0; ++ if (pispbe->hw_busy == 0) { ++ unsigned int i; ++ ++ for (i = 0; i < PISPBE_NUM_NODE_GROUPS; i++) { ++ /* ++ * A non-zero return from pispbe_schedule_internal means ++ * the lock was released. ++ */ ++ if (pispbe_schedule_internal(&pispbe->node_groupi, ++ flags)) ++ return; ++ } ++ } ++ spin_unlock_irqrestore(&pispbe->hw_lock, flags); ++} ++ ++static void pispbe_isr_jobdone(struct pispbe_dev *pispbe, ++ struct pispbe_job *job) ++{ ++ struct pispbe_buffer **buf = job->buf; ++ u64 ts = ktime_get_ns(); ++ int i; ++ ++ for (i = 0; i < PISPBE_NUM_NODES; i++) { ++ if (bufi) { ++ bufi->vb.vb2_buf.timestamp = ts; ++ bufi->vb.sequence = job->node_group->sequence; ++ vb2_buffer_done(&bufi->vb.vb2_buf, ++ VB2_BUF_STATE_DONE); ++ } ++ } ++ ++ job->node_group->sequence++; ++} ++ ++static irqreturn_t pispbe_isr(int irq, void *dev) ++{ ++ struct pispbe_dev *pispbe = (struct pispbe_dev *)dev; ++ u8 started, done; ++ int can_queue_another = 0; ++ u32 u; ++ ++ u = read_reg(pispbe, PISP_BE_INTERRUPT_STATUS_OFFSET); ++ if (u == 0) ++ return IRQ_NONE; ++ ++ write_reg(pispbe, PISP_BE_INTERRUPT_STATUS_OFFSET, u); ++ dev_dbg(pispbe->dev, "Hardware interrupt\n"); ++ u = read_reg(pispbe, PISP_BE_BATCH_STATUS_OFFSET); ++ done = (uint8_t)u; ++ started = (uint8_t)(u >> 8); ++ dev_dbg(pispbe->dev, ++ "H/W started %d done %d, previously started %d done %d\n", ++ (int)started, (int)done, (int)pispbe->started, ++ (int)pispbe->done); ++ ++ /* ++ * Be aware that done can go up by 2 and started by 1 when: a job that ++ * we previously saw "start" now finishes, and we then queued a new job ++ * which we see both start and finish "simultaneously". ++ */ ++ if (pispbe->running_job.node_group && pispbe->done != done) { ++ pispbe_isr_jobdone(pispbe, &pispbe->running_job); ++ memset(&pispbe->running_job, 0, sizeof(pispbe->running_job)); ++ pispbe->done++; ++ dev_dbg(pispbe->dev, "Job done (1)\n"); ++ } ++ ++ if (pispbe->started != started) { ++ pispbe->started++; ++ can_queue_another = 1; ++ dev_dbg(pispbe->dev, "Job started\n"); ++ ++ if (pispbe->done != done && pispbe->queued_job.node_group) { ++ pispbe_isr_jobdone(pispbe, &pispbe->queued_job); ++ pispbe->done++; ++ dev_dbg(pispbe->dev, "Job done (2)\n"); ++ } else { ++ pispbe->running_job = pispbe->queued_job; ++ } ++ ++ memset(&pispbe->queued_job, 0, sizeof(pispbe->queued_job)); ++ } ++ ++ if (pispbe->done != done || pispbe->started != started) { ++ dev_err(pispbe->dev, "PROBLEM: counters not matching!\n"); ++ pispbe->started = started; ++ pispbe->done = done; ++ } ++ ++ /* check if there's more to do before going to sleep */ ++ pispbe_schedule_any(pispbe, can_queue_another); ++ ++ return IRQ_HANDLED; ++} ++ ++static int pisp_be_validate_config(struct pispbe_node_group *node_group, ++ struct pisp_be_tiles_config *config) ++{ ++ u32 bayer_enables = config->config.global.bayer_enables; ++ u32 rgb_enables = config->config.global.rgb_enables; ++ struct device *dev = node_group->pispbe->dev; ++ struct v4l2_format *fmt; ++ unsigned int bpl, size, i, j; ++ ++ if (!(bayer_enables & PISP_BE_BAYER_ENABLE_INPUT) == ++ !(rgb_enables & PISP_BE_RGB_ENABLE_INPUT)) { ++ dev_err(dev, "%s: Not one input enabled\n", __func__); ++ return -EIO; ++ } ++ ++ /* Ensure output config strides and buffer sizes match the V4L2 formats. */ ++ fmt = &node_group->nodeTDN_OUTPUT_NODE.format; ++ if (bayer_enables & PISP_BE_BAYER_ENABLE_TDN_OUTPUT) { ++ bpl = config->config.tdn_output_format.stride; ++ size = bpl * config->config.tdn_output_format.height; ++ if (fmt->fmt.pix_mp.plane_fmt0.bytesperline < bpl) { ++ dev_err(dev, "%s: bpl mismatch on tdn_output\n", ++ __func__); ++ return -EINVAL; ++ } ++ if (fmt->fmt.pix_mp.plane_fmt0.sizeimage < size) { ++ dev_err(dev, "%s: size mismatch on tdn_output\n", ++ __func__); ++ return -EINVAL; ++ } ++ } ++ ++ fmt = &node_group->nodeSTITCH_OUTPUT_NODE.format; ++ if (bayer_enables & PISP_BE_BAYER_ENABLE_STITCH_OUTPUT) { ++ bpl = config->config.stitch_output_format.stride; ++ size = bpl * config->config.stitch_output_format.height; ++ if (fmt->fmt.pix_mp.plane_fmt0.bytesperline < bpl) { ++ dev_err(dev, "%s: bpl mismatch on stitch_output\n", ++ __func__); ++ return -EINVAL; ++ } ++ if (fmt->fmt.pix_mp.plane_fmt0.sizeimage < size) { ++ dev_err(dev, "%s: size mismatch on stitch_output\n", ++ __func__); ++ return -EINVAL; ++ } ++ } ++ ++ for (j = 0; j < PISP_BACK_END_NUM_OUTPUTS; j++) { ++ if (!(rgb_enables & PISP_BE_RGB_ENABLE_OUTPUT(j))) ++ continue; ++ if (config->config.output_formatj.image.format & ++ PISP_IMAGE_FORMAT_WALLPAPER_ROLL) ++ continue; /* TODO: Size checks for wallpaper formats */ ++ ++ fmt = &node_group->nodeOUTPUT0_NODE + j.format; ++ for (i = 0; i < fmt->fmt.pix_mp.num_planes; i++) { ++ bpl = !i ? config->config.output_formatj.image.stride ++ : config->config.output_formatj.image.stride2; ++ size = bpl * config->config.output_formatj.image.height; ++ ++ if (config->config.output_formatj.image.format & ++ PISP_IMAGE_FORMAT_SAMPLING_420) ++ size >>= 1; ++ if (fmt->fmt.pix_mp.plane_fmti.bytesperline < bpl) { ++ dev_err(dev, "%s: bpl mismatch on output %d\n", ++ __func__, j); ++ return -EINVAL; ++ } ++ if (fmt->fmt.pix_mp.plane_fmti.sizeimage < size) { ++ dev_err(dev, "%s: size mismatch on output\n", ++ __func__); ++ return -EINVAL; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int pispbe_node_queue_setup(struct vb2_queue *q, unsigned int *nbuffers, ++ unsigned int *nplanes, unsigned int sizes, ++ struct device *alloc_devs) ++{ ++ struct pispbe_node *node = vb2_get_drv_priv(q); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ *nplanes = 1; ++ if (NODE_IS_MPLANE(node)) { ++ unsigned int i; ++ ++ *nplanes = node->format.fmt.pix_mp.num_planes; ++ for (i = 0; i < *nplanes; i++) { ++ unsigned int size = ++ node->format.fmt.pix_mp.plane_fmti.sizeimage; ++ if (sizesi && sizesi < size) { ++ dev_err(pispbe->dev, "%s: size %u < %u\n", ++ __func__, sizesi, size); ++ return -EINVAL; ++ } ++ sizesi = size; ++ } ++ } else if (NODE_IS_META(node)) { ++ sizes0 = node->format.fmt.meta.buffersize; ++ /* ++ * Limit the config node buffer count to the number of internal ++ * buffers allocated. ++ */ ++ if (node->id == CONFIG_NODE) ++ *nbuffers = min_t(unsigned int, *nbuffers, ++ PISP_BE_NUM_CONFIG_BUFFERS); ++ } ++ ++ dev_dbg(pispbe->dev, ++ "Image (or metadata) size %u, nbuffers %u for node %s\n", ++ sizes0, *nbuffers, NODE_NAME(node)); ++ ++ return 0; ++} ++ ++static int pispbe_node_buffer_prepare(struct vb2_buffer *vb) ++{ ++ struct pispbe_node *node = vb2_get_drv_priv(vb->vb2_queue); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ unsigned long size = 0; ++ unsigned int num_planes = NODE_IS_MPLANE(node) ? ++ node->format.fmt.pix_mp.num_planes : 1; ++ unsigned int i; ++ ++ for (i = 0; i < num_planes; i++) { ++ size = NODE_IS_MPLANE(node) ++ ? node->format.fmt.pix_mp.plane_fmti.sizeimage ++ : node->format.fmt.meta.buffersize; ++ ++ if (vb2_plane_size(vb, i) < size) { ++ dev_err(pispbe->dev, ++ "data will not fit into plane %d (%lu < %lu)\n", ++ i, vb2_plane_size(vb, i), size); ++ return -EINVAL; ++ } ++ ++ vb2_set_plane_payload(vb, i, size); ++ } ++ ++ if (node->id == CONFIG_NODE) { ++ void *dst = &node->node_group->configvb->index; ++ void *src = vb2_plane_vaddr(vb, 0); ++ ++ memcpy(dst, src, sizeof(struct pisp_be_tiles_config)); ++ return pisp_be_validate_config(node->node_group, dst); ++ } ++ ++ return 0; ++} ++ ++static void pispbe_node_buffer_queue(struct vb2_buffer *buf) ++{ ++ struct vb2_v4l2_buffer *vbuf = ++ container_of(buf, struct vb2_v4l2_buffer, vb2_buf); ++ struct pispbe_buffer *buffer = ++ container_of(vbuf, struct pispbe_buffer, vb); ++ struct pispbe_node *node = vb2_get_drv_priv(buf->vb2_queue); ++ struct pispbe_node_group *node_group = node->node_group; ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ unsigned long flags; ++ ++ dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node)); ++ spin_lock_irqsave(&node->ready_lock, flags); ++ list_add_tail(&buffer->ready_list, &node->ready_queue); ++ spin_unlock_irqrestore(&node->ready_lock, flags); ++ ++ /* ++ * Every time we add a buffer, check if there's now some work for the hw ++ * to do, but only for this client. ++ */ ++ pispbe_schedule_one(node_group); ++} ++ ++static int pispbe_node_start_streaming(struct vb2_queue *q, unsigned int count) ++{ ++ unsigned long flags; ++ struct pispbe_node *node = vb2_get_drv_priv(q); ++ struct pispbe_node_group *node_group = node->node_group; ++ struct pispbe_dev *pispbe = node_group->pispbe; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(pispbe->dev); ++ if (ret < 0) ++ return ret; ++ ++ spin_lock_irqsave(&pispbe->hw_lock, flags); ++ node->node_group->streaming_map |= BIT(node->id); ++ node->node_group->sequence = 0; ++ spin_unlock_irqrestore(&pispbe->hw_lock, flags); ++ ++ dev_dbg(pispbe->dev, "%s: for node %s (count %u)\n", ++ __func__, NODE_NAME(node), count); ++ dev_dbg(pispbe->dev, "Nodes streaming for this group now 0x%x\n", ++ node->node_group->streaming_map); ++ ++ /* Maybe we're ready to run. */ ++ pispbe_schedule_one(node_group); ++ ++ return 0; ++} ++ ++static void pispbe_node_stop_streaming(struct vb2_queue *q) ++{ ++ struct pispbe_node *node = vb2_get_drv_priv(q); ++ struct pispbe_node_group *node_group = node->node_group; ++ struct pispbe_dev *pispbe = node_group->pispbe; ++ struct pispbe_buffer *buf; ++ unsigned long flags; ++ ++ /* ++ * Now this is a bit awkward. In a simple M2M device we could just wait ++ * for all queued jobs to complete, but here there's a risk that a ++ * partial set of buffers was queued and cannot be run. For now, just ++ * cancel all buffers stuck in the "ready queue", then wait for any ++ * running job. ++ * XXX This may return buffers out of order. ++ */ ++ dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node)); ++ spin_lock_irqsave(&pispbe->hw_lock, flags); ++ do { ++ unsigned long flags1; ++ ++ spin_lock_irqsave(&node->ready_lock, flags1); ++ buf = list_first_entry_or_null(&node->ready_queue, ++ struct pispbe_buffer, ++ ready_list); ++ if (buf) { ++ list_del(&buf->ready_list); ++ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); ++ } ++ spin_unlock_irqrestore(&node->ready_lock, flags1); ++ } while (buf); ++ spin_unlock_irqrestore(&pispbe->hw_lock, flags); ++ ++ vb2_wait_for_all_buffers(&node->queue); ++ ++ spin_lock_irqsave(&pispbe->hw_lock, flags); ++ node_group->streaming_map &= ~BIT(node->id); ++ spin_unlock_irqrestore(&pispbe->hw_lock, flags); ++ ++ pm_runtime_mark_last_busy(pispbe->dev); ++ pm_runtime_put_autosuspend(pispbe->dev); ++ ++ dev_dbg(pispbe->dev, "Nodes streaming for this group now 0x%x\n", ++ node_group->streaming_map); ++} ++ ++static const struct vb2_ops pispbe_node_queue_ops = { ++ .queue_setup = pispbe_node_queue_setup, ++ .buf_prepare = pispbe_node_buffer_prepare, ++ .buf_queue = pispbe_node_buffer_queue, ++ .start_streaming = pispbe_node_start_streaming, ++ .stop_streaming = pispbe_node_stop_streaming, ++}; ++ ++static const struct v4l2_file_operations pispbe_fops = { ++ .owner = THIS_MODULE, ++ .open = v4l2_fh_open, ++ .release = vb2_fop_release, ++ .poll = vb2_fop_poll, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = vb2_fop_mmap ++}; ++ ++static int pispbe_node_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ strscpy(cap->driver, PISPBE_NAME, sizeof(cap->driver)); ++ strscpy(cap->card, PISPBE_NAME, sizeof(cap->card)); ++ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", ++ dev_name(pispbe->dev)); ++ ++ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE | ++ V4L2_CAP_VIDEO_OUTPUT_MPLANE | ++ V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS | ++ V4L2_CAP_META_OUTPUT | V4L2_CAP_META_CAPTURE; ++ cap->device_caps = node->vfd.device_caps; ++ ++ dev_dbg(pispbe->dev, "Caps for node %s: %x and %x (dev %x)\n", ++ NODE_NAME(node), cap->capabilities, cap->device_caps, ++ node->vfd.device_caps); ++ return 0; ++} ++ ++static int pispbe_node_g_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ if (!NODE_IS_CAPTURE(node) || NODE_IS_META(node)) { ++ dev_err(pispbe->dev, ++ "Cannot get capture fmt for output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ *f = node->format; ++ dev_dbg(pispbe->dev, "Get capture format for node %s\n", ++ NODE_NAME(node)); ++ return 0; ++} ++ ++static int pispbe_node_g_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ if (NODE_IS_CAPTURE(node) || NODE_IS_META(node)) { ++ dev_err(pispbe->dev, ++ "Cannot get capture fmt for output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ *f = node->format; ++ dev_dbg(pispbe->dev, "Get output format for node %s\n", ++ NODE_NAME(node)); ++ return 0; ++} ++ ++static int pispbe_node_g_fmt_meta_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ if (!NODE_IS_META(node) || NODE_IS_CAPTURE(node)) { ++ dev_err(pispbe->dev, ++ "Cannot get capture fmt for meta output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ *f = node->format; ++ dev_dbg(pispbe->dev, "Get output format for meta node %s\n", ++ NODE_NAME(node)); ++ return 0; ++} ++ ++static int pispbe_node_g_fmt_meta_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ if (!NODE_IS_META(node) || NODE_IS_OUTPUT(node)) { ++ dev_err(pispbe->dev, ++ "Cannot get capture fmt for meta output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ *f = node->format; ++ dev_dbg(pispbe->dev, "Get output format for meta node %s\n", ++ NODE_NAME(node)); ++ return 0; ++} ++ ++static int verify_be_pix_format(const struct v4l2_format *f, ++ struct pispbe_node *node) ++{ ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ unsigned int nplanes = f->fmt.pix_mp.num_planes; ++ unsigned int i; ++ ++ if (f->fmt.pix_mp.width == 0 || f->fmt.pix_mp.height == 0) { ++ dev_err(pispbe->dev, "Details incorrect for output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ ++ if (nplanes == 0 || nplanes > MAX_PLANES) { ++ dev_err(pispbe->dev, ++ "Bad number of planes for output node %s, req =%d\n", ++ NODE_NAME(node), nplanes); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < nplanes; i++) { ++ const struct v4l2_plane_pix_format *p; ++ ++ p = &f->fmt.pix_mp.plane_fmti; ++ if (p->bytesperline == 0 || p->sizeimage == 0) { ++ dev_err(pispbe->dev, ++ "Invalid plane %d for output node %s\n", ++ i, NODE_NAME(node)); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static const struct pisp_be_format *find_format(unsigned int fourcc) ++{ ++ const struct pisp_be_format *fmt; ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(supported_formats); i++) { ++ fmt = &supported_formatsi; ++ if (fmt->fourcc == fourcc) ++ return fmt; ++ } ++ ++ return NULL; ++} ++ ++static void set_plane_params(struct v4l2_format *f, ++ const struct pisp_be_format *fmt) ++{ ++ unsigned int nplanes = f->fmt.pix_mp.num_planes; ++ unsigned int total_plane_factor = 0; ++ unsigned int i; ++ ++ for (i = 0; i < MAX_PLANES; i++) ++ total_plane_factor += fmt->plane_factori; ++ ++ for (i = 0; i < nplanes; i++) { ++ struct v4l2_plane_pix_format *p = &f->fmt.pix_mp.plane_fmti; ++ unsigned int bpl, plane_size; ++ ++ bpl = (f->fmt.pix_mp.width * fmt->bit_depth) >> 3; ++ bpl = ALIGN(max(p->bytesperline, bpl), fmt->align); ++ ++ plane_size = bpl * f->fmt.pix_mp.height * ++ (nplanes > 1 ? fmt->plane_factori : total_plane_factor); ++ /* ++ * The shift is to divide out the plane_factor fixed point ++ * scaling of 8. ++ */ ++ plane_size = max(p->sizeimage, plane_size >> 3); ++ ++ p->bytesperline = bpl; ++ p->sizeimage = plane_size; ++ } ++} ++ ++static int try_format(struct v4l2_format *f, struct pispbe_node *node) ++{ ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ const struct pisp_be_format *fmt; ++ unsigned int i; ++ bool is_rgb; ++ u32 pixfmt = f->fmt.pix_mp.pixelformat; ++ ++ dev_dbg(pispbe->dev, ++ "%s: %s req %ux%u " V4L2_FOURCC_CONV ", planes %d\n", ++ __func__, NODE_NAME(node), f->fmt.pix_mp.width, ++ f->fmt.pix_mp.height, V4L2_FOURCC_CONV_ARGS(pixfmt), ++ f->fmt.pix_mp.num_planes); ++ ++ if (pixfmt == V4L2_PIX_FMT_RPI_BE) ++ return verify_be_pix_format(f, node); ++ ++ fmt = find_format(pixfmt); ++ if (!fmt) { ++ dev_dbg(pispbe->dev, "%s: %s Format not found, defaulting to YUV420\n", ++ __func__, NODE_NAME(node)); ++ fmt = find_format(V4L2_PIX_FMT_YUV420); ++ } ++ ++ f->fmt.pix_mp.pixelformat = fmt->fourcc; ++ f->fmt.pix_mp.num_planes = fmt->num_planes; ++ f->fmt.pix_mp.field = V4L2_FIELD_NONE; ++ f->fmt.pix_mp.width = max(min(f->fmt.pix_mp.width, 65536u), ++ PISP_BACK_END_MIN_TILE_WIDTH); ++ f->fmt.pix_mp.height = max(min(f->fmt.pix_mp.height, 65536u), ++ PISP_BACK_END_MIN_TILE_HEIGHT); ++ ++ /* ++ * Fill in the actual colour space when the requested one was ++ * not supported. This also catches the case when the "default" ++ * colour space was requested (as that's never in the mask). ++ */ ++ if (!(V4L2_COLORSPACE_MASK(f->fmt.pix_mp.colorspace) & fmt->colorspace_mask)) ++ f->fmt.pix_mp.colorspace = fmt->colorspace_default; ++ ++ /* In all cases, we only support the defaults for these: */ ++ f->fmt.pix_mp.ycbcr_enc = ++ V4L2_MAP_YCBCR_ENC_DEFAULT(f->fmt.pix_mp.colorspace); ++ f->fmt.pix_mp.xfer_func = ++ V4L2_MAP_XFER_FUNC_DEFAULT(f->fmt.pix_mp.colorspace); ++ ++ is_rgb = f->fmt.pix_mp.colorspace == V4L2_COLORSPACE_SRGB; ++ f->fmt.pix_mp.quantization = ++ V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb, f->fmt.pix_mp.colorspace, ++ f->fmt.pix_mp.ycbcr_enc); ++ ++ /* Set plane size and bytes/line for each plane. */ ++ set_plane_params(f, fmt); ++ ++ for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { ++ dev_dbg(pispbe->dev, ++ "%s: %s calc plane %d, %ux%u, depth %u, bpl %u size %u\n", ++ __func__, NODE_NAME(node), i, f->fmt.pix_mp.width, ++ f->fmt.pix_mp.height, fmt->bit_depth, ++ f->fmt.pix_mp.plane_fmti.bytesperline, ++ f->fmt.pix_mp.plane_fmti.sizeimage); ++ } ++ ++ return 0; ++} ++ ++static int pispbe_node_try_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ int ret; ++ ++ if (!NODE_IS_CAPTURE(node) || NODE_IS_META(node)) { ++ dev_err(pispbe->dev, ++ "Cannot set capture fmt for output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ ++ ret = try_format(f, node); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int pispbe_node_try_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ int ret; ++ ++ if (!NODE_IS_OUTPUT(node) || NODE_IS_META(node)) { ++ dev_err(pispbe->dev, ++ "Cannot set capture fmt for output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ ++ ret = try_format(f, node); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int pispbe_node_try_fmt_meta_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ if (!NODE_IS_META(node) || NODE_IS_CAPTURE(node)) { ++ dev_err(pispbe->dev, ++ "Cannot set capture fmt for meta output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ ++ f->fmt.meta.dataformat = V4L2_META_FMT_RPI_BE_CFG; ++ f->fmt.meta.buffersize = sizeof(struct pisp_be_tiles_config); ++ ++ return 0; ++} ++ ++static int pispbe_node_try_fmt_meta_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ if (!NODE_IS_META(node) || NODE_IS_OUTPUT(node)) { ++ dev_err(pispbe->dev, ++ "Cannot set capture fmt for meta output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ ++ f->fmt.meta.dataformat = V4L2_PIX_FMT_RPI_BE; ++ if (!f->fmt.meta.buffersize) ++ f->fmt.meta.buffersize = BIT(20); ++ ++ return 0; ++} ++ ++static int pispbe_node_s_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ int ret = pispbe_node_try_fmt_vid_cap(file, priv, f); ++ ++ if (ret < 0) ++ return ret; ++ ++ node->format = *f; ++ node->pisp_format = find_format(f->fmt.pix_mp.pixelformat); ++ ++ dev_dbg(pispbe->dev, ++ "Set capture format for node %s to " V4L2_FOURCC_CONV "\n", ++ NODE_NAME(node), ++ V4L2_FOURCC_CONV_ARGS(f->fmt.pix_mp.pixelformat)); ++ return 0; ++} ++ ++static int pispbe_node_s_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ int ret = pispbe_node_try_fmt_vid_out(file, priv, f); ++ ++ if (ret < 0) ++ return ret; ++ ++ node->format = *f; ++ node->pisp_format = find_format(f->fmt.pix_mp.pixelformat); ++ ++ dev_dbg(pispbe->dev, ++ "Set output format for node %s to " V4L2_FOURCC_CONV "\n", ++ NODE_NAME(node), ++ V4L2_FOURCC_CONV_ARGS(f->fmt.pix_mp.pixelformat)); ++ return 0; ++} ++ ++static int pispbe_node_s_fmt_meta_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ int ret = pispbe_node_try_fmt_meta_out(file, priv, f); ++ ++ if (ret < 0) ++ return ret; ++ ++ node->format = *f; ++ node->pisp_format = &meta_out_supported_formats0; ++ ++ dev_dbg(pispbe->dev, ++ "Set output format for meta node %s to " V4L2_FOURCC_CONV "\n", ++ NODE_NAME(node), ++ V4L2_FOURCC_CONV_ARGS(f->fmt.meta.dataformat)); ++ return 0; ++} ++ ++static int pispbe_node_s_fmt_meta_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ int ret = pispbe_node_try_fmt_meta_cap(file, priv, f); ++ ++ if (ret < 0) ++ return ret; ++ ++ node->format = *f; ++ node->pisp_format = find_format(f->fmt.meta.dataformat); ++ ++ dev_dbg(pispbe->dev, ++ "Set capture format for meta node %s to " V4L2_FOURCC_CONV "\n", ++ NODE_NAME(node), ++ V4L2_FOURCC_CONV_ARGS(f->fmt.meta.dataformat)); ++ return 0; ++} ++ ++static int pispbe_node_enum_fmt(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ ++ if (f->type != node->queue.type) ++ return -EINVAL; ++ ++ if (NODE_IS_META(node)) { ++ if (f->index) ++ return -EINVAL; ++ ++ if (NODE_IS_OUTPUT(node)) ++ f->pixelformat = V4L2_META_FMT_RPI_BE_CFG; ++ else ++ f->pixelformat = V4L2_PIX_FMT_RPI_BE; ++ f->flags = 0; ++ return 0; ++ } ++ ++ if (f->index >= ARRAY_SIZE(supported_formats)) ++ return -EINVAL; ++ ++ f->pixelformat = supported_formatsf->index.fourcc; ++ f->flags = 0; ++ ++ return 0; ++} ++ ++static int pispbe_enum_framesizes(struct file *file, void *priv, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ if (NODE_IS_META(node) || fsize->index) ++ return -EINVAL; ++ ++ if (!find_format(fsize->pixel_format)) { ++ dev_err(pispbe->dev, "Invalid pixel code: %x\n", ++ fsize->pixel_format); ++ return -EINVAL; ++ } ++ ++ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; ++ fsize->stepwise.min_width = 32; ++ fsize->stepwise.max_width = 65535; ++ fsize->stepwise.step_width = 2; ++ ++ fsize->stepwise.min_height = 32; ++ fsize->stepwise.max_height = 65535; ++ fsize->stepwise.step_height = 2; ++ ++ return 0; ++} ++ ++static int pispbe_node_streamon(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ /* Do we need a node->stream_lock mutex? */ ++ ++ dev_dbg(pispbe->dev, "Stream on for node %s\n", NODE_NAME(node)); ++ ++ /* Do we care about the type? Each node has only one queue. */ ++ ++ INIT_LIST_HEAD(&node->ready_queue); ++ ++ /* locking should be handled by the queue->lock? */ ++ return vb2_streamon(&node->queue, type); ++} ++ ++static int pispbe_node_streamoff(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ ++ return vb2_streamoff(&node->queue, type); ++} ++ ++static const struct v4l2_ioctl_ops pispbe_node_ioctl_ops = { ++ .vidioc_querycap = pispbe_node_querycap, ++ .vidioc_g_fmt_vid_cap_mplane = pispbe_node_g_fmt_vid_cap, ++ .vidioc_g_fmt_vid_out_mplane = pispbe_node_g_fmt_vid_out, ++ .vidioc_g_fmt_meta_out = pispbe_node_g_fmt_meta_out, ++ .vidioc_g_fmt_meta_cap = pispbe_node_g_fmt_meta_cap, ++ .vidioc_try_fmt_vid_cap_mplane = pispbe_node_try_fmt_vid_cap, ++ .vidioc_try_fmt_vid_out_mplane = pispbe_node_try_fmt_vid_out, ++ .vidioc_try_fmt_meta_out = pispbe_node_try_fmt_meta_out, ++ .vidioc_try_fmt_meta_cap = pispbe_node_try_fmt_meta_cap, ++ .vidioc_s_fmt_vid_cap_mplane = pispbe_node_s_fmt_vid_cap, ++ .vidioc_s_fmt_vid_out_mplane = pispbe_node_s_fmt_vid_out, ++ .vidioc_s_fmt_meta_out = pispbe_node_s_fmt_meta_out, ++ .vidioc_s_fmt_meta_cap = pispbe_node_s_fmt_meta_cap, ++ .vidioc_enum_fmt_vid_cap = pispbe_node_enum_fmt, ++ .vidioc_enum_fmt_vid_out = pispbe_node_enum_fmt, ++ .vidioc_enum_fmt_meta_cap = pispbe_node_enum_fmt, ++ .vidioc_enum_fmt_meta_out = pispbe_node_enum_fmt, ++ .vidioc_enum_framesizes = pispbe_enum_framesizes, ++ .vidioc_create_bufs = vb2_ioctl_create_bufs, ++ .vidioc_prepare_buf = vb2_ioctl_prepare_buf, ++ .vidioc_querybuf = vb2_ioctl_querybuf, ++ .vidioc_qbuf = vb2_ioctl_qbuf, ++ .vidioc_dqbuf = vb2_ioctl_dqbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_reqbufs = vb2_ioctl_reqbufs, ++ .vidioc_streamon = pispbe_node_streamon, ++ .vidioc_streamoff = pispbe_node_streamoff, ++}; ++ ++static const struct video_device pispbe_videodev = { ++ .name = PISPBE_NAME, ++ .vfl_dir = VFL_DIR_M2M, /* gets overwritten */ ++ .fops = &pispbe_fops, ++ .ioctl_ops = &pispbe_node_ioctl_ops, ++ .minor = -1, ++ .release = video_device_release_empty, ++}; ++ ++static void node_set_default_format(struct pispbe_node *node) ++{ ++ if (NODE_IS_META(node) && NODE_IS_OUTPUT(node)) { ++ /* Config node */ ++ struct v4l2_format *f = &node->format; ++ ++ f->fmt.meta.dataformat = V4L2_META_FMT_RPI_BE_CFG; ++ f->fmt.meta.buffersize = sizeof(struct pisp_be_tiles_config); ++ f->type = node->buf_type; ++ } else if (NODE_IS_META(node) && NODE_IS_CAPTURE(node)) { ++ /* HOG output node */ ++ struct v4l2_format *f = &node->format; ++ ++ f->fmt.meta.dataformat = V4L2_PIX_FMT_RPI_BE; ++ f->fmt.meta.buffersize = BIT(20); ++ f->type = node->buf_type; ++ } else { ++ struct v4l2_format f = {0}; ++ ++ f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420; ++ f.fmt.pix_mp.width = 1920; ++ f.fmt.pix_mp.height = 1080; ++ f.type = node->buf_type; ++ try_format(&f, node); ++ node->format = f; ++ } ++ ++ node->pisp_format = find_format(node->format.fmt.pix_mp.pixelformat); ++} ++ ++/* ++ * Initialise a struct pispbe_node and register it as /dev/video<N> ++ * to represent one of the PiSP Back End's input or output streams. ++ */ ++static int ++pispbe_init_node(struct pispbe_node_group *node_group, unsigned int id) ++{ ++ bool output = NODE_DESC_IS_OUTPUT(&node_descid); ++ struct pispbe_node *node = &node_group->nodeid; ++ struct pispbe_dev *pispbe = node_group->pispbe; ++ struct media_entity *entity = &node->vfd.entity; ++ struct video_device *vdev = &node->vfd; ++ struct vb2_queue *q = &node->queue; ++ int ret; ++ ++ node->id = id; ++ node->node_group = node_group; ++ node->buf_type = node_descid.buf_type; ++ ++ mutex_init(&node->node_lock); ++ mutex_init(&node->queue_lock); ++ INIT_LIST_HEAD(&node->ready_queue); ++ spin_lock_init(&node->ready_lock); ++ ++ node->format.type = node->buf_type; ++ node_set_default_format(node); ++ ++ q->type = node->buf_type; ++ q->io_modes = VB2_MMAP | VB2_DMABUF; ++ q->mem_ops = &vb2_dma_contig_memops; ++ q->drv_priv = node; ++ q->ops = &pispbe_node_queue_ops; ++ q->buf_struct_size = sizeof(struct pispbe_buffer); ++ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ++ q->dev = node->node_group->pispbe->dev; ++ /* get V4L2 to handle node->queue locking */ ++ q->lock = &node->queue_lock; ++ ++ ret = vb2_queue_init(q); ++ if (ret < 0) { ++ dev_err(pispbe->dev, "vb2_queue_init failed\n"); ++ return ret; ++ } ++ ++ *vdev = pispbe_videodev; /* default initialization */ ++ strscpy(vdev->name, node_descid.ent_name, sizeof(vdev->name)); ++ vdev->v4l2_dev = &node_group->v4l2_dev; ++ vdev->vfl_dir = output ? VFL_DIR_TX : VFL_DIR_RX; ++ /* get V4L2 to serialise our ioctls */ ++ vdev->lock = &node->node_lock; ++ vdev->queue = &node->queue; ++ vdev->device_caps = V4L2_CAP_STREAMING | node_descid.caps; ++ ++ node->pad.flags = output ? MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK; ++ ret = media_entity_pads_init(entity, 1, &node->pad); ++ if (ret) { ++ dev_err(pispbe->dev, ++ "Failed to register media pads for %s device node\n", ++ NODE_NAME(node)); ++ goto err_unregister_queue; ++ } ++ ++ ret = video_register_device(vdev, VFL_TYPE_VIDEO, ++ PISPBE_VIDEO_NODE_OFFSET); ++ if (ret) { ++ dev_err(pispbe->dev, ++ "Failed to register video %s device node\n", ++ NODE_NAME(node)); ++ goto err_unregister_queue; ++ } ++ video_set_drvdata(vdev, node); ++ ++ if (output) ++ ret = media_create_pad_link(entity, 0, &node_group->sd.entity, ++ id, MEDIA_LNK_FL_IMMUTABLE | ++ MEDIA_LNK_FL_ENABLED); ++ else ++ ret = media_create_pad_link(&node_group->sd.entity, id, entity, ++ 0, MEDIA_LNK_FL_IMMUTABLE | ++ MEDIA_LNK_FL_ENABLED); ++ if (ret) ++ goto err_unregister_video_dev; ++ ++ dev_info(pispbe->dev, ++ "%s device node registered as /dev/video%d\n", ++ NODE_NAME(node), node->vfd.num); ++ return 0; ++ ++err_unregister_video_dev: ++ video_unregister_device(&node->vfd); ++err_unregister_queue: ++ vb2_queue_release(&node->queue); ++ return ret; ++} ++ ++static const struct v4l2_subdev_pad_ops pispbe_pad_ops = { ++ .link_validate = v4l2_subdev_link_validate_default, ++}; ++ ++static const struct v4l2_subdev_ops pispbe_sd_ops = { ++ .pad = &pispbe_pad_ops, ++}; ++ ++static int pispbe_init_subdev(struct pispbe_node_group *node_group) ++{ ++ struct pispbe_dev *pispbe = node_group->pispbe; ++ struct v4l2_subdev *sd = &node_group->sd; ++ unsigned int i; ++ int ret; ++ ++ v4l2_subdev_init(sd, &pispbe_sd_ops); ++ sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; ++ sd->owner = THIS_MODULE; ++ sd->dev = pispbe->dev; ++ strscpy(sd->name, PISPBE_NAME, sizeof(sd->name)); ++ ++ for (i = 0; i < PISPBE_NUM_NODES; i++) ++ node_group->padi.flags = ++ NODE_DESC_IS_OUTPUT(&node_desci) ? ++ MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&sd->entity, PISPBE_NUM_NODES, ++ node_group->pad); ++ if (ret) ++ goto error; ++ ++ ret = v4l2_device_register_subdev(&node_group->v4l2_dev, sd); ++ if (ret) ++ goto error; ++ ++ return 0; ++ ++error: ++ media_entity_cleanup(&sd->entity); ++ return ret; ++} ++ ++static int pispbe_init_group(struct pispbe_dev *pispbe, unsigned int id) ++{ ++ struct pispbe_node_group *node_group = &pispbe->node_groupid; ++ struct v4l2_device *v4l2_dev; ++ struct media_device *mdev; ++ unsigned int num_registered = 0; ++ int ret; ++ ++ node_group->id = id; ++ node_group->pispbe = pispbe; ++ node_group->streaming_map = 0; ++ ++ dev_info(pispbe->dev, "Register nodes for group %u\n", id); ++ ++ /* Register v4l2_device and media_device */ ++ mdev = &node_group->mdev; ++ mdev->hw_revision = node_group->pispbe->hw_version; ++ mdev->dev = node_group->pispbe->dev; ++ strscpy(mdev->model, PISPBE_NAME, sizeof(mdev->model)); ++ snprintf(mdev->bus_info, sizeof(mdev->bus_info), ++ "platform:%s", dev_name(node_group->pispbe->dev)); ++ media_device_init(mdev); ++ ++ v4l2_dev = &node_group->v4l2_dev; ++ v4l2_dev->mdev = &node_group->mdev; ++ strscpy(v4l2_dev->name, PISPBE_NAME, sizeof(v4l2_dev->name)); ++ ++ ret = v4l2_device_register(pispbe->dev, &node_group->v4l2_dev); ++ if (ret) ++ goto err_media_dev_cleanup; ++ ++ /* Register the PISPBE subdevice. */ ++ ret = pispbe_init_subdev(node_group); ++ if (ret) ++ goto err_unregister_v4l2; ++ ++ /* Create device video nodes */ ++ for (; num_registered < PISPBE_NUM_NODES; num_registered++) { ++ ret = pispbe_init_node(node_group, num_registered); ++ if (ret) ++ goto err_unregister_nodes; ++ } ++ ++ ret = media_device_register(mdev); ++ if (ret) ++ goto err_unregister_nodes; ++ ++ node_group->config = ++ dma_alloc_coherent(pispbe->dev, ++ sizeof(struct pisp_be_tiles_config) * ++ PISP_BE_NUM_CONFIG_BUFFERS, ++ &node_group->config_dma_addr, GFP_KERNEL); ++ if (!node_group->config) { ++ dev_err(pispbe->dev, "Unable to allocate cached config buffers.\n"); ++ ret = -ENOMEM; ++ goto err_unregister_mdev; ++ } ++ ++ return 0; ++ ++err_unregister_mdev: ++ media_device_unregister(mdev); ++err_unregister_nodes: ++ while (num_registered-- > 0) { ++ video_unregister_device(&node_group->nodenum_registered.vfd); ++ vb2_queue_release(&node_group->nodenum_registered.queue); ++ } ++ v4l2_device_unregister_subdev(&node_group->sd); ++ media_entity_cleanup(&node_group->sd.entity); ++err_unregister_v4l2: ++ v4l2_device_unregister(v4l2_dev); ++err_media_dev_cleanup: ++ media_device_cleanup(mdev); ++ return ret; ++} ++ ++static void pispbe_destroy_node_group(struct pispbe_node_group *node_group) ++{ ++ struct pispbe_dev *pispbe = node_group->pispbe; ++ int i; ++ ++ if (node_group->config) { ++ dma_free_coherent(node_group->pispbe->dev, ++ sizeof(struct pisp_be_tiles_config) * ++ PISP_BE_NUM_CONFIG_BUFFERS, ++ node_group->config, ++ node_group->config_dma_addr); ++ } ++ ++ dev_info(pispbe->dev, "Unregister from media controller\n"); ++ ++ v4l2_device_unregister_subdev(&node_group->sd); ++ media_entity_cleanup(&node_group->sd.entity); ++ media_device_unregister(&node_group->mdev); ++ ++ for (i = PISPBE_NUM_NODES - 1; i >= 0; i--) { ++ video_unregister_device(&node_group->nodei.vfd); ++ vb2_queue_release(&node_group->nodei.queue); ++ } ++ ++ media_device_cleanup(&node_group->mdev); ++ v4l2_device_unregister(&node_group->v4l2_dev); ++} ++ ++static int pispbe_runtime_suspend(struct device *dev) ++{ ++ struct pispbe_dev *pispbe = dev_get_drvdata(dev); ++ ++ clk_disable_unprepare(pispbe->clk); ++ ++ return 0; ++} ++ ++static int pispbe_runtime_resume(struct device *dev) ++{ ++ struct pispbe_dev *pispbe = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = clk_prepare_enable(pispbe->clk); ++ if (ret) { ++ dev_err(dev, "Unable to enable clock\n"); ++ return ret; ++ } ++ ++ dev_dbg(dev, "%s: Enabled clock, rate=%lu\n", ++ __func__, clk_get_rate(pispbe->clk)); ++ ++ return 0; ++} ++ ++/* ++ * Probe the ISP-BE hardware block, as a single platform device. ++ * This will instantiate multiple "node groups" each with many device nodes. ++ */ ++static int pispbe_probe(struct platform_device *pdev) ++{ ++ unsigned int num_groups = 0; ++ struct pispbe_dev *pispbe; ++ int ret; ++ ++ pispbe = devm_kzalloc(&pdev->dev, sizeof(*pispbe), GFP_KERNEL); ++ if (!pispbe) ++ return -ENOMEM; ++ ++ dev_set_drvdata(&pdev->dev, pispbe); ++ pispbe->dev = &pdev->dev; ++ platform_set_drvdata(pdev, pispbe); ++ ++ pispbe->be_reg_base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(pispbe->be_reg_base)) { ++ dev_err(&pdev->dev, "Failed to get ISP-BE registers address\n"); ++ return PTR_ERR(pispbe->be_reg_base); ++ } ++ ++ pispbe->irq = platform_get_irq(pdev, 0); ++ if (pispbe->irq <= 0) { ++ dev_err(&pdev->dev, "No IRQ resource\n"); ++ return -EINVAL; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, pispbe->irq, pispbe_isr, 0, ++ PISPBE_NAME, pispbe); ++ if (ret) { ++ dev_err(&pdev->dev, "Unable to request interrupt\n"); ++ return ret; ++ } ++ ++ ret = dma_set_mask_and_coherent(pispbe->dev, DMA_BIT_MASK(36)); ++ if (ret) ++ return ret; ++ ++ pispbe->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(pispbe->clk)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(pispbe->clk), ++ "Failed to get clock"); ++ ++ /* Hardware initialisation */ ++ pm_runtime_set_autosuspend_delay(pispbe->dev, 200); ++ pm_runtime_use_autosuspend(pispbe->dev); ++ pm_runtime_enable(pispbe->dev); ++ ++ ret = pm_runtime_resume_and_get(pispbe->dev); ++ if (ret) ++ goto pm_runtime_disable_err; ++ ++ pispbe->hw_busy = 0; ++ spin_lock_init(&pispbe->hw_lock); ++ ret = hw_init(pispbe); ++ if (ret) ++ goto pm_runtime_put_err; ++ ++ /* ++ * Initialise and register devices for each node_group, including media ++ * device ++ */ ++ for (num_groups = 0; ++ num_groups < PISPBE_NUM_NODE_GROUPS; ++ num_groups++) { ++ ret = pispbe_init_group(pispbe, num_groups); ++ if (ret) ++ goto disable_nodes_err; ++ } ++ ++ pm_runtime_mark_last_busy(pispbe->dev); ++ pm_runtime_put_autosuspend(pispbe->dev); ++ ++ return 0; ++ ++disable_nodes_err: ++ while (num_groups-- > 0) ++ pispbe_destroy_node_group(&pispbe->node_groupnum_groups); ++pm_runtime_put_err: ++ pm_runtime_put(pispbe->dev); ++pm_runtime_disable_err: ++ pm_runtime_dont_use_autosuspend(pispbe->dev); ++ pm_runtime_disable(pispbe->dev); ++ ++ dev_err(&pdev->dev, "%s: returning %d", __func__, ret); ++ ++ return ret; ++} ++ ++static int pispbe_remove(struct platform_device *pdev) ++{ ++ struct pispbe_dev *pispbe = platform_get_drvdata(pdev); ++ int i; ++ ++ for (i = PISPBE_NUM_NODE_GROUPS - 1; i >= 0; i--) ++ pispbe_destroy_node_group(&pispbe->node_groupi); ++ ++ pm_runtime_dont_use_autosuspend(pispbe->dev); ++ pm_runtime_disable(pispbe->dev); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops pispbe_pm_ops = { ++ SET_RUNTIME_PM_OPS(pispbe_runtime_suspend, pispbe_runtime_resume, NULL) ++}; ++ ++static const struct of_device_id pispbe_of_match = { ++ { ++ .compatible = "raspberrypi,pispbe", ++ }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, pispbe_of_match); ++ ++static struct platform_driver pispbe_pdrv = { ++ .probe = pispbe_probe, ++ .remove = pispbe_remove, ++ .driver = { ++ .name = PISPBE_NAME, ++ .of_match_table = pispbe_of_match, ++ .pm = &pispbe_pm_ops, ++ }, ++}; ++ ++module_platform_driver(pispbe_pdrv); +diff --git a/drivers/media/platform/raspberrypi/pisp_be/pisp_be_config.h b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_config.h +new file mode 100644 +index 000000000000..bddb6e5d4670 +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_config.h +@@ -0,0 +1,533 @@ ++/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ ++/* ++ * PiSP Back End configuration definitions. ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd ++ * ++ */ ++#ifndef _PISP_BE_CONFIG_H_ ++#define _PISP_BE_CONFIG_H_ ++ ++#include <linux/types.h> ++ ++#include <media/raspberrypi/pisp_common.h> ++ ++/* byte alignment for inputs */ ++#define PISP_BACK_END_INPUT_ALIGN 4u ++/* alignment for compressed inputs */ ++#define PISP_BACK_END_COMPRESSED_ALIGN 8u ++/* minimum required byte alignment for outputs */ ++#define PISP_BACK_END_OUTPUT_MIN_ALIGN 16u ++/* preferred byte alignment for outputs */ ++#define PISP_BACK_END_OUTPUT_MAX_ALIGN 64u ++ ++/* minimum allowed tile width anywhere in the pipeline */ ++#define PISP_BACK_END_MIN_TILE_WIDTH 16u ++/* minimum allowed tile width anywhere in the pipeline */ ++#define PISP_BACK_END_MIN_TILE_HEIGHT 16u ++ ++#define PISP_BACK_END_NUM_OUTPUTS 2 ++#define PISP_BACK_END_HOG_OUTPUT 1 ++ ++#define PISP_BACK_END_NUM_TILES 64 ++ ++enum pisp_be_bayer_enable { ++ PISP_BE_BAYER_ENABLE_INPUT = 0x000001, ++ PISP_BE_BAYER_ENABLE_DECOMPRESS = 0x000002, ++ PISP_BE_BAYER_ENABLE_DPC = 0x000004, ++ PISP_BE_BAYER_ENABLE_GEQ = 0x000008, ++ PISP_BE_BAYER_ENABLE_TDN_INPUT = 0x000010, ++ PISP_BE_BAYER_ENABLE_TDN_DECOMPRESS = 0x000020, ++ PISP_BE_BAYER_ENABLE_TDN = 0x000040, ++ PISP_BE_BAYER_ENABLE_TDN_COMPRESS = 0x000080, ++ PISP_BE_BAYER_ENABLE_TDN_OUTPUT = 0x000100, ++ PISP_BE_BAYER_ENABLE_SDN = 0x000200, ++ PISP_BE_BAYER_ENABLE_BLC = 0x000400, ++ PISP_BE_BAYER_ENABLE_STITCH_INPUT = 0x000800, ++ PISP_BE_BAYER_ENABLE_STITCH_DECOMPRESS = 0x001000, ++ PISP_BE_BAYER_ENABLE_STITCH = 0x002000, ++ PISP_BE_BAYER_ENABLE_STITCH_COMPRESS = 0x004000, ++ PISP_BE_BAYER_ENABLE_STITCH_OUTPUT = 0x008000, ++ PISP_BE_BAYER_ENABLE_WBG = 0x010000, ++ PISP_BE_BAYER_ENABLE_CDN = 0x020000, ++ PISP_BE_BAYER_ENABLE_LSC = 0x040000, ++ PISP_BE_BAYER_ENABLE_TONEMAP = 0x080000, ++ PISP_BE_BAYER_ENABLE_CAC = 0x100000, ++ PISP_BE_BAYER_ENABLE_DEBIN = 0x200000, ++ PISP_BE_BAYER_ENABLE_DEMOSAIC = 0x400000, ++}; ++ ++enum pisp_be_rgb_enable { ++ PISP_BE_RGB_ENABLE_INPUT = 0x000001, ++ PISP_BE_RGB_ENABLE_CCM = 0x000002, ++ PISP_BE_RGB_ENABLE_SAT_CONTROL = 0x000004, ++ PISP_BE_RGB_ENABLE_YCBCR = 0x000008, ++ PISP_BE_RGB_ENABLE_FALSE_COLOUR = 0x000010, ++ PISP_BE_RGB_ENABLE_SHARPEN = 0x000020, ++ /* Preferred colours would occupy 0x000040 */ ++ PISP_BE_RGB_ENABLE_YCBCR_INVERSE = 0x000080, ++ PISP_BE_RGB_ENABLE_GAMMA = 0x000100, ++ PISP_BE_RGB_ENABLE_CSC0 = 0x000200, ++ PISP_BE_RGB_ENABLE_CSC1 = 0x000400, ++ PISP_BE_RGB_ENABLE_DOWNSCALE0 = 0x001000, ++ PISP_BE_RGB_ENABLE_DOWNSCALE1 = 0x002000, ++ PISP_BE_RGB_ENABLE_RESAMPLE0 = 0x008000, ++ PISP_BE_RGB_ENABLE_RESAMPLE1 = 0x010000, ++ PISP_BE_RGB_ENABLE_OUTPUT0 = 0x040000, ++ PISP_BE_RGB_ENABLE_OUTPUT1 = 0x080000, ++ PISP_BE_RGB_ENABLE_HOG = 0x200000 ++}; ++ ++#define PISP_BE_RGB_ENABLE_CSC(i) (PISP_BE_RGB_ENABLE_CSC0 << (i)) ++#define PISP_BE_RGB_ENABLE_DOWNSCALE(i) (PISP_BE_RGB_ENABLE_DOWNSCALE0 << (i)) ++#define PISP_BE_RGB_ENABLE_RESAMPLE(i) (PISP_BE_RGB_ENABLE_RESAMPLE0 << (i)) ++#define PISP_BE_RGB_ENABLE_OUTPUT(i) (PISP_BE_RGB_ENABLE_OUTPUT0 << (i)) ++ ++/* ++ * We use the enable flags to show when blocks are "dirty", but we need some ++ * extra ones too. ++ */ ++enum pisp_be_dirty { ++ PISP_BE_DIRTY_GLOBAL = 0x0001, ++ PISP_BE_DIRTY_SH_FC_COMBINE = 0x0002, ++ PISP_BE_DIRTY_CROP = 0x0004 ++}; ++ ++struct pisp_be_global_config { ++ u32 bayer_enables; ++ u32 rgb_enables; ++ u8 bayer_order; ++ u8 pad3; ++}; ++ ++struct pisp_be_input_buffer_config { ++ /* low 32 bits followed by high 32 bits (for each of up to 3 planes) */ ++ u32 addr32; ++}; ++ ++struct pisp_be_dpc_config { ++ u8 coeff_level; ++ u8 coeff_range; ++ u8 pad; ++#define PISP_BE_DPC_FLAG_FOLDBACK 1 ++ u8 flags; ++}; ++ ++struct pisp_be_geq_config { ++ u16 offset; ++#define PISP_BE_GEQ_SHARPER BIT(15) ++#define PISP_BE_GEQ_SLOPE ((1 << 10) - 1) ++ /* top bit is the "sharper" flag, slope value is bottom 10 bits */ ++ u16 slope_sharper; ++ u16 min; ++ u16 max; ++}; ++ ++struct pisp_be_tdn_input_buffer_config { ++ /* low 32 bits followed by high 32 bits */ ++ u32 addr2; ++}; ++ ++struct pisp_be_tdn_config { ++ u16 black_level; ++ u16 ratio; ++ u16 noise_constant; ++ u16 noise_slope; ++ u16 threshold; ++ u8 reset; ++ u8 pad; ++}; ++ ++struct pisp_be_tdn_output_buffer_config { ++ /* low 32 bits followed by high 32 bits */ ++ u32 addr2; ++}; ++ ++struct pisp_be_sdn_config { ++ u16 black_level; ++ u8 leakage; ++ u8 pad; ++ u16 noise_constant; ++ u16 noise_slope; ++ u16 noise_constant2; ++ u16 noise_slope2; ++}; ++ ++struct pisp_be_stitch_input_buffer_config { ++ /* low 32 bits followed by high 32 bits */ ++ u32 addr2; ++}; ++ ++#define PISP_BE_STITCH_STREAMING_LONG 0x8000 ++#define PISP_BE_STITCH_EXPOSURE_RATIO_MASK 0x7fff ++ ++struct pisp_be_stitch_config { ++ u16 threshold_lo; ++ u8 threshold_diff_power; ++ u8 pad; ++ ++ /* top bit indicates whether streaming input is the long exposure */ ++ u16 exposure_ratio; ++ ++ u8 motion_threshold_256; ++ u8 motion_threshold_recip; ++}; ++ ++struct pisp_be_stitch_output_buffer_config { ++ /* low 32 bits followed by high 32 bits */ ++ u32 addr2; ++}; ++ ++struct pisp_be_cdn_config { ++ u16 thresh; ++ u8 iir_strength; ++ u8 g_adjust; ++}; ++ ++#define PISP_BE_LSC_LOG_GRID_SIZE 5 ++#define PISP_BE_LSC_GRID_SIZE (1 << PISP_BE_LSC_LOG_GRID_SIZE) ++#define PISP_BE_LSC_STEP_PRECISION 18 ++ ++struct pisp_be_lsc_config { ++ /* (1<<18) / grid_cell_width */ ++ u16 grid_step_x; ++ /* (1<<18) / grid_cell_height */ ++ u16 grid_step_y; ++ /* RGB gains jointly encoded in 32 bits */ ++ u32 lut_packedPISP_BE_LSC_GRID_SIZE + 1 ++ PISP_BE_LSC_GRID_SIZE + 1; ++}; ++ ++struct pisp_be_lsc_extra { ++ u16 offset_x; ++ u16 offset_y; ++}; ++ ++#define PISP_BE_CAC_LOG_GRID_SIZE 3 ++#define PISP_BE_CAC_GRID_SIZE (1 << PISP_BE_CAC_LOG_GRID_SIZE) ++#define PISP_BE_CAC_STEP_PRECISION 20 ++ ++struct pisp_be_cac_config { ++ /* (1<<20) / grid_cell_width */ ++ u16 grid_step_x; ++ /* (1<<20) / grid_cell_height */ ++ u16 grid_step_y; ++ /* gridygridxrbxy */ ++ s8 lutPISP_BE_CAC_GRID_SIZE + 1PISP_BE_CAC_GRID_SIZE + 122; ++}; ++ ++struct pisp_be_cac_extra { ++ u16 offset_x; ++ u16 offset_y; ++}; ++ ++#define PISP_BE_DEBIN_NUM_COEFFS 4 ++ ++struct pisp_be_debin_config { ++ s8 coeffsPISP_BE_DEBIN_NUM_COEFFS; ++ s8 h_enable; ++ s8 v_enable; ++ s8 pad2; ++}; ++ ++#define PISP_BE_TONEMAP_LUT_SIZE 64 ++ ++struct pisp_be_tonemap_config { ++ u16 detail_constant; ++ u16 detail_slope; ++ u16 iir_strength; ++ u16 strength; ++ u32 lutPISP_BE_TONEMAP_LUT_SIZE; ++}; ++ ++struct pisp_be_demosaic_config { ++ u8 sharper; ++ u8 fc_mode; ++ u8 pad2; ++}; ++ ++struct pisp_be_ccm_config { ++ s16 coeffs9; ++ u8 pad2; ++ s32 offsets3; ++}; ++ ++struct pisp_be_sat_control_config { ++ u8 shift_r; ++ u8 shift_g; ++ u8 shift_b; ++ u8 pad; ++}; ++ ++struct pisp_be_false_colour_config { ++ u8 distance; ++ u8 pad3; ++}; ++ ++#define PISP_BE_SHARPEN_SIZE 5 ++#define PISP_BE_SHARPEN_FUNC_NUM_POINTS 9 ++ ++struct pisp_be_sharpen_config { ++ s8 kernel0PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE; ++ s8 pad03; ++ s8 kernel1PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE; ++ s8 pad13; ++ s8 kernel2PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE; ++ s8 pad23; ++ s8 kernel3PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE; ++ s8 pad33; ++ s8 kernel4PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE; ++ s8 pad43; ++ u16 threshold_offset0; ++ u16 threshold_slope0; ++ u16 scale0; ++ u16 pad5; ++ u16 threshold_offset1; ++ u16 threshold_slope1; ++ u16 scale1; ++ u16 pad6; ++ u16 threshold_offset2; ++ u16 threshold_slope2; ++ u16 scale2; ++ u16 pad7; ++ u16 threshold_offset3; ++ u16 threshold_slope3; ++ u16 scale3; ++ u16 pad8; ++ u16 threshold_offset4; ++ u16 threshold_slope4; ++ u16 scale4; ++ u16 pad9; ++ u16 positive_strength; ++ u16 positive_pre_limit; ++ u16 positive_funcPISP_BE_SHARPEN_FUNC_NUM_POINTS; ++ u16 positive_limit; ++ u16 negative_strength; ++ u16 negative_pre_limit; ++ u16 negative_funcPISP_BE_SHARPEN_FUNC_NUM_POINTS; ++ u16 negative_limit; ++ u8 enables; ++ u8 white; ++ u8 black; ++ u8 grey; ++}; ++ ++struct pisp_be_sh_fc_combine_config { ++ u8 y_factor; ++ u8 c1_factor; ++ u8 c2_factor; ++ u8 pad; ++}; ++ ++#define PISP_BE_GAMMA_LUT_SIZE 64 ++ ++struct pisp_be_gamma_config { ++ u32 lutPISP_BE_GAMMA_LUT_SIZE; ++}; ++ ++struct pisp_be_crop_config { ++ u16 offset_x, offset_y; ++ u16 width, height; ++}; ++ ++#define PISP_BE_RESAMPLE_FILTER_SIZE 96 ++ ++struct pisp_be_resample_config { ++ u16 scale_factor_h, scale_factor_v; ++ s16 coefPISP_BE_RESAMPLE_FILTER_SIZE; ++}; ++ ++struct pisp_be_resample_extra { ++ u16 scaled_width; ++ u16 scaled_height; ++ s16 initial_phase_h3; ++ s16 initial_phase_v3; ++}; ++ ++struct pisp_be_downscale_config { ++ u16 scale_factor_h; ++ u16 scale_factor_v; ++ u16 scale_recip_h; ++ u16 scale_recip_v; ++}; ++ ++struct pisp_be_downscale_extra { ++ u16 scaled_width; ++ u16 scaled_height; ++}; ++ ++struct pisp_be_hog_config { ++ u8 compute_signed; ++ u8 channel_mix3; ++ u32 stride; ++}; ++ ++struct pisp_be_axi_config { ++ u8 r_qos; /* Read QoS */ ++ u8 r_cache_prot; /* Read { prot2:0, cache3:0 } */ ++ u8 w_qos; /* Write QoS */ ++ u8 w_cache_prot; /* Write { prot2:0, cache3:0 } */ ++}; ++ ++enum pisp_be_transform { ++ PISP_BE_TRANSFORM_NONE = 0x0, ++ PISP_BE_TRANSFORM_HFLIP = 0x1, ++ PISP_BE_TRANSFORM_VFLIP = 0x2, ++ PISP_BE_TRANSFORM_ROT180 = ++ (PISP_BE_TRANSFORM_HFLIP | PISP_BE_TRANSFORM_VFLIP) ++}; ++ ++struct pisp_be_output_format_config { ++ struct pisp_image_format_config image; ++ u8 transform; ++ u8 pad3; ++ u16 lo; ++ u16 hi; ++ u16 lo2; ++ u16 hi2; ++}; ++ ++struct pisp_be_output_buffer_config { ++ /* low 32 bits followed by high 32 bits (for each of 3 planes) */ ++ u32 addr32; ++}; ++ ++struct pisp_be_hog_buffer_config { ++ /* low 32 bits followed by high 32 bits */ ++ u32 addr2; ++}; ++ ++struct pisp_be_config { ++ /* I/O configuration: */ ++ struct pisp_be_input_buffer_config input_buffer; ++ struct pisp_be_tdn_input_buffer_config tdn_input_buffer; ++ struct pisp_be_stitch_input_buffer_config stitch_input_buffer; ++ struct pisp_be_tdn_output_buffer_config tdn_output_buffer; ++ struct pisp_be_stitch_output_buffer_config stitch_output_buffer; ++ struct pisp_be_output_buffer_config ++ output_bufferPISP_BACK_END_NUM_OUTPUTS; ++ struct pisp_be_hog_buffer_config hog_buffer; ++ /* Processing configuration: */ ++ struct pisp_be_global_config global; ++ struct pisp_image_format_config input_format; ++ struct pisp_decompress_config decompress; ++ struct pisp_be_dpc_config dpc; ++ struct pisp_be_geq_config geq; ++ struct pisp_image_format_config tdn_input_format; ++ struct pisp_decompress_config tdn_decompress; ++ struct pisp_be_tdn_config tdn; ++ struct pisp_compress_config tdn_compress; ++ struct pisp_image_format_config tdn_output_format; ++ struct pisp_be_sdn_config sdn; ++ struct pisp_bla_config blc; ++ struct pisp_compress_config stitch_compress; ++ struct pisp_image_format_config stitch_output_format; ++ struct pisp_image_format_config stitch_input_format; ++ struct pisp_decompress_config stitch_decompress; ++ struct pisp_be_stitch_config stitch; ++ struct pisp_be_lsc_config lsc; ++ struct pisp_wbg_config wbg; ++ struct pisp_be_cdn_config cdn; ++ struct pisp_be_cac_config cac; ++ struct pisp_be_debin_config debin; ++ struct pisp_be_tonemap_config tonemap; ++ struct pisp_be_demosaic_config demosaic; ++ struct pisp_be_ccm_config ccm; ++ struct pisp_be_sat_control_config sat_control; ++ struct pisp_be_ccm_config ycbcr; ++ struct pisp_be_sharpen_config sharpen; ++ struct pisp_be_false_colour_config false_colour; ++ struct pisp_be_sh_fc_combine_config sh_fc_combine; ++ struct pisp_be_ccm_config ycbcr_inverse; ++ struct pisp_be_gamma_config gamma; ++ struct pisp_be_ccm_config cscPISP_BACK_END_NUM_OUTPUTS; ++ struct pisp_be_downscale_config downscalePISP_BACK_END_NUM_OUTPUTS; ++ struct pisp_be_resample_config resamplePISP_BACK_END_NUM_OUTPUTS; ++ struct pisp_be_output_format_config ++ output_formatPISP_BACK_END_NUM_OUTPUTS; ++ struct pisp_be_hog_config hog; ++ struct pisp_be_axi_config axi; ++ /* Non-register fields: */ ++ struct pisp_be_lsc_extra lsc_extra; ++ struct pisp_be_cac_extra cac_extra; ++ struct pisp_be_downscale_extra ++ downscale_extraPISP_BACK_END_NUM_OUTPUTS; ++ struct pisp_be_resample_extra resample_extraPISP_BACK_END_NUM_OUTPUTS; ++ struct pisp_be_crop_config crop; ++ struct pisp_image_format_config hog_format; ++ u32 dirty_flags_bayer; /* these use pisp_be_bayer_enable */ ++ u32 dirty_flags_rgb; /* use pisp_be_rgb_enable */ ++ u32 dirty_flags_extra; /* these use pisp_be_dirty_t */ ++}; ++ ++/* ++ * We also need a tile structure to describe the size of the tiles going ++ * through the pipeline. ++ */ ++ ++enum pisp_tile_edge { ++ PISP_LEFT_EDGE = (1 << 0), ++ PISP_RIGHT_EDGE = (1 << 1), ++ PISP_TOP_EDGE = (1 << 2), ++ PISP_BOTTOM_EDGE = (1 << 3) ++}; ++ ++struct pisp_tile { ++ u8 edge; // enum pisp_tile_edge ++ u8 pad03; ++ // 4 bytes ++ u32 input_addr_offset; ++ u32 input_addr_offset2; ++ u16 input_offset_x; ++ u16 input_offset_y; ++ u16 input_width; ++ u16 input_height; ++ // 20 bytes ++ u32 tdn_input_addr_offset; ++ u32 tdn_output_addr_offset; ++ u32 stitch_input_addr_offset; ++ u32 stitch_output_addr_offset; ++ // 36 bytes ++ u32 lsc_grid_offset_x; ++ u32 lsc_grid_offset_y; ++ // 44 bytes ++ u32 cac_grid_offset_x; ++ u32 cac_grid_offset_y; ++ // 52 bytes ++ u16 crop_x_startPISP_BACK_END_NUM_OUTPUTS; ++ u16 crop_x_endPISP_BACK_END_NUM_OUTPUTS; ++ u16 crop_y_startPISP_BACK_END_NUM_OUTPUTS; ++ u16 crop_y_endPISP_BACK_END_NUM_OUTPUTS; ++ // 68 bytes ++ /* Ordering is planes then branches */ ++ u16 downscale_phase_x3 * PISP_BACK_END_NUM_OUTPUTS; ++ u16 downscale_phase_y3 * PISP_BACK_END_NUM_OUTPUTS; ++ // 92 bytes ++ u16 resample_in_widthPISP_BACK_END_NUM_OUTPUTS; ++ u16 resample_in_heightPISP_BACK_END_NUM_OUTPUTS; ++ // 100 bytes ++ /* Ordering is planes then branches */ ++ u16 resample_phase_x3 * PISP_BACK_END_NUM_OUTPUTS; ++ u16 resample_phase_y3 * PISP_BACK_END_NUM_OUTPUTS; ++ // 124 bytes ++ u16 output_offset_xPISP_BACK_END_NUM_OUTPUTS; ++ u16 output_offset_yPISP_BACK_END_NUM_OUTPUTS; ++ u16 output_widthPISP_BACK_END_NUM_OUTPUTS; ++ u16 output_heightPISP_BACK_END_NUM_OUTPUTS; ++ // 140 bytes ++ u32 output_addr_offsetPISP_BACK_END_NUM_OUTPUTS; ++ u32 output_addr_offset2PISP_BACK_END_NUM_OUTPUTS; ++ // 156 bytes ++ u32 output_hog_addr_offset; ++ // 160 bytes ++}; ++ ++static_assert(sizeof(struct pisp_tile) == 160); ++ ++struct pisp_be_tiles_config { ++ struct pisp_be_config config; ++ struct pisp_tile tilesPISP_BACK_END_NUM_TILES; ++ int num_tiles; ++}; ++ ++#endif /* _PISP_BE_CONFIG_H_ */ +diff --git a/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h +new file mode 100644 +index 000000000000..4e2b94475adf +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h +@@ -0,0 +1,519 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * PiSP Back End driver image format definitions. ++ * ++ * Copyright (c) 2021 Raspberry Pi Ltd ++ */ ++ ++#ifndef _PISP_BE_FORMATS_ ++#define _PISP_BE_FORMATS_ ++ ++#include <linux/bits.h> ++#include <linux/videodev2.h> ++ ++#define MAX_PLANES 3 ++#define P3(x) ((x) * 8) ++ ++struct pisp_be_format { ++ unsigned int fourcc; ++ unsigned int align; ++ unsigned int bit_depth; ++ /* 0P3 factor for plane sizing */ ++ unsigned int plane_factorMAX_PLANES; ++ unsigned int num_planes; ++ unsigned int colorspace_mask; ++ enum v4l2_colorspace colorspace_default; ++}; ++ ++#define V4L2_COLORSPACE_MASK(colorspace) BIT(colorspace) ++ ++#define V4L2_COLORSPACE_MASK_JPEG V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_JPEG) ++#define V4L2_COLORSPACE_MASK_SMPTE170M V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SMPTE170M) ++#define V4L2_COLORSPACE_MASK_REC709 V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_REC709) ++#define V4L2_COLORSPACE_MASK_SRGB V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SRGB) ++#define V4L2_COLORSPACE_MASK_RAW V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_RAW) ++ ++/* ++ * All three colour spaces JPEG, SMPTE170M and REC709 are fundamentally sRGB ++ * underneath (as near as makes no difference to us), just with different YCbCr ++ * encodings. Therefore the ISP can generate sRGB on its main output and any of ++ * the others on its low resolution output. Applications should, when using both ++ * outputs, program the colour spaces on them to be the same, matching whatever ++ * is requested for the low resolution output, even if the main output is ++ * producing an RGB format. In turn this requires us to allow all these colour ++ * spaces for every YUV/RGB output format. ++ */ ++#define V4L2_COLORSPACE_MASK_ALL_SRGB (V4L2_COLORSPACE_MASK_JPEG | \ ++ V4L2_COLORSPACE_MASK_SRGB | \ ++ V4L2_COLORSPACE_MASK_SMPTE170M | \ ++ V4L2_COLORSPACE_MASK_REC709) ++ ++static const struct pisp_be_format supported_formats = { ++ /* Single plane YUV formats */ ++ { ++ .fourcc = V4L2_PIX_FMT_YUV420, ++ /* 128 alignment to ensure U/V planes are 64 byte aligned. */ ++ .align = 128, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.25), P3(0.25) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_JPEG, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YVU420, ++ /* 128 alignment to ensure U/V planes are 64 byte aligned. */ ++ .align = 128, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.25), P3(0.25) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .align = 32, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.5) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .align = 32, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.5) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .align = 64, ++ .bit_depth = 16, ++ .plane_factor = { P3(1) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_UYVY, ++ .align = 64, ++ .bit_depth = 16, ++ .plane_factor = { P3(1) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YVYU, ++ .align = 64, ++ .bit_depth = 16, ++ .plane_factor = { P3(1) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_VYUY, ++ .align = 64, ++ .bit_depth = 16, ++ .plane_factor = { P3(1) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ /* Multiplane YUV formats */ ++ { ++ .fourcc = V4L2_PIX_FMT_YUV420M, ++ .align = 64, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.25), P3(0.25) }, ++ .num_planes = 3, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_JPEG, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12M, ++ .align = 32, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.5) }, ++ .num_planes = 2, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21M, ++ .align = 32, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.5) }, ++ .num_planes = 2, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YVU420M, ++ .align = 64, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.25), P3(0.25) }, ++ .num_planes = 3, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YUV422M, ++ .align = 64, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.5), P3(0.5) }, ++ .num_planes = 3, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_JPEG, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YVU422M, ++ .align = 64, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.5), P3(0.5) }, ++ .num_planes = 3, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YUV444M, ++ .align = 64, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(1), P3(1) }, ++ .num_planes = 3, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_JPEG, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YVU444M, ++ .align = 64, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(1), P3(1) }, ++ .num_planes = 3, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ /* RGB formats */ ++ { ++ .fourcc = V4L2_PIX_FMT_RGB24, ++ .align = 32, ++ .bit_depth = 24, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_BGR24, ++ .align = 32, ++ .bit_depth = 24, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_XBGR32, ++ .align = 64, ++ .bit_depth = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_RGBX32, ++ .align = 64, ++ .bit_depth = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_RGB48, ++ .align = 64, ++ .bit_depth = 48, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_BGR48, ++ .align = 64, ++ .bit_depth = 48, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SRGB, ++ }, ++ /* Bayer formats - 8-bit */ ++ { ++ .fourcc = V4L2_PIX_FMT_SRGGB8, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR8, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG8, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG8, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ /* Bayer formats - 16-bit */ ++ { ++ .fourcc = V4L2_PIX_FMT_SRGGB16, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR16, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG16, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG16, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ /* Bayer formats unpacked to 16bpp */ ++ /* 10 bit */ ++ .fourcc = V4L2_PIX_FMT_SRGGB10, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR10, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG10, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG10, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ /* 12 bit */ ++ .fourcc = V4L2_PIX_FMT_SRGGB12, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR12, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG12, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG12, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ /* 14 bit */ ++ .fourcc = V4L2_PIX_FMT_SRGGB14, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR14, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG14, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG14, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ /* Bayer formats - 16-bit PiSP Compressed */ ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_BGGR, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_RGGB, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_GRBG, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_GBRG, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ /* Greyscale Formats */ ++ { ++ .fourcc = V4L2_PIX_FMT_GREY, ++ .bit_depth = 8, ++ .align = 32, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_Y16, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_MONO, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ /* Opaque BE format for HW verification. */ ++ { ++ .fourcc = V4L2_PIX_FMT_RPI_BE, ++ .align = 32, ++ }, ++}; ++ ++static const struct pisp_be_format meta_out_supported_formats = { ++ /* Configuration buffer format. */ ++ { ++ .fourcc = V4L2_META_FMT_RPI_BE_CFG, ++ }, ++}; ++ ++#endif /* _PISP_BE_FORMATS_ */ +diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/Kconfig b/drivers/media/platform/raspberrypi/rp1_cfe/Kconfig +new file mode 100644 +index 000000000000..8cb1255319fb +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/Kconfig +@@ -0,0 +1,14 @@ ++# RP1 V4L2 camera support ++ ++config VIDEO_RP1_CFE ++ tristate "RP1 Camera Frond End (CFE) video capture driver" ++ depends on VIDEO_DEV ++ select VIDEO_V4L2_SUBDEV_API ++ select MEDIA_CONTROLLER ++ select VIDEOBUF2_DMA_CONTIG ++ select V4L2_FWNODE ++ help ++ Say Y here to enable support for the RP1 Camera Front End. ++ ++ To compile this driver as a module, choose M here. The module will be ++ called rp1-cfe. +diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/Makefile b/drivers/media/platform/raspberrypi/rp1_cfe/Makefile +new file mode 100644 +index 000000000000..9709d6f603e9 +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/Makefile +@@ -0,0 +1,6 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Makefile for RP1 Camera Front End driver ++# ++rp1-cfe-objs := cfe.o csi2.o pisp_fe.o dphy.o ++obj-$(CONFIG_VIDEO_RP1_CFE) += rp1-cfe.o +diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +new file mode 100644 +index 000000000000..45bd8abbddbc +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -0,0 +1,2423 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * RP1 Camera Front End Driver ++ * ++ * Copyright (C) 2021-2022 - Raspberry Pi Ltd. ++ * ++ */ ++ ++#include <linux/atomic.h> ++#include <linux/clk.h> ++#include <linux/debugfs.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/phy/phy.h> ++#include <linux/pinctrl/consumer.h> ++#include <linux/platform_device.h> ++#include <linux/pm_runtime.h> ++#include <linux/seq_file.h> ++#include <linux/slab.h> ++#include <linux/uaccess.h> ++#include <linux/videodev2.h> ++ ++#include <media/v4l2-async.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-fwnode.h> ++#include <media/v4l2-ioctl.h> ++#include <media/videobuf2-dma-contig.h> ++ ++#include "cfe.h" ++#include "cfe_fmts.h" ++#include "csi2.h" ++#include "pisp_fe.h" ++#include "pisp_fe_config.h" ++#include "pisp_statistics.h" ++ ++#define CFE_MODULE_NAME "rp1-cfe" ++#define CFE_VERSION "1.0" ++ ++bool cfe_debug_verbose; ++module_param_named(verbose_debug, cfe_debug_verbose, bool, 0644); ++MODULE_PARM_DESC(verbose_debug, "verbose debugging messages"); ++ ++#define cfe_dbg_verbose(fmt, arg...) \ ++ do { \ ++ if (cfe_debug_verbose) \ ++ dev_dbg(&cfe->pdev->dev, fmt, ##arg); \ ++ } while (0) ++#define cfe_dbg(fmt, arg...) dev_dbg(&cfe->pdev->dev, fmt, ##arg) ++#define cfe_info(fmt, arg...) dev_info(&cfe->pdev->dev, fmt, ##arg) ++#define cfe_err(fmt, arg...) dev_err(&cfe->pdev->dev, fmt, ##arg) ++ ++/* MIPICFG registers */ ++#define MIPICFG_CFG 0x004 ++#define MIPICFG_INTR 0x028 ++#define MIPICFG_INTE 0x02c ++#define MIPICFG_INTF 0x030 ++#define MIPICFG_INTS 0x034 ++ ++#define MIPICFG_CFG_SEL_CSI BIT(0) ++ ++#define MIPICFG_INT_CSI_DMA BIT(0) ++#define MIPICFG_INT_CSI_HOST BIT(2) ++#define MIPICFG_INT_PISP_FE BIT(4) ++ ++#define BPL_ALIGNMENT 16 ++#define MAX_BYTESPERLINE 0xffffff00 ++#define MAX_BUFFER_SIZE 0xffffff00 ++/* ++ * Max width is therefore determined by the max stride divided by the number of ++ * bits per pixel. ++ * ++ * However, to avoid overflow issues let's use a 16k maximum. This lets us ++ * calculate 16k * 16k * 4 with 32bits. If we need higher maximums, a careful ++ * review and adjustment of the code is needed so that it will deal with ++ * overflows correctly. ++ */ ++#define MAX_WIDTH 16384 ++#define MAX_HEIGHT MAX_WIDTH ++/* Define a nominal minimum image size */ ++#define MIN_WIDTH 16 ++#define MIN_HEIGHT 16 ++/* Default size of the embedded buffer */ ++#define DEFAULT_EMBEDDED_SIZE 16384 ++ ++const struct v4l2_mbus_framefmt cfe_default_format = { ++ .width = 640, ++ .height = 480, ++ .code = MEDIA_BUS_FMT_SRGGB10_1X10, ++ .field = V4L2_FIELD_NONE, ++ .colorspace = V4L2_COLORSPACE_RAW, ++ .ycbcr_enc = V4L2_YCBCR_ENC_601, ++ .quantization = V4L2_QUANTIZATION_FULL_RANGE, ++ .xfer_func = V4L2_XFER_FUNC_NONE, ++}; ++ ++const struct v4l2_mbus_framefmt cfe_default_meta_format = { ++ .width = DEFAULT_EMBEDDED_SIZE, ++ .height = 1, ++ .code = MEDIA_BUS_FMT_SENSOR_DATA, ++ .field = V4L2_FIELD_NONE, ++}; ++ ++enum node_ids { ++ /* CSI2 HW output nodes first. */ ++ CSI2_CH0, ++ CSI2_CH1, ++ CSI2_CH2, ++ CSI2_CH3, ++ /* FE only nodes from here on. */ ++ FE_OUT0, ++ FE_OUT1, ++ FE_STATS, ++ FE_CONFIG, ++ NUM_NODES ++}; ++ ++struct node_description { ++ unsigned int id; ++ const char *name; ++ unsigned int caps; ++ unsigned int pad_flags; ++ unsigned int link_pad; ++}; ++ ++/* Must match the ordering of enum ids */ ++static const struct node_description node_descNUM_NODES = { ++ CSI2_CH0 = { ++ .name = "csi2_ch0", ++ .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE, ++ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, ++ .link_pad = CSI2_NUM_CHANNELS + 0 ++ }, ++ /* ++ * TODO: This node should be named "csi2_ch1" and the caps should be set ++ * to both video and meta capture. However, to keep compatibility with ++ * the current libcamera, keep the name as "embedded" and support ++ * only meta capture. ++ */ ++ CSI2_CH1 = { ++ .name = "embedded", ++ .caps = V4L2_CAP_META_CAPTURE, ++ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, ++ .link_pad = CSI2_NUM_CHANNELS + 1 ++ }, ++ CSI2_CH2 = { ++ .name = "csi2_ch2", ++ .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE, ++ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, ++ .link_pad = CSI2_NUM_CHANNELS + 2 ++ }, ++ CSI2_CH3 = { ++ .name = "csi2_ch3", ++ .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE, ++ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, ++ .link_pad = CSI2_NUM_CHANNELS + 3 ++ }, ++ FE_OUT0 = { ++ .name = "fe_image0", ++ .caps = V4L2_CAP_VIDEO_CAPTURE, ++ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, ++ .link_pad = FE_OUTPUT0_PAD ++ }, ++ FE_OUT1 = { ++ .name = "fe_image1", ++ .caps = V4L2_CAP_VIDEO_CAPTURE, ++ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, ++ .link_pad = FE_OUTPUT1_PAD ++ }, ++ FE_STATS = { ++ .name = "fe_stats", ++ .caps = V4L2_CAP_META_CAPTURE, ++ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, ++ .link_pad = FE_STATS_PAD ++ }, ++ FE_CONFIG = { ++ .name = "fe_config", ++ .caps = V4L2_CAP_META_OUTPUT, ++ .pad_flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT, ++ .link_pad = FE_CONFIG_PAD ++ }, ++}; ++ ++#define is_fe_node(node) (((node)->id) >= FE_OUT0) ++#define is_csi2_node(node) (!is_fe_node(node)) ++ ++#define node_supports_image_output(node) \ ++ (!!(node_desc(node)->id.caps & V4L2_CAP_VIDEO_CAPTURE)) ++#define node_supports_meta_output(node) \ ++ (!!(node_desc(node)->id.caps & V4L2_CAP_META_CAPTURE)) ++#define node_supports_image_input(node) \ ++ (!!(node_desc(node)->id.caps & V4L2_CAP_VIDEO_OUTPUT)) ++#define node_supports_meta_input(node) \ ++ (!!(node_desc(node)->id.caps & V4L2_CAP_META_OUTPUT)) ++#define node_supports_image(node) \ ++ (node_supports_image_output(node) || node_supports_image_input(node)) ++#define node_supports_meta(node) \ ++ (node_supports_meta_output(node) || node_supports_meta_input(node)) ++ ++#define is_image_output_node(node) \ ++ ((node)->buffer_queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ++#define is_image_input_node(node) \ ++ ((node)->buffer_queue.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ++#define is_image_node(node) \ ++ (is_image_output_node(node) || is_image_input_node(node)) ++#define is_meta_output_node(node) \ ++ ((node)->buffer_queue.type == V4L2_BUF_TYPE_META_CAPTURE) ++#define is_meta_input_node(node) \ ++ ((node)->buffer_queue.type == V4L2_BUF_TYPE_META_OUTPUT) ++#define is_meta_node(node) \ ++ (is_meta_output_node(node) || is_meta_input_node(node)) ++ ++/* To track state across all nodes. */ ++#define NUM_STATES 5 ++#define NODE_REGISTERED BIT(0) ++#define NODE_ENABLED BIT(1) ++#define NODE_STREAMING BIT(2) ++#define FS_INT BIT(3) ++#define FE_INT BIT(4) ++ ++struct cfe_buffer { ++ struct vb2_v4l2_buffer vb; ++ struct list_head list; ++}; ++ ++struct cfe_config_buffer { ++ struct cfe_buffer buf; ++ struct pisp_fe_config config; ++}; ++ ++static inline struct cfe_buffer *to_cfe_buffer(struct vb2_buffer *vb) ++{ ++ return container_of(vb, struct cfe_buffer, vb.vb2_buf); ++} ++ ++static inline ++struct cfe_config_buffer *to_cfe_config_buffer(struct cfe_buffer *buf) ++{ ++ return container_of(buf, struct cfe_config_buffer, buf); ++} ++ ++struct cfe_node { ++ unsigned int id; ++ /* Pointer pointing to current v4l2_buffer */ ++ struct cfe_buffer *cur_frm; ++ /* Pointer pointing to next v4l2_buffer */ ++ struct cfe_buffer *next_frm; ++ /* Used to store current pixel format */ ++ struct v4l2_format vid_fmt; ++ /* Used to store current meta format */ ++ struct v4l2_format meta_fmt; ++ /* Buffer queue used in video-buf */ ++ struct vb2_queue buffer_queue; ++ /* Queue of filled frames */ ++ struct list_head dma_queue; ++ /* lock used to access this structure */ ++ struct mutex lock; ++ /* Identifies video device for this channel */ ++ struct video_device video_dev; ++ /* Pointer to the parent handle */ ++ struct cfe_device *cfe; ++ struct media_pad pad; ++ unsigned int fs_count; ++ u64 ts; ++}; ++ ++struct cfe_device { ++ struct dentry *debugfs; ++ struct kref kref; ++ ++ /* V4l2 specific parameters */ ++ struct v4l2_async_connection *asd; ++ ++ /* peripheral base address */ ++ void __iomem *mipi_cfg_base; ++ ++ struct clk *clk; ++ ++ /* V4l2 device */ ++ struct v4l2_device v4l2_dev; ++ struct media_device mdev; ++ struct media_pipeline pipe; ++ ++ /* IRQ lock for node state and DMA queues */ ++ spinlock_t state_lock; ++ bool job_ready; ++ bool job_queued; ++ ++ /* parent device */ ++ struct platform_device *pdev; ++ /* subdevice async Notifier */ ++ struct v4l2_async_notifier notifier; ++ ++ /* ptr to sub device */ ++ struct v4l2_subdev *sensor; ++ ++ struct cfe_node nodeNUM_NODES; ++ DECLARE_BITMAP(node_flags, NUM_STATES * NUM_NODES); ++ ++ struct csi2_device csi2; ++ struct pisp_fe_device fe; ++ ++ int fe_csi2_channel; ++}; ++ ++static inline bool is_fe_enabled(struct cfe_device *cfe) ++{ ++ return cfe->fe_csi2_channel != -1; ++} ++ ++static inline struct cfe_device *to_cfe_device(struct v4l2_device *v4l2_dev) ++{ ++ return container_of(v4l2_dev, struct cfe_device, v4l2_dev); ++} ++ ++static inline u32 cfg_reg_read(struct cfe_device *cfe, u32 offset) ++{ ++ return readl(cfe->mipi_cfg_base + offset); ++} ++ ++static inline void cfg_reg_write(struct cfe_device *cfe, u32 offset, u32 val) ++{ ++ writel(val, cfe->mipi_cfg_base + offset); ++} ++ ++static bool check_state(struct cfe_device *cfe, unsigned long state, ++ unsigned int node_id) ++{ ++ unsigned long bit; ++ ++ for_each_set_bit(bit, &state, sizeof(state)) { ++ if (!test_bit(bit + (node_id * NUM_STATES), cfe->node_flags)) ++ return false; ++ } ++ return true; ++} ++ ++static void set_state(struct cfe_device *cfe, unsigned long state, ++ unsigned int node_id) ++{ ++ unsigned long bit; ++ ++ for_each_set_bit(bit, &state, sizeof(state)) ++ set_bit(bit + (node_id * NUM_STATES), cfe->node_flags); ++} ++ ++static void clear_state(struct cfe_device *cfe, unsigned long state, ++ unsigned int node_id) ++{ ++ unsigned long bit; ++ ++ for_each_set_bit(bit, &state, sizeof(state)) ++ clear_bit(bit + (node_id * NUM_STATES), cfe->node_flags); ++} ++ ++static bool test_any_node(struct cfe_device *cfe, unsigned long cond) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < NUM_NODES; i++) { ++ if (check_state(cfe, cond, i)) ++ return true; ++ } ++ ++ return false; ++} ++ ++static bool test_all_nodes(struct cfe_device *cfe, unsigned long precond, ++ unsigned long cond) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < NUM_NODES; i++) { ++ if (check_state(cfe, precond, i)) { ++ if (!check_state(cfe, cond, i)) ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++static int mipi_cfg_regs_show(struct seq_file *s, void *data) ++{ ++ struct cfe_device *cfe = s->private; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(&cfe->pdev->dev); ++ if (ret) ++ return ret; ++ ++#define DUMP(reg) seq_printf(s, #reg " \t0x%08x\n", cfg_reg_read(cfe, reg)) ++ DUMP(MIPICFG_CFG); ++ DUMP(MIPICFG_INTR); ++ DUMP(MIPICFG_INTE); ++ DUMP(MIPICFG_INTF); ++ DUMP(MIPICFG_INTS); ++#undef DUMP ++ ++ pm_runtime_put(&cfe->pdev->dev); ++ ++ return 0; ++} ++ ++static int format_show(struct seq_file *s, void *data) ++{ ++ struct cfe_device *cfe = s->private; ++ unsigned int i; ++ ++ for (i = 0; i < NUM_NODES; i++) { ++ struct cfe_node *node = &cfe->nodei; ++ unsigned long sb, state = 0; ++ ++ for (sb = 0; sb < NUM_STATES; sb++) { ++ if (check_state(cfe, BIT(sb), i)) ++ state |= BIT(sb); ++ } ++ ++ seq_printf(s, "\nNode %u (%s) state: 0x%lx\n", i, ++ node_desci.name, state); ++ ++ if (node_supports_image(node)) ++ seq_printf(s, "format: " V4L2_FOURCC_CONV " 0x%x\n" ++ "resolution: %ux%u\nbpl: %u\nsize: %u\n", ++ V4L2_FOURCC_CONV_ARGS(node->vid_fmt.fmt.pix.pixelformat), ++ node->vid_fmt.fmt.pix.pixelformat, ++ node->vid_fmt.fmt.pix.width, ++ node->vid_fmt.fmt.pix.height, ++ node->vid_fmt.fmt.pix.bytesperline, ++ node->vid_fmt.fmt.pix.sizeimage); ++ ++ if (node_supports_meta(node)) ++ seq_printf(s, "format: " V4L2_FOURCC_CONV " 0x%x\nsize: %u\n", ++ V4L2_FOURCC_CONV_ARGS(node->meta_fmt.fmt.meta.dataformat), ++ node->meta_fmt.fmt.meta.dataformat, ++ node->meta_fmt.fmt.meta.buffersize); ++ } ++ ++ return 0; ++} ++ ++DEFINE_SHOW_ATTRIBUTE(mipi_cfg_regs); ++DEFINE_SHOW_ATTRIBUTE(format); ++ ++/* Format setup functions */ ++const struct cfe_fmt *find_format_by_code(u32 code) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(formats); i++) { ++ if (formatsi.code == code) ++ return &formatsi; ++ } ++ ++ return NULL; ++} ++ ++const struct cfe_fmt *find_format_by_pix(u32 pixelformat) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(formats); i++) { ++ if (formatsi.fourcc == pixelformat) ++ return &formatsi; ++ } ++ ++ return NULL; ++} ++ ++/* ++ * Given the mbus code, find the 16 bit remapped code. Returns 0 if no remap ++ * possible. ++ */ ++u32 cfe_find_16bit_code(u32 code) ++{ ++ const struct cfe_fmt *cfe_fmt; ++ ++ cfe_fmt = find_format_by_code(code); ++ ++ if (!cfe_fmt || !cfe_fmt->remapCFE_REMAP_16BIT) ++ return 0; ++ ++ cfe_fmt = find_format_by_pix(cfe_fmt->remapCFE_REMAP_16BIT); ++ if (!cfe_fmt) ++ return 0; ++ ++ return cfe_fmt->code; ++} ++ ++/* ++ * Given the mbus code, find the 8 bit compressed code. Returns 0 if no remap ++ * possible. ++ */ ++u32 cfe_find_compressed_code(u32 code) ++{ ++ const struct cfe_fmt *cfe_fmt; ++ ++ cfe_fmt = find_format_by_code(code); ++ ++ if (!cfe_fmt || !cfe_fmt->remapCFE_REMAP_COMPRESSED) ++ return 0; ++ ++ cfe_fmt = find_format_by_pix(cfe_fmt->remapCFE_REMAP_COMPRESSED); ++ if (!cfe_fmt) ++ return 0; ++ ++ return cfe_fmt->code; ++} ++ ++static int cfe_calc_format_size_bpl(struct cfe_device *cfe, ++ const struct cfe_fmt *fmt, ++ struct v4l2_format *f) ++{ ++ unsigned int min_bytesperline; ++ ++ v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, MAX_WIDTH, 2, ++ &f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 0, 0); ++ ++ min_bytesperline = ++ ALIGN((f->fmt.pix.width * fmt->depth) >> 3, BPL_ALIGNMENT); ++ ++ if (f->fmt.pix.bytesperline > min_bytesperline && ++ f->fmt.pix.bytesperline <= MAX_BYTESPERLINE) ++ f->fmt.pix.bytesperline = ++ ALIGN(f->fmt.pix.bytesperline, BPL_ALIGNMENT); ++ else ++ f->fmt.pix.bytesperline = min_bytesperline; ++ ++ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; ++ ++ cfe_dbg("%s: " V4L2_FOURCC_CONV " size: %ux%u bpl:%u img_size:%u\n", ++ __func__, V4L2_FOURCC_CONV_ARGS(f->fmt.pix.pixelformat), ++ f->fmt.pix.width, f->fmt.pix.height, ++ f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); ++ ++ return 0; ++} ++ ++static void cfe_schedule_next_csi2_job(struct cfe_device *cfe) ++{ ++ struct cfe_buffer *buf; ++ unsigned int i; ++ dma_addr_t addr; ++ ++ for (i = 0; i < CSI2_NUM_CHANNELS; i++) { ++ struct cfe_node *node = &cfe->nodei; ++ unsigned int stride, size; ++ ++ if (!check_state(cfe, NODE_STREAMING, i)) ++ continue; ++ ++ buf = list_first_entry(&node->dma_queue, struct cfe_buffer, ++ list); ++ node->next_frm = buf; ++ list_del(&buf->list); ++ ++ cfe_dbg_verbose("%s: %s buffer:%p\n", __func__, ++ node_descnode->id.name, &buf->vb.vb2_buf); ++ ++ if (is_meta_node(node)) { ++ size = node->meta_fmt.fmt.meta.buffersize; ++ stride = 0; ++ } else { ++ size = node->vid_fmt.fmt.pix.sizeimage; ++ stride = node->vid_fmt.fmt.pix.bytesperline; ++ } ++ ++ addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); ++ csi2_set_buffer(&cfe->csi2, node->id, addr, stride, size); ++ } ++} ++ ++static void cfe_schedule_next_pisp_job(struct cfe_device *cfe) ++{ ++ struct vb2_buffer *vb2_bufsFE_NUM_PADS = { 0 }; ++ struct cfe_config_buffer *config_buf; ++ struct cfe_buffer *buf; ++ unsigned int i; ++ ++ for (i = CSI2_NUM_CHANNELS; i < NUM_NODES; i++) { ++ struct cfe_node *node = &cfe->nodei; ++ ++ if (!check_state(cfe, NODE_STREAMING, i)) ++ continue; ++ ++ buf = list_first_entry(&node->dma_queue, struct cfe_buffer, ++ list); ++ ++ cfe_dbg_verbose("%s: %s buffer:%p\n", __func__, ++ node_descnode->id.name, &buf->vb.vb2_buf); ++ ++ node->next_frm = buf; ++ vb2_bufsnode_desci.link_pad = &buf->vb.vb2_buf; ++ list_del(&buf->list); ++ } ++ ++ config_buf = to_cfe_config_buffer(cfe->nodeFE_CONFIG.next_frm); ++ pisp_fe_submit_job(&cfe->fe, vb2_bufs, &config_buf->config); ++} ++ ++static bool cfe_check_job_ready(struct cfe_device *cfe) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < NUM_NODES; i++) { ++ struct cfe_node *node = &cfe->nodei; ++ ++ if (!check_state(cfe, NODE_ENABLED, i)) ++ continue; ++ ++ if (list_empty(&node->dma_queue)) { ++ cfe_dbg_verbose("%s: %s has no buffer, unable to schedule job\n", ++ __func__, node_desci.name); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++static void cfe_prepare_next_job(struct cfe_device *cfe) ++{ ++ cfe->job_queued = true; ++ cfe_schedule_next_csi2_job(cfe); ++ if (is_fe_enabled(cfe)) ++ cfe_schedule_next_pisp_job(cfe); ++ ++ /* Flag if another job is ready after this. */ ++ cfe->job_ready = cfe_check_job_ready(cfe); ++ ++ cfe_dbg_verbose("%s: end with scheduled job\n", __func__); ++} ++ ++static void cfe_process_buffer_complete(struct cfe_node *node, ++ enum vb2_buffer_state state) ++{ ++ struct cfe_device *cfe = node->cfe; ++ ++ cfe_dbg_verbose("%s: %s buffer:%p\n", __func__, ++ node_descnode->id.name, &node->cur_frm->vb.vb2_buf); ++ ++ node->cur_frm->vb.sequence = node->fs_count - 1; ++ vb2_buffer_done(&node->cur_frm->vb.vb2_buf, state); ++} ++ ++static void cfe_queue_event_sof(struct cfe_node *node) ++{ ++ struct v4l2_event event = { ++ .type = V4L2_EVENT_FRAME_SYNC, ++ .u.frame_sync.frame_sequence = node->fs_count - 1, ++ }; ++ ++ v4l2_event_queue(&node->video_dev, &event); ++} ++ ++static void cfe_sof_isr_handler(struct cfe_node *node) ++{ ++ struct cfe_device *cfe = node->cfe; ++ bool matching_fs = true; ++ unsigned int i; ++ ++ cfe_dbg_verbose("%s: %s seq %u\n", __func__, node_descnode->id.name, ++ node->fs_count); ++ ++ /* ++ * If the sensor is producing unexpected frame event ordering over a ++ * sustained period of time, guard against the possibility of coming ++ * here and orphaning the cur_frm if it's not been dequeued already. ++ * Unfortunately, there is not enough hardware state to tell if this ++ * may have occurred. ++ */ ++ if (WARN(node->cur_frm, "%s: %s Orphanded frame at seq %u\n", ++ __func__, node_descnode->id.name, node->fs_count)) ++ cfe_process_buffer_complete(node, VB2_BUF_STATE_ERROR); ++ ++ node->cur_frm = node->next_frm; ++ node->next_frm = NULL; ++ node->fs_count++; ++ ++ node->ts = ktime_get_ns(); ++ for (i = 0; i < NUM_NODES; i++) { ++ if (!check_state(cfe, NODE_STREAMING, i) || i == node->id) ++ continue; ++ /* ++ * This checks if any other node has seen a FS. If yes, use the ++ * same timestamp, eventually across all node buffers. ++ */ ++ if (cfe->nodei.fs_count >= node->fs_count) ++ node->ts = cfe->nodei.ts; ++ /* ++ * This checks if all other node have seen a matching FS. If ++ * yes, we can flag another job to be queued. ++ */ ++ if (matching_fs && cfe->nodei.fs_count != node->fs_count) ++ matching_fs = false; ++ } ++ ++ if (matching_fs) ++ cfe->job_queued = false; ++ ++ if (node->cur_frm) ++ node->cur_frm->vb.vb2_buf.timestamp = node->ts; ++ ++ set_state(cfe, FS_INT, node->id); ++ clear_state(cfe, FE_INT, node->id); ++ ++ if (is_image_output_node(node)) ++ cfe_queue_event_sof(node); ++} ++ ++static void cfe_eof_isr_handler(struct cfe_node *node) ++{ ++ struct cfe_device *cfe = node->cfe; ++ ++ cfe_dbg_verbose("%s: %s seq %u\n", __func__, node_descnode->id.name, ++ node->fs_count - 1); ++ ++ if (node->cur_frm) ++ cfe_process_buffer_complete(node, VB2_BUF_STATE_DONE); ++ ++ node->cur_frm = NULL; ++ set_state(cfe, FE_INT, node->id); ++ clear_state(cfe, FS_INT, node->id); ++} ++ ++static irqreturn_t cfe_isr(int irq, void *dev) ++{ ++ struct cfe_device *cfe = dev; ++ unsigned int i; ++ bool sofNUM_NODES = {0}, eofNUM_NODES = {0}; ++ u32 sts; ++ ++ sts = cfg_reg_read(cfe, MIPICFG_INTS); ++ ++ if (sts & MIPICFG_INT_CSI_DMA) ++ csi2_isr(&cfe->csi2, sof, eof); ++ ++ if (sts & MIPICFG_INT_PISP_FE) ++ pisp_fe_isr(&cfe->fe, sof + CSI2_NUM_CHANNELS, ++ eof + CSI2_NUM_CHANNELS); ++ ++ spin_lock(&cfe->state_lock); ++ ++ for (i = 0; i < NUM_NODES; i++) { ++ struct cfe_node *node = &cfe->nodei; ++ ++ /* ++ * The check_state(NODE_STREAMING) is to ensure we do not loop ++ * over the CSI2_CHx nodes when the FE is active since they ++ * generate interrupts even though the node is not streaming. ++ */ ++ if (!check_state(cfe, NODE_STREAMING, i) || ++ !(sofi || eofi)) ++ continue; ++ ++ /* ++ * There are 3 cases where we could get FS + FE_ACK at ++ * the same time: ++ * 1) FE of the current frame, and FS of the next frame. ++ * 2) FS + FE of the same frame. ++ * 3) FE of the current frame, and FS + FE of the next ++ * frame. To handle this, see the sof handler below. ++ * ++ * (1) is handled implicitly by the ordering of the FE and FS ++ * handlers below. ++ */ ++ if (eofi) { ++ /* ++ * The condition below tests for (2). Run the FS handler ++ * first before the FE handler, both for the current ++ * frame. ++ */ ++ if (sofi && !check_state(cfe, FS_INT, i)) { ++ cfe_sof_isr_handler(node); ++ sofi = false; ++ } ++ ++ cfe_eof_isr_handler(node); ++ } ++ ++ if (sofi) { ++ /* ++ * The condition below tests for (3). In such cases, we ++ * come in here with FS flag set in the node state from ++ * the previous frame since it only gets cleared in ++ * eof_isr_handler(). Handle the FE for the previous ++ * frame first before the FS handler for the current ++ * frame. ++ */ ++ if (check_state(cfe, FS_INT, node->id) && ++ !check_state(cfe, FE_INT, node->id)) { ++ cfe_dbg("%s: %s Handling missing previous FE interrupt\n", ++ __func__, node_descnode->id.name); ++ cfe_eof_isr_handler(node); ++ } ++ ++ cfe_sof_isr_handler(node); ++ } ++ ++ if (!cfe->job_queued && cfe->job_ready) ++ cfe_prepare_next_job(cfe); ++ } ++ ++ spin_unlock(&cfe->state_lock); ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Stream helpers ++ */ ++ ++static void cfe_start_channel(struct cfe_node *node) ++{ ++ struct cfe_device *cfe = node->cfe; ++ struct v4l2_subdev_state *state; ++ struct v4l2_mbus_framefmt *source_fmt; ++ const struct cfe_fmt *fmt; ++ unsigned long flags; ++ bool start_fe = is_fe_enabled(cfe) && ++ test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING); ++ ++ cfe_dbg("%s: %s\n", __func__, node_descnode->id.name); ++ ++ state = v4l2_subdev_lock_and_get_active_state(&cfe->csi2.sd); ++ ++ if (start_fe) { ++ unsigned int width, height; ++ ++ WARN_ON(!is_fe_enabled(cfe)); ++ cfe_dbg("%s: %s using csi2 channel %d\n", ++ __func__, node_descFE_OUT0.name, ++ cfe->fe_csi2_channel); ++ ++ source_fmt = v4l2_subdev_get_pad_format(&cfe->csi2.sd, state, ++ cfe->fe_csi2_channel); ++ fmt = find_format_by_code(source_fmt->code); ++ ++ width = source_fmt->width; ++ height = source_fmt->height; ++ ++ /* Must have a valid CSI2 datatype. */ ++ WARN_ON(!fmt->csi_dt); ++ ++ /* ++ * Start the associated CSI2 Channel as well. ++ * ++ * Must write to the ADDR register to latch the ctrl values ++ * even if we are connected to the front end. Once running, ++ * this is handled by the CSI2 AUTO_ARM mode. ++ */ ++ csi2_start_channel(&cfe->csi2, cfe->fe_csi2_channel, ++ CSI2_MODE_FE_STREAMING, ++ true, false, width, height); ++ csi2_set_buffer(&cfe->csi2, cfe->fe_csi2_channel, 0, 0, -1); ++ pisp_fe_start(&cfe->fe); ++ } ++ ++ if (is_csi2_node(node)) { ++ unsigned int width = 0, height = 0; ++ ++ u32 mode = CSI2_MODE_NORMAL; ++ ++ source_fmt = v4l2_subdev_get_pad_format(&cfe->csi2.sd, state, ++ node_descnode->id.link_pad - CSI2_NUM_CHANNELS); ++ fmt = find_format_by_code(source_fmt->code); ++ ++ /* Must have a valid CSI2 datatype. */ ++ WARN_ON(!fmt->csi_dt); ++ ++ if (is_image_output_node(node)) { ++ width = source_fmt->width; ++ height = source_fmt->height; ++ ++ if (node->vid_fmt.fmt.pix.pixelformat == ++ fmt->remapCFE_REMAP_16BIT) ++ mode = CSI2_MODE_REMAP; ++ else if (node->vid_fmt.fmt.pix.pixelformat == ++ fmt->remapCFE_REMAP_COMPRESSED) { ++ mode = CSI2_MODE_COMPRESSED; ++ csi2_set_compression(&cfe->csi2, node->id, ++ CSI2_COMPRESSION_DELTA, 0, ++ 0); ++ } ++ } ++ /* Unconditionally start this CSI2 channel. */ ++ csi2_start_channel(&cfe->csi2, node->id, ++ mode, ++ /* Auto arm */ ++ false, ++ /* Pack bytes */ ++ is_meta_node(node) ? true : false, ++ width, height); ++ } ++ ++ v4l2_subdev_unlock_state(state); ++ ++ spin_lock_irqsave(&cfe->state_lock, flags); ++ if (cfe->job_ready && test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING)) ++ cfe_prepare_next_job(cfe); ++ spin_unlock_irqrestore(&cfe->state_lock, flags); ++} ++ ++static void cfe_stop_channel(struct cfe_node *node, bool fe_stop) ++{ ++ struct cfe_device *cfe = node->cfe; ++ ++ cfe_dbg("%s: %s fe_stop %u\n", __func__, ++ node_descnode->id.name, fe_stop); ++ ++ if (fe_stop) { ++ csi2_stop_channel(&cfe->csi2, cfe->fe_csi2_channel); ++ pisp_fe_stop(&cfe->fe); ++ } ++ ++ if (is_csi2_node(node)) ++ csi2_stop_channel(&cfe->csi2, node->id); ++} ++ ++static void cfe_return_buffers(struct cfe_node *node, ++ enum vb2_buffer_state state) ++{ ++ struct cfe_device *cfe = node->cfe; ++ struct cfe_buffer *buf, *tmp; ++ unsigned long flags; ++ ++ cfe_dbg("%s: %s\n", __func__, node_descnode->id.name); ++ ++ spin_lock_irqsave(&cfe->state_lock, flags); ++ list_for_each_entry_safe(buf, tmp, &node->dma_queue, list) { ++ list_del(&buf->list); ++ vb2_buffer_done(&buf->vb.vb2_buf, state); ++ } ++ ++ if (node->cur_frm) ++ vb2_buffer_done(&node->cur_frm->vb.vb2_buf, state); ++ if (node->next_frm && node->cur_frm != node->next_frm) ++ vb2_buffer_done(&node->next_frm->vb.vb2_buf, state); ++ ++ node->cur_frm = NULL; ++ node->next_frm = NULL; ++ spin_unlock_irqrestore(&cfe->state_lock, flags); ++} ++ ++/* ++ * vb2 ops ++ */ ++ ++static int cfe_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, ++ unsigned int *nplanes, unsigned int sizes, ++ struct device *alloc_devs) ++{ ++ struct cfe_node *node = vb2_get_drv_priv(vq); ++ struct cfe_device *cfe = node->cfe; ++ unsigned int size = is_image_node(node) ? node->vid_fmt.fmt.pix.sizeimage : ++ node->meta_fmt.fmt.meta.buffersize; ++ ++ cfe_dbg("%s: %s type:%u\n", __func__, node_descnode->id.name, ++ node->buffer_queue.type); ++ ++ if (vq->num_buffers + *nbuffers < 3) ++ *nbuffers = 3 - vq->num_buffers; ++ ++ if (*nplanes) { ++ if (sizes0 < size) { ++ cfe_err("sizes0 %i < size %u\n", sizes0, size); ++ return -EINVAL; ++ } ++ size = sizes0; ++ } ++ ++ *nplanes = 1; ++ sizes0 = size; ++ ++ return 0; ++} ++ ++static int cfe_buffer_prepare(struct vb2_buffer *vb) ++{ ++ struct cfe_node *node = vb2_get_drv_priv(vb->vb2_queue); ++ struct cfe_device *cfe = node->cfe; ++ struct cfe_buffer *buf = to_cfe_buffer(vb); ++ unsigned long size; ++ ++ cfe_dbg_verbose("%s: %s buffer:%p\n", __func__, ++ node_descnode->id.name, vb); ++ ++ size = is_image_node(node) ? node->vid_fmt.fmt.pix.sizeimage : ++ node->meta_fmt.fmt.meta.buffersize; ++ if (vb2_plane_size(vb, 0) < size) { ++ cfe_err("data will not fit into plane (%lu < %lu)\n", ++ vb2_plane_size(vb, 0), size); ++ return -EINVAL; ++ } ++ ++ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); ++ ++ if (node->id == FE_CONFIG) { ++ struct cfe_config_buffer *b = to_cfe_config_buffer(buf); ++ void *addr = vb2_plane_vaddr(vb, 0); ++ ++ memcpy(&b->config, addr, sizeof(struct pisp_fe_config)); ++ return pisp_fe_validate_config(&cfe->fe, &b->config, ++ &cfe->nodeFE_OUT0.vid_fmt, ++ &cfe->nodeFE_OUT1.vid_fmt); ++ } ++ ++ return 0; ++} ++ ++static void cfe_buffer_queue(struct vb2_buffer *vb) ++{ ++ struct cfe_node *node = vb2_get_drv_priv(vb->vb2_queue); ++ struct cfe_device *cfe = node->cfe; ++ struct cfe_buffer *buf = to_cfe_buffer(vb); ++ unsigned long flags; ++ ++ cfe_dbg_verbose("%s: %s buffer:%p\n", __func__, ++ node_descnode->id.name, vb); ++ ++ spin_lock_irqsave(&cfe->state_lock, flags); ++ ++ list_add_tail(&buf->list, &node->dma_queue); ++ ++ if (!cfe->job_ready) ++ cfe->job_ready = cfe_check_job_ready(cfe); ++ ++ if (!cfe->job_queued && cfe->job_ready && ++ test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING)) { ++ cfe_dbg("Preparing job immediately for channel %u\n", ++ node->id); ++ cfe_prepare_next_job(cfe); ++ } ++ ++ spin_unlock_irqrestore(&cfe->state_lock, flags); ++} ++ ++static u64 sensor_link_rate(struct cfe_device *cfe) ++{ ++ struct v4l2_mbus_framefmt *source_fmt; ++ struct v4l2_subdev_state *state; ++ struct media_entity *entity; ++ struct v4l2_subdev *subdev; ++ const struct cfe_fmt *fmt; ++ struct media_pad *pad; ++ s64 link_freq; ++ ++ state = v4l2_subdev_lock_and_get_active_state(&cfe->csi2.sd); ++ source_fmt = v4l2_subdev_get_pad_format(&cfe->csi2.sd, state, 0); ++ fmt = find_format_by_code(source_fmt->code); ++ v4l2_subdev_unlock_state(state); ++ ++ /* ++ * Walk up the media graph to find either the sensor entity, or another ++ * entity that advertises the V4L2_CID_LINK_FREQ or V4L2_CID_PIXEL_RATE ++ * control through the subdev. ++ */ ++ entity = &cfe->csi2.sd.entity; ++ while (1) { ++ pad = &entity->pads0; ++ if (!(pad->flags & MEDIA_PAD_FL_SINK)) ++ goto err; ++ ++ pad = media_pad_remote_pad_first(pad); ++ if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) ++ goto err; ++ ++ entity = pad->entity; ++ subdev = media_entity_to_v4l2_subdev(entity); ++ if (entity->function == MEDIA_ENT_F_CAM_SENSOR || ++ v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_LINK_FREQ) || ++ v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_PIXEL_RATE)) ++ break; ++ } ++ ++ link_freq = v4l2_get_link_freq(subdev->ctrl_handler, fmt->depth, ++ cfe->csi2.dphy.active_lanes * 2); ++ if (link_freq < 0) ++ goto err; ++ ++ /* x2 for DDR. */ ++ link_freq *= 2; ++ cfe_info("Using a link rate of %lld Mbps\n", link_freq / (1000 * 1000)); ++ return link_freq; ++ ++err: ++ cfe_err("Unable to determine sensor link rate, using 999 Mbps\n"); ++ return 999 * 1000000UL; ++} ++ ++static int cfe_start_streaming(struct vb2_queue *vq, unsigned int count) ++{ ++ struct v4l2_mbus_config mbus_config = { 0 }; ++ struct cfe_node *node = vb2_get_drv_priv(vq); ++ struct cfe_device *cfe = node->cfe; ++ int ret; ++ ++ cfe_dbg("%s: %s begin.\n", __func__, node_descnode->id.name); ++ ++ if (!check_state(cfe, NODE_ENABLED, node->id)) { ++ cfe_err("%s node link is not enabled.\n", ++ node_descnode->id.name); ++ ret = -EINVAL; ++ goto err_streaming; ++ } ++ ++ ret = pm_runtime_resume_and_get(&cfe->pdev->dev); ++ if (ret < 0) { ++ cfe_err("pm_runtime_resume_and_get failed\n"); ++ goto err_streaming; ++ } ++ ++ /* When using the Frontend, we must enable the FE_CONFIG node. */ ++ if (is_fe_enabled(cfe) && ++ !check_state(cfe, NODE_ENABLED, cfe->nodeFE_CONFIG.id)) { ++ cfe_err("FE enabled, but FE_CONFIG node is not\n"); ++ ret = -EINVAL; ++ goto err_pm_put; ++ } ++ ++ ret = media_pipeline_start(&node->pad, &cfe->pipe); ++ if (ret < 0) { ++ cfe_err("Failed to start media pipeline: %d\n", ret); ++ goto err_pm_put; ++ } ++ ++ clear_state(cfe, FS_INT | FE_INT, node->id); ++ set_state(cfe, NODE_STREAMING, node->id); ++ node->fs_count = 0; ++ cfe_start_channel(node); ++ ++ if (!test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING)) { ++ cfe_dbg("Not all nodes are set to streaming yet!\n"); ++ return 0; ++ } ++ ++ cfg_reg_write(cfe, MIPICFG_CFG, MIPICFG_CFG_SEL_CSI); ++ cfg_reg_write(cfe, MIPICFG_INTE, MIPICFG_INT_CSI_DMA | MIPICFG_INT_PISP_FE); ++ ++ ret = v4l2_subdev_call(cfe->sensor, pad, get_mbus_config, 0, ++ &mbus_config); ++ if (ret < 0 && ret != -ENOIOCTLCMD) { ++ cfe_err("g_mbus_config failed\n"); ++ goto err_pm_put; ++ } ++ ++ cfe->csi2.dphy.active_lanes = mbus_config.bus.mipi_csi2.num_data_lanes; ++ if (!cfe->csi2.dphy.active_lanes) ++ cfe->csi2.dphy.active_lanes = cfe->csi2.dphy.max_lanes; ++ if (cfe->csi2.dphy.active_lanes > cfe->csi2.dphy.max_lanes) { ++ cfe_err("Device has requested %u data lanes, which is >%u configured in DT\n", ++ cfe->csi2.dphy.active_lanes, cfe->csi2.dphy.max_lanes); ++ ret = -EINVAL; ++ goto err_disable_cfe; ++ } ++ ++ cfe_dbg("Configuring CSI-2 block - %u data lanes\n", cfe->csi2.dphy.active_lanes); ++ cfe->csi2.dphy.dphy_rate = sensor_link_rate(cfe) / 1000000UL; ++ csi2_open_rx(&cfe->csi2); ++ ++ cfe_dbg("Starting sensor streaming\n"); ++ ret = v4l2_subdev_call(cfe->sensor, video, s_stream, 1); ++ if (ret < 0) { ++ cfe_err("stream on failed in subdev\n"); ++ goto err_disable_cfe; ++ } ++ ++ cfe_dbg("%s: %s end.\n", __func__, node_descnode->id.name); ++ ++ return 0; ++ ++err_disable_cfe: ++ csi2_close_rx(&cfe->csi2); ++ cfe_stop_channel(node, true); ++ media_pipeline_stop(&node->pad); ++err_pm_put: ++ pm_runtime_put(&cfe->pdev->dev); ++err_streaming: ++ cfe_return_buffers(node, VB2_BUF_STATE_QUEUED); ++ clear_state(cfe, NODE_STREAMING, node->id); ++ ++ return ret; ++} ++ ++static void cfe_stop_streaming(struct vb2_queue *vq) ++{ ++ struct cfe_node *node = vb2_get_drv_priv(vq); ++ struct cfe_device *cfe = node->cfe; ++ unsigned long flags; ++ bool fe_stop; ++ ++ cfe_dbg("%s: %s begin.\n", __func__, node_descnode->id.name); ++ ++ spin_lock_irqsave(&cfe->state_lock, flags); ++ fe_stop = is_fe_enabled(cfe) && ++ test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING); ++ ++ cfe->job_ready = false; ++ clear_state(cfe, NODE_STREAMING, node->id); ++ spin_unlock_irqrestore(&cfe->state_lock, flags); ++ ++ cfe_stop_channel(node, fe_stop); ++ ++ if (!test_any_node(cfe, NODE_STREAMING)) { ++ /* Stop streaming the sensor and disable the peripheral. */ ++ if (v4l2_subdev_call(cfe->sensor, video, s_stream, 0) < 0) ++ cfe_err("stream off failed in subdev\n"); ++ ++ csi2_close_rx(&cfe->csi2); ++ ++ cfg_reg_write(cfe, MIPICFG_INTE, 0); ++ } ++ ++ media_pipeline_stop(&node->pad); ++ ++ /* Clear all queued buffers for the node */ ++ cfe_return_buffers(node, VB2_BUF_STATE_ERROR); ++ ++ pm_runtime_put(&cfe->pdev->dev); ++ ++ cfe_dbg("%s: %s end.\n", __func__, node_descnode->id.name); ++} ++ ++static const struct vb2_ops cfe_video_qops = { ++ .wait_prepare = vb2_ops_wait_prepare, ++ .wait_finish = vb2_ops_wait_finish, ++ .queue_setup = cfe_queue_setup, ++ .buf_prepare = cfe_buffer_prepare, ++ .buf_queue = cfe_buffer_queue, ++ .start_streaming = cfe_start_streaming, ++ .stop_streaming = cfe_stop_streaming, ++}; ++ ++/* ++ * v4l2 ioctl ops ++ */ ++ ++static int cfe_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ ++ strscpy(cap->driver, CFE_MODULE_NAME, sizeof(cap->driver)); ++ strscpy(cap->card, CFE_MODULE_NAME, sizeof(cap->card)); ++ ++ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", ++ dev_name(&cfe->pdev->dev)); ++ ++ cap->capabilities |= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE | ++ V4L2_CAP_META_OUTPUT; ++ ++ return 0; ++} ++ ++static int cfe_enum_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ unsigned int i, j; ++ ++ if (!node_supports_image_output(node)) ++ return -EINVAL; ++ ++ cfe_dbg("%s: %s\n", __func__, node_descnode->id.name); ++ ++ for (i = 0, j = 0; i < ARRAY_SIZE(formats); i++) { ++ if (f->mbus_code && formatsi.code != f->mbus_code) ++ continue; ++ ++ if (formatsi.flags & CFE_FORMAT_FLAG_META_OUT || ++ formatsi.flags & CFE_FORMAT_FLAG_META_CAP) ++ continue; ++ ++ if (is_fe_node(node) && ++ !(formatsi.flags & CFE_FORMAT_FLAG_FE_OUT)) ++ continue; ++ ++ if (j == f->index) { ++ f->pixelformat = formatsi.fourcc; ++ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ return 0; ++ } ++ j++; ++ } ++ ++ return -EINVAL; ++} ++ ++static int cfe_g_fmt(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ ++ cfe_dbg("%s: %s\n", __func__, node_descnode->id.name); ++ ++ if (!node_supports_image(node)) ++ return -EINVAL; ++ ++ *f = node->vid_fmt; ++ ++ return 0; ++} ++ ++static int try_fmt_vid_cap(struct cfe_node *node, struct v4l2_format *f) ++{ ++ struct cfe_device *cfe = node->cfe; ++ const struct cfe_fmt *fmt; ++ ++ cfe_dbg("%s: %s %ux%u, V4L2 pix " V4L2_FOURCC_CONV "\n", ++ __func__, node_descnode->id.name, ++ f->fmt.pix.width, f->fmt.pix.height, ++ V4L2_FOURCC_CONV_ARGS(f->fmt.pix.pixelformat)); ++ ++ if (!node_supports_image_output(node)) ++ return -EINVAL; ++ ++ /* ++ * Default to a format that works for both CSI2 and FE. ++ */ ++ fmt = find_format_by_pix(f->fmt.pix.pixelformat); ++ if (!fmt) ++ fmt = find_format_by_code(MEDIA_BUS_FMT_SBGGR10_1X10); ++ ++ f->fmt.pix.pixelformat = fmt->fourcc; ++ ++ if (is_fe_node(node) && fmt->remapCFE_REMAP_16BIT) { ++ f->fmt.pix.pixelformat = fmt->remapCFE_REMAP_16BIT; ++ fmt = find_format_by_pix(f->fmt.pix.pixelformat); ++ } ++ ++ f->fmt.pix.field = V4L2_FIELD_NONE; ++ ++ cfe_calc_format_size_bpl(cfe, fmt, f); ++ ++ return 0; ++} ++ ++static int cfe_s_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ struct vb2_queue *q = &node->buffer_queue; ++ int ret; ++ ++ cfe_dbg("%s: %s\n", __func__, node_descnode->id.name); ++ ++ if (vb2_is_busy(q)) ++ return -EBUSY; ++ ++ ret = try_fmt_vid_cap(node, f); ++ if (ret) ++ return ret; ++ ++ node->vid_fmt = *f; ++ ++ cfe_dbg("%s: Set %ux%u, V4L2 pix " V4L2_FOURCC_CONV "\n", __func__, ++ node->vid_fmt.fmt.pix.width, node->vid_fmt.fmt.pix.height, ++ V4L2_FOURCC_CONV_ARGS(node->vid_fmt.fmt.pix.pixelformat)); ++ ++ return 0; ++} ++ ++static int cfe_try_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ ++ cfe_dbg("%s: %s\n", __func__, node_descnode->id.name); ++ ++ return try_fmt_vid_cap(node, f); ++} ++ ++static int cfe_enum_fmt_meta(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ ++ cfe_dbg("%s: %s\n", __func__, node_descnode->id.name); ++ ++ if (!node_supports_meta(node) || f->index != 0) ++ return -EINVAL; ++ ++ switch (node->id) { ++ case CSI2_CH0...CSI2_CH3: ++ f->pixelformat = V4L2_META_FMT_SENSOR_DATA; ++ return 0; ++ case FE_STATS: ++ f->pixelformat = V4L2_META_FMT_RPI_FE_STATS; ++ return 0; ++ case FE_CONFIG: ++ f->pixelformat = V4L2_META_FMT_RPI_FE_CFG; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int try_fmt_meta(struct cfe_node *node, struct v4l2_format *f) ++{ ++ if (!node_supports_meta(node)) ++ return -EINVAL; ++ ++ switch (node->id) { ++ case CSI2_CH0...CSI2_CH3: ++ f->fmt.meta.dataformat = V4L2_META_FMT_SENSOR_DATA; ++ if (!f->fmt.meta.buffersize) ++ f->fmt.meta.buffersize = DEFAULT_EMBEDDED_SIZE; ++ f->fmt.meta.buffersize = ++ min_t(u32, f->fmt.meta.buffersize, MAX_BUFFER_SIZE); ++ f->fmt.meta.buffersize = ++ ALIGN(f->fmt.meta.buffersize, BPL_ALIGNMENT); ++ return 0; ++ case FE_STATS: ++ f->fmt.meta.dataformat = V4L2_META_FMT_RPI_FE_STATS; ++ f->fmt.meta.buffersize = sizeof(struct pisp_statistics); ++ return 0; ++ case FE_CONFIG: ++ f->fmt.meta.dataformat = V4L2_META_FMT_RPI_FE_CFG; ++ f->fmt.meta.buffersize = sizeof(struct pisp_fe_config); ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int cfe_g_fmt_meta(struct file *file, void *priv, struct v4l2_format *f) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ ++ cfe_dbg("%s: %s\n", __func__, node_descnode->id.name); ++ ++ if (!node_supports_meta(node)) ++ return -EINVAL; ++ ++ *f = node->meta_fmt; ++ ++ return 0; ++} ++ ++static int cfe_s_fmt_meta(struct file *file, void *priv, struct v4l2_format *f) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ struct vb2_queue *q = &node->buffer_queue; ++ int ret; ++ ++ cfe_dbg("%s: %s\n", __func__, node_descnode->id.name); ++ ++ if (vb2_is_busy(q)) ++ return -EBUSY; ++ ++ if (!node_supports_meta(node)) ++ return -EINVAL; ++ ++ ret = try_fmt_meta(node, f); ++ if (ret) ++ return ret; ++ ++ node->meta_fmt = *f; ++ ++ cfe_dbg("%s: Set " V4L2_FOURCC_CONV "\n", __func__, ++ V4L2_FOURCC_CONV_ARGS(node->meta_fmt.fmt.meta.dataformat)); ++ ++ return 0; ++} ++ ++static int cfe_try_fmt_meta(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ ++ cfe_dbg("%s: %s\n", __func__, node_descnode->id.name); ++ return try_fmt_meta(node, f); ++} ++ ++static int cfe_enum_framesizes(struct file *file, void *priv, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ const struct cfe_fmt *fmt; ++ ++ cfe_dbg("%s %s\n", __func__, node_descnode->id.name); ++ ++ if (fsize->index > 0) ++ return -EINVAL; ++ ++ /* check for valid format */ ++ fmt = find_format_by_pix(fsize->pixel_format); ++ if (!fmt) { ++ cfe_dbg("Invalid pixel code: %x\n", fsize->pixel_format); ++ return -EINVAL; ++ } ++ ++ /* TODO: Do we have limits on the step_width? */ ++ ++ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; ++ fsize->stepwise.min_width = MIN_WIDTH; ++ fsize->stepwise.max_width = MAX_WIDTH; ++ fsize->stepwise.step_width = 2; ++ fsize->stepwise.min_height = MIN_HEIGHT; ++ fsize->stepwise.max_height = MAX_HEIGHT; ++ fsize->stepwise.step_height = 1; ++ ++ return 0; ++} ++ ++static int cfe_vb2_ioctl_reqbufs(struct file *file, void *priv, ++ struct v4l2_requestbuffers *p) ++{ ++ struct video_device *vdev = video_devdata(file); ++ struct cfe_node *node = video_get_drvdata(vdev); ++ struct cfe_device *cfe = node->cfe; ++ int ret; ++ ++ cfe_dbg("%s: %s type:%u\n", __func__, node_descnode->id.name, ++ p->type); ++ ++ if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && ++ p->type != V4L2_BUF_TYPE_META_CAPTURE && ++ p->type != V4L2_BUF_TYPE_META_OUTPUT) ++ return -EINVAL; ++ ++ ret = vb2_queue_change_type(vdev->queue, p->type); ++ if (ret) ++ return ret; ++ ++ return vb2_ioctl_reqbufs(file, priv, p); ++} ++ ++static int cfe_vb2_ioctl_create_bufs(struct file *file, void *priv, ++ struct v4l2_create_buffers *p) ++{ ++ struct video_device *vdev = video_devdata(file); ++ struct cfe_node *node = video_get_drvdata(vdev); ++ struct cfe_device *cfe = node->cfe; ++ int ret; ++ ++ cfe_dbg("%s: %s type:%u\n", __func__, node_descnode->id.name, ++ p->format.type); ++ ++ if (p->format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE && ++ p->format.type != V4L2_BUF_TYPE_META_CAPTURE && ++ p->format.type != V4L2_BUF_TYPE_META_OUTPUT) ++ return -EINVAL; ++ ++ ret = vb2_queue_change_type(vdev->queue, p->format.type); ++ if (ret) ++ return ret; ++ ++ return vb2_ioctl_create_bufs(file, priv, p); ++} ++ ++static int cfe_subscribe_event(struct v4l2_fh *fh, ++ const struct v4l2_event_subscription *sub) ++{ ++ struct cfe_node *node = video_get_drvdata(fh->vdev); ++ ++ switch (sub->type) { ++ case V4L2_EVENT_FRAME_SYNC: ++ if (!node_supports_image_output(node)) ++ break; ++ ++ return v4l2_event_subscribe(fh, sub, 2, NULL); ++ case V4L2_EVENT_SOURCE_CHANGE: ++ if (!node_supports_image_output(node) && ++ !node_supports_meta_output(node)) ++ break; ++ ++ return v4l2_event_subscribe(fh, sub, 4, NULL); ++ } ++ ++ return v4l2_ctrl_subscribe_event(fh, sub); ++} ++ ++static const struct v4l2_ioctl_ops cfe_ioctl_ops = { ++ .vidioc_querycap = cfe_querycap, ++ .vidioc_enum_fmt_vid_cap = cfe_enum_fmt_vid_cap, ++ .vidioc_g_fmt_vid_cap = cfe_g_fmt, ++ .vidioc_s_fmt_vid_cap = cfe_s_fmt_vid_cap, ++ .vidioc_try_fmt_vid_cap = cfe_try_fmt_vid_cap, ++ ++ .vidioc_enum_fmt_meta_cap = cfe_enum_fmt_meta, ++ .vidioc_g_fmt_meta_cap = cfe_g_fmt_meta, ++ .vidioc_s_fmt_meta_cap = cfe_s_fmt_meta, ++ .vidioc_try_fmt_meta_cap = cfe_try_fmt_meta, ++ ++ .vidioc_enum_fmt_meta_out = cfe_enum_fmt_meta, ++ .vidioc_g_fmt_meta_out = cfe_g_fmt_meta, ++ .vidioc_s_fmt_meta_out = cfe_s_fmt_meta, ++ .vidioc_try_fmt_meta_out = cfe_try_fmt_meta, ++ ++ .vidioc_enum_framesizes = cfe_enum_framesizes, ++ ++ .vidioc_reqbufs = cfe_vb2_ioctl_reqbufs, ++ .vidioc_create_bufs = cfe_vb2_ioctl_create_bufs, ++ .vidioc_prepare_buf = vb2_ioctl_prepare_buf, ++ .vidioc_querybuf = vb2_ioctl_querybuf, ++ .vidioc_qbuf = vb2_ioctl_qbuf, ++ .vidioc_dqbuf = vb2_ioctl_dqbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_streamon = vb2_ioctl_streamon, ++ .vidioc_streamoff = vb2_ioctl_streamoff, ++ ++ .vidioc_subscribe_event = cfe_subscribe_event, ++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, ++}; ++ ++static void cfe_notify(struct v4l2_subdev *sd, unsigned int notification, ++ void *arg) ++{ ++ struct cfe_device *cfe = to_cfe_device(sd->v4l2_dev); ++ unsigned int i; ++ ++ switch (notification) { ++ case V4L2_DEVICE_NOTIFY_EVENT: ++ for (i = 0; i < NUM_NODES; i++) { ++ struct cfe_node *node = &cfe->nodei; ++ ++ if (check_state(cfe, NODE_REGISTERED, i)) ++ continue; ++ ++ v4l2_event_queue(&node->video_dev, arg); ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++/* cfe capture driver file operations */ ++static const struct v4l2_file_operations cfe_fops = { ++ .owner = THIS_MODULE, ++ .open = v4l2_fh_open, ++ .release = vb2_fop_release, ++ .poll = vb2_fop_poll, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = vb2_fop_mmap, ++}; ++ ++static int cfe_video_link_validate(struct media_link *link) ++{ ++ struct video_device *vd = container_of(link->sink->entity, ++ struct video_device, entity); ++ struct cfe_node *node = container_of(vd, struct cfe_node, video_dev); ++ struct cfe_device *cfe = node->cfe; ++ struct v4l2_mbus_framefmt *source_fmt; ++ struct v4l2_subdev_state *state; ++ struct v4l2_subdev *source_sd; ++ int ret = 0; ++ ++ cfe_dbg("%s: %s link \"%s\":%u -> \"%s\":%u\n", __func__, ++ node_descnode->id.name, ++ link->source->entity->name, link->source->index, ++ link->sink->entity->name, link->sink->index); ++ ++ if (!media_entity_remote_source_pad_unique(link->sink->entity)) { ++ cfe_err("video node %s pad not connected\n", vd->name); ++ return -ENOTCONN; ++ } ++ ++ source_sd = media_entity_to_v4l2_subdev(link->source->entity); ++ ++ state = v4l2_subdev_lock_and_get_active_state(source_sd); ++ ++ source_fmt = v4l2_subdev_get_pad_format(source_sd, state, ++ link->source->index); ++ if (!source_fmt) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ if (is_image_output_node(node)) { ++ struct v4l2_pix_format *pix_fmt = &node->vid_fmt.fmt.pix; ++ const struct cfe_fmt *fmt = NULL; ++ unsigned int i; ++ ++ if (source_fmt->width != pix_fmt->width || ++ source_fmt->height != pix_fmt->height) { ++ cfe_err("Wrong width or height %ux%u (remote pad set to %ux%u)\n", ++ pix_fmt->width, pix_fmt->height, ++ source_fmt->width, ++ source_fmt->height); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(formats); i++) { ++ if (formatsi.code == source_fmt->code && ++ formatsi.fourcc == pix_fmt->pixelformat) { ++ fmt = &formatsi; ++ break; ++ } ++ } ++ if (!fmt) { ++ cfe_err("Format mismatch!\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ } else if (is_csi2_node(node) && is_meta_output_node(node)) { ++ struct v4l2_meta_format *meta_fmt = &node->meta_fmt.fmt.meta; ++ const struct cfe_fmt *fmt; ++ u32 source_size; ++ ++ fmt = find_format_by_code(source_fmt->code); ++ if (!fmt || fmt->fourcc != meta_fmt->dataformat) { ++ cfe_err("Metadata format mismatch!\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ source_size = DIV_ROUND_UP(source_fmt->width * source_fmt->height * fmt->depth, 8); ++ ++ if (source_fmt->code != MEDIA_BUS_FMT_SENSOR_DATA) { ++ cfe_err("Bad metadata mbus format\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ if (source_size > meta_fmt->buffersize) { ++ cfe_err("Metadata buffer too small: %u < %u\n", ++ meta_fmt->buffersize, source_size); ++ ret = -EINVAL; ++ goto out; ++ } ++ } ++ ++out: ++ v4l2_subdev_unlock_state(state); ++ ++ return ret; ++} ++ ++static const struct media_entity_operations cfe_media_entity_ops = { ++ .link_validate = cfe_video_link_validate, ++}; ++ ++static int cfe_video_link_notify(struct media_link *link, u32 flags, ++ unsigned int notification) ++{ ++ struct media_device *mdev = link->graph_obj.mdev; ++ struct cfe_device *cfe = container_of(mdev, struct cfe_device, mdev); ++ struct media_entity *fe = &cfe->fe.sd.entity; ++ struct media_entity *csi2 = &cfe->csi2.sd.entity; ++ unsigned long lock_flags; ++ unsigned int i; ++ ++ if (notification != MEDIA_DEV_NOTIFY_POST_LINK_CH) ++ return 0; ++ ++ cfe_dbg("%s: %s%u -> %s%u 0x%x", __func__, ++ link->source->entity->name, link->source->index, ++ link->sink->entity->name, link->sink->index, flags); ++ ++ spin_lock_irqsave(&cfe->state_lock, lock_flags); ++ ++ for (i = 0; i < NUM_NODES; i++) { ++ if (link->sink->entity != &cfe->nodei.video_dev.entity && ++ link->source->entity != &cfe->nodei.video_dev.entity) ++ continue; ++ ++ if (link->flags & MEDIA_LNK_FL_ENABLED) ++ set_state(cfe, NODE_ENABLED, i); ++ else ++ clear_state(cfe, NODE_ENABLED, i); ++ ++ break; ++ } ++ ++ spin_unlock_irqrestore(&cfe->state_lock, lock_flags); ++ ++ if (link->source->entity != csi2) ++ return 0; ++ if (link->sink->entity != fe) ++ return 0; ++ if (link->sink->index != 0) ++ return 0; ++ ++ cfe->fe_csi2_channel = -1; ++ if (link->flags & MEDIA_LNK_FL_ENABLED) { ++ if (link->source->index == node_descCSI2_CH0.link_pad) ++ cfe->fe_csi2_channel = CSI2_CH0; ++ else if (link->source->index == node_descCSI2_CH1.link_pad) ++ cfe->fe_csi2_channel = CSI2_CH1; ++ else if (link->source->index == node_descCSI2_CH2.link_pad) ++ cfe->fe_csi2_channel = CSI2_CH2; ++ else if (link->source->index == node_descCSI2_CH3.link_pad) ++ cfe->fe_csi2_channel = CSI2_CH3; ++ } ++ ++ if (is_fe_enabled(cfe)) ++ cfe_dbg("%s: Found CSI2:%d -> FE:0 link\n", __func__, ++ cfe->fe_csi2_channel); ++ else ++ cfe_dbg("%s: Unable to find CSI2:x -> FE:0 link\n", __func__); ++ ++ return 0; ++} ++ ++static const struct media_device_ops cfe_media_device_ops = { ++ .link_notify = cfe_video_link_notify, ++}; ++ ++static void cfe_release(struct kref *kref) ++{ ++ struct cfe_device *cfe = container_of(kref, struct cfe_device, kref); ++ ++ media_device_cleanup(&cfe->mdev); ++ ++ kfree(cfe); ++} ++ ++static void cfe_put(struct cfe_device *cfe) ++{ ++ kref_put(&cfe->kref, cfe_release); ++} ++ ++static void cfe_get(struct cfe_device *cfe) ++{ ++ kref_get(&cfe->kref); ++} ++ ++static void cfe_node_release(struct video_device *vdev) ++{ ++ struct cfe_node *node = video_get_drvdata(vdev); ++ ++ cfe_put(node->cfe); ++} ++ ++static int cfe_register_node(struct cfe_device *cfe, int id) ++{ ++ struct video_device *vdev; ++ const struct cfe_fmt *fmt; ++ struct vb2_queue *q; ++ struct cfe_node *node = &cfe->nodeid; ++ int ret; ++ ++ node->cfe = cfe; ++ node->id = id; ++ ++ if (node_supports_image(node)) { ++ if (node_supports_image_output(node)) ++ node->vid_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ else ++ node->vid_fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ ++ fmt = find_format_by_code(cfe_default_format.code); ++ if (!fmt) { ++ cfe_err("Failed to find format code\n"); ++ return -EINVAL; ++ } ++ ++ node->vid_fmt.fmt.pix.pixelformat = fmt->fourcc; ++ v4l2_fill_pix_format(&node->vid_fmt.fmt.pix, &cfe_default_format); ++ ++ ret = try_fmt_vid_cap(node, &node->vid_fmt); ++ if (ret) ++ return ret; ++ } ++ ++ if (node_supports_meta(node)) { ++ if (node_supports_meta_output(node)) ++ node->meta_fmt.type = V4L2_BUF_TYPE_META_CAPTURE; ++ else ++ node->meta_fmt.type = V4L2_BUF_TYPE_META_OUTPUT; ++ ++ ret = try_fmt_meta(node, &node->meta_fmt); ++ if (ret) ++ return ret; ++ } ++ ++ mutex_init(&node->lock); ++ ++ q = &node->buffer_queue; ++ q->type = node_supports_image(node) ? node->vid_fmt.type : ++ node->meta_fmt.type; ++ q->io_modes = VB2_MMAP | VB2_DMABUF; ++ q->drv_priv = node; ++ q->ops = &cfe_video_qops; ++ q->mem_ops = &vb2_dma_contig_memops; ++ q->buf_struct_size = id == FE_CONFIG ? sizeof(struct cfe_config_buffer) ++ : sizeof(struct cfe_buffer); ++ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ++ q->lock = &node->lock; ++ q->min_buffers_needed = 1; ++ q->dev = &cfe->pdev->dev; ++ ++ ret = vb2_queue_init(q); ++ if (ret) { ++ cfe_err("vb2_queue_init() failed\n"); ++ return ret; ++ } ++ ++ INIT_LIST_HEAD(&node->dma_queue); ++ ++ vdev = &node->video_dev; ++ vdev->release = cfe_node_release; ++ vdev->fops = &cfe_fops; ++ vdev->ioctl_ops = &cfe_ioctl_ops; ++ vdev->entity.ops = &cfe_media_entity_ops; ++ vdev->v4l2_dev = &cfe->v4l2_dev; ++ vdev->vfl_dir = (node_supports_image_output(node) || ++ node_supports_meta_output(node)) ? ++ VFL_DIR_RX : ++ VFL_DIR_TX; ++ vdev->queue = q; ++ vdev->lock = &node->lock; ++ vdev->device_caps = node_descid.caps; ++ vdev->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_IO_MC; ++ ++ /* Define the device names */ ++ snprintf(vdev->name, sizeof(vdev->name), "%s-%s", CFE_MODULE_NAME, ++ node_descid.name); ++ ++ video_set_drvdata(vdev, node); ++ if (node->id == FE_OUT0) ++ vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT; ++ node->pad.flags = node_descid.pad_flags; ++ media_entity_pads_init(&vdev->entity, 1, &node->pad); ++ ++ if (!node_supports_image(node)) { ++ v4l2_disable_ioctl(&node->video_dev, ++ VIDIOC_ENUM_FRAMEINTERVALS); ++ v4l2_disable_ioctl(&node->video_dev, ++ VIDIOC_ENUM_FRAMESIZES); ++ } ++ ++ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); ++ if (ret) { ++ cfe_err("Unable to register video device %s\n", vdev->name); ++ return ret; ++ } ++ ++ cfe_info("Registered %s node id %d successfully as /dev/video%u\n", ++ vdev->name, id, vdev->num); ++ ++ /* ++ * Acquire a reference to cfe, which will be released when the video ++ * device will be unregistered and userspace will have closed all open ++ * file handles. ++ */ ++ cfe_get(cfe); ++ set_state(cfe, NODE_REGISTERED, id); ++ ++ return 0; ++} ++ ++static void cfe_unregister_nodes(struct cfe_device *cfe) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < NUM_NODES; i++) { ++ struct cfe_node *node = &cfe->nodei; ++ ++ if (check_state(cfe, NODE_REGISTERED, i)) { ++ clear_state(cfe, NODE_REGISTERED, i); ++ video_unregister_device(&node->video_dev); ++ } ++ } ++} ++ ++static int cfe_link_node_pads(struct cfe_device *cfe) ++{ ++ unsigned int i, source_pad = 0; ++ int ret; ++ ++ for (i = 0; i < CSI2_NUM_CHANNELS; i++) { ++ struct cfe_node *node = &cfe->nodei; ++ ++ if (!check_state(cfe, NODE_REGISTERED, i)) ++ continue; ++ ++ /* Find next source pad */ ++ while (source_pad < cfe->sensor->entity.num_pads && ++ !(cfe->sensor->entity.padssource_pad.flags & ++ MEDIA_PAD_FL_SOURCE)) ++ source_pad++; ++ ++ if (source_pad < cfe->sensor->entity.num_pads) { ++ /* Sensor -> CSI2 */ ++ ret = media_create_pad_link(&cfe->sensor->entity, source_pad, ++ &cfe->csi2.sd.entity, i, ++ MEDIA_LNK_FL_IMMUTABLE | ++ MEDIA_LNK_FL_ENABLED); ++ if (ret) ++ return ret; ++ ++ /* Dealt with that source_pad, look at the next one next time */ ++ source_pad++; ++ } ++ ++ /* CSI2 channel # -> /dev/video# */ ++ ret = media_create_pad_link(&cfe->csi2.sd.entity, ++ node_desci.link_pad, ++ &node->video_dev.entity, 0, 0); ++ if (ret) ++ return ret; ++ ++ if (node_supports_image(node)) { ++ /* CSI2 channel # -> FE Input */ ++ ret = media_create_pad_link(&cfe->csi2.sd.entity, ++ node_desci.link_pad, ++ &cfe->fe.sd.entity, ++ FE_STREAM_PAD, 0); ++ if (ret) ++ return ret; ++ } ++ } ++ ++ for (; i < NUM_NODES; i++) { ++ struct cfe_node *node = &cfe->nodei; ++ struct media_entity *src, *dst; ++ unsigned int src_pad, dst_pad; ++ ++ if (node_desci.pad_flags & MEDIA_PAD_FL_SINK) { ++ /* FE -> /dev/video# */ ++ src = &cfe->fe.sd.entity; ++ src_pad = node_desci.link_pad; ++ dst = &node->video_dev.entity; ++ dst_pad = 0; ++ } else { ++ /* /dev/video# -> FE */ ++ dst = &cfe->fe.sd.entity; ++ dst_pad = node_desci.link_pad; ++ src = &node->video_dev.entity; ++ src_pad = 0; ++ } ++ ++ ret = media_create_pad_link(src, src_pad, dst, dst_pad, 0); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int cfe_probe_complete(struct cfe_device *cfe) ++{ ++ unsigned int i; ++ int ret; ++ ++ cfe->v4l2_dev.notify = cfe_notify; ++ ++ for (i = 0; i < NUM_NODES; i++) { ++ ret = cfe_register_node(cfe, i); ++ if (ret) { ++ cfe_err("Unable to register video node %u.\n", i); ++ goto unregister; ++ } ++ } ++ ++ ret = cfe_link_node_pads(cfe); ++ if (ret) { ++ cfe_err("Unable to link node pads.\n"); ++ goto unregister; ++ } ++ ++ ret = v4l2_device_register_subdev_nodes(&cfe->v4l2_dev); ++ if (ret) { ++ cfe_err("Unable to register subdev nodes.\n"); ++ goto unregister; ++ } ++ ++ return 0; ++ ++unregister: ++ cfe_unregister_nodes(cfe); ++ return ret; ++} ++ ++static int cfe_async_bound(struct v4l2_async_notifier *notifier, ++ struct v4l2_subdev *subdev, ++ struct v4l2_async_connection *asd) ++{ ++ struct cfe_device *cfe = to_cfe_device(notifier->v4l2_dev); ++ ++ if (cfe->sensor) { ++ cfe_info("Rejecting subdev %s (Already set!!)", subdev->name); ++ return 0; ++ } ++ ++ cfe->sensor = subdev; ++ cfe_info("Using sensor %s for capture\n", subdev->name); ++ ++ return 0; ++} ++ ++static int cfe_async_complete(struct v4l2_async_notifier *notifier) ++{ ++ struct cfe_device *cfe = to_cfe_device(notifier->v4l2_dev); ++ ++ return cfe_probe_complete(cfe); ++} ++ ++static const struct v4l2_async_notifier_operations cfe_async_ops = { ++ .bound = cfe_async_bound, ++ .complete = cfe_async_complete, ++}; ++ ++static int of_cfe_connect_subdevs(struct cfe_device *cfe) ++{ ++ struct platform_device *pdev = cfe->pdev; ++ struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; ++ struct device_node *node = pdev->dev.of_node; ++ struct device_node *ep_node; ++ struct device_node *sensor_node; ++ unsigned int lane; ++ int ret = -EINVAL; ++ ++ /* Get the local endpoint and remote device. */ ++ ep_node = of_graph_get_next_endpoint(node, NULL); ++ if (!ep_node) { ++ cfe_err("can't get next endpoint\n"); ++ return -EINVAL; ++ } ++ ++ cfe_dbg("ep_node is %pOF\n", ep_node); ++ ++ sensor_node = of_graph_get_remote_port_parent(ep_node); ++ if (!sensor_node) { ++ cfe_err("can't get remote parent\n"); ++ goto cleanup_exit; ++ } ++ ++ cfe_info("found subdevice %pOF\n", sensor_node); ++ ++ /* Parse the local endpoint and validate its configuration. */ ++ v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), &ep); ++ ++ cfe->csi2.multipacket_line = ++ fwnode_property_present(of_fwnode_handle(ep_node), ++ "multipacket-line"); ++ ++ if (ep.bus_type != V4L2_MBUS_CSI2_DPHY) { ++ cfe_err("endpoint node type != CSI2\n"); ++ return -EINVAL; ++ } ++ ++ for (lane = 0; lane < ep.bus.mipi_csi2.num_data_lanes; lane++) { ++ if (ep.bus.mipi_csi2.data_laneslane != lane + 1) { ++ cfe_err("subdevice %pOF: data lanes reordering not supported\n", ++ sensor_node); ++ goto cleanup_exit; ++ } ++ } ++ ++ cfe->csi2.dphy.max_lanes = ep.bus.mipi_csi2.num_data_lanes; ++ cfe->csi2.bus_flags = ep.bus.mipi_csi2.flags; ++ ++ cfe_dbg("subdevice %pOF: %u data lanes, flags=0x%08x, multipacket_line=%u\n", ++ sensor_node, cfe->csi2.dphy.max_lanes, cfe->csi2.bus_flags, ++ cfe->csi2.multipacket_line); ++ ++ /* Initialize and register the async notifier. */ ++ v4l2_async_nf_init(&cfe->notifier, &cfe->v4l2_dev); ++ cfe->notifier.ops = &cfe_async_ops; ++ ++ cfe->asd = v4l2_async_nf_add_fwnode(&cfe->notifier, ++ of_fwnode_handle(sensor_node), ++ struct v4l2_async_connection); ++ if (IS_ERR(cfe->asd)) { ++ cfe_err("Error adding subdevice: %d\n", ret); ++ goto cleanup_exit; ++ } ++ ++ ret = v4l2_async_nf_register(&cfe->notifier); ++ if (ret) { ++ cfe_err("Error registering async notifier: %d\n", ret); ++ ret = -EINVAL; ++ } ++ ++cleanup_exit: ++ of_node_put(sensor_node); ++ of_node_put(ep_node); ++ ++ return ret; ++} ++ ++static int cfe_probe(struct platform_device *pdev) ++{ ++ struct cfe_device *cfe; ++ char debugfs_name32; ++ int ret; ++ ++ cfe = kzalloc(sizeof(*cfe), GFP_KERNEL); ++ if (!cfe) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, cfe); ++ ++ kref_init(&cfe->kref); ++ cfe->pdev = pdev; ++ cfe->fe_csi2_channel = -1; ++ spin_lock_init(&cfe->state_lock); ++ ++ cfe->csi2.base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(cfe->csi2.base)) { ++ dev_err(&pdev->dev, "Failed to get dma io block\n"); ++ ret = PTR_ERR(cfe->csi2.base); ++ goto err_cfe_put; ++ } ++ ++ cfe->csi2.dphy.base = devm_platform_ioremap_resource(pdev, 1); ++ if (IS_ERR(cfe->csi2.dphy.base)) { ++ dev_err(&pdev->dev, "Failed to get host io block\n"); ++ ret = PTR_ERR(cfe->csi2.dphy.base); ++ goto err_cfe_put; ++ } ++ ++ cfe->mipi_cfg_base = devm_platform_ioremap_resource(pdev, 2); ++ if (IS_ERR(cfe->mipi_cfg_base)) { ++ dev_err(&pdev->dev, "Failed to get mipi cfg io block\n"); ++ ret = PTR_ERR(cfe->mipi_cfg_base); ++ goto err_cfe_put; ++ } ++ ++ cfe->fe.base = devm_platform_ioremap_resource(pdev, 3); ++ if (IS_ERR(cfe->fe.base)) { ++ dev_err(&pdev->dev, "Failed to get pisp fe io block\n"); ++ ret = PTR_ERR(cfe->fe.base); ++ goto err_cfe_put; ++ } ++ ++ ret = platform_get_irq(pdev, 0); ++ if (ret <= 0) { ++ dev_err(&pdev->dev, "No IRQ resource\n"); ++ ret = -EINVAL; ++ goto err_cfe_put; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, ret, cfe_isr, 0, "rp1-cfe", cfe); ++ if (ret) { ++ dev_err(&pdev->dev, "Unable to request interrupt\n"); ++ ret = -EINVAL; ++ goto err_cfe_put; ++ } ++ ++ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); ++ if (ret) { ++ dev_err(&pdev->dev, "DMA enable failed\n"); ++ goto err_cfe_put; ++ } ++ ++ /* TODO: Enable clock only when running. */ ++ cfe->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(cfe->clk)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(cfe->clk), ++ "clock not found\n"); ++ ++ cfe->mdev.dev = &pdev->dev; ++ cfe->mdev.ops = &cfe_media_device_ops; ++ strscpy(cfe->mdev.model, CFE_MODULE_NAME, sizeof(cfe->mdev.model)); ++ strscpy(cfe->mdev.serial, "", sizeof(cfe->mdev.serial)); ++ snprintf(cfe->mdev.bus_info, sizeof(cfe->mdev.bus_info), "platform:%s", ++ dev_name(&pdev->dev)); ++ ++ media_device_init(&cfe->mdev); ++ ++ cfe->v4l2_dev.mdev = &cfe->mdev; ++ ++ ret = v4l2_device_register(&pdev->dev, &cfe->v4l2_dev); ++ if (ret) { ++ cfe_err("Unable to register v4l2 device.\n"); ++ goto err_cfe_put; ++ } ++ ++ snprintf(debugfs_name, sizeof(debugfs_name), "rp1-cfe:%s", ++ dev_name(&pdev->dev)); ++ cfe->debugfs = debugfs_create_dir(debugfs_name, NULL); ++ debugfs_create_file("format", 0444, cfe->debugfs, cfe, &format_fops); ++ debugfs_create_file("regs", 0444, cfe->debugfs, cfe, ++ &mipi_cfg_regs_fops); ++ ++ /* Enable the block power domain */ ++ pm_runtime_enable(&pdev->dev); ++ ++ ret = pm_runtime_resume_and_get(&cfe->pdev->dev); ++ if (ret) ++ goto err_runtime_disable; ++ ++ cfe->csi2.v4l2_dev = &cfe->v4l2_dev; ++ ret = csi2_init(&cfe->csi2, cfe->debugfs); ++ if (ret) { ++ cfe_err("Failed to init csi2 (%d)\n", ret); ++ goto err_runtime_put; ++ } ++ ++ cfe->fe.v4l2_dev = &cfe->v4l2_dev; ++ ret = pisp_fe_init(&cfe->fe, cfe->debugfs); ++ if (ret) { ++ cfe_err("Failed to init pisp fe (%d)\n", ret); ++ goto err_csi2_uninit; ++ } ++ ++ cfe->mdev.hw_revision = cfe->fe.hw_revision; ++ ret = media_device_register(&cfe->mdev); ++ if (ret < 0) { ++ cfe_err("Unable to register media-controller device.\n"); ++ goto err_pisp_fe_uninit; ++ } ++ ++ ret = of_cfe_connect_subdevs(cfe); ++ if (ret) { ++ cfe_err("Failed to connect subdevs\n"); ++ goto err_media_unregister; ++ } ++ ++ pm_runtime_put(&cfe->pdev->dev); ++ ++ return 0; ++ ++err_media_unregister: ++ media_device_unregister(&cfe->mdev); ++err_pisp_fe_uninit: ++ pisp_fe_uninit(&cfe->fe); ++err_csi2_uninit: ++ csi2_uninit(&cfe->csi2); ++err_runtime_put: ++ pm_runtime_put(&cfe->pdev->dev); ++err_runtime_disable: ++ pm_runtime_disable(&pdev->dev); ++ debugfs_remove(cfe->debugfs); ++ v4l2_device_unregister(&cfe->v4l2_dev); ++err_cfe_put: ++ cfe_put(cfe); ++ ++ return ret; ++} ++ ++static int cfe_remove(struct platform_device *pdev) ++{ ++ struct cfe_device *cfe = platform_get_drvdata(pdev); ++ ++ debugfs_remove(cfe->debugfs); ++ ++ v4l2_async_nf_unregister(&cfe->notifier); ++ media_device_unregister(&cfe->mdev); ++ cfe_unregister_nodes(cfe); ++ ++ pisp_fe_uninit(&cfe->fe); ++ csi2_uninit(&cfe->csi2); ++ ++ pm_runtime_disable(&pdev->dev); ++ ++ v4l2_device_unregister(&cfe->v4l2_dev); ++ ++ cfe_put(cfe); ++ ++ return 0; ++} ++ ++static int cfe_runtime_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct cfe_device *cfe = platform_get_drvdata(pdev); ++ ++ clk_disable_unprepare(cfe->clk); ++ ++ return 0; ++} ++ ++static int cfe_runtime_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct cfe_device *cfe = platform_get_drvdata(pdev); ++ int ret; ++ ++ ret = clk_prepare_enable(cfe->clk); ++ if (ret) { ++ dev_err(dev, "Unable to enable clock\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops cfe_pm_ops = { ++ SET_RUNTIME_PM_OPS(cfe_runtime_suspend, cfe_runtime_resume, NULL) ++ SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) ++}; ++ ++static const struct of_device_id cfe_of_match = { ++ { .compatible = "raspberrypi,rp1-cfe" }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, cfe_of_match); ++ ++static struct platform_driver cfe_driver = { ++ .probe = cfe_probe, ++ .remove = cfe_remove, ++ .driver = { ++ .name = CFE_MODULE_NAME, ++ .of_match_table = cfe_of_match, ++ .pm = &cfe_pm_ops, ++ }, ++}; ++ ++module_platform_driver(cfe_driver); ++ ++MODULE_AUTHOR("Naushir Patuck <naush@raspberrypi.com>"); ++MODULE_DESCRIPTION("RP1 Camera Front End driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(CFE_VERSION); +diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.h b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.h +new file mode 100644 +index 000000000000..637b63a838c4 +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.h +@@ -0,0 +1,43 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * RP1 CFE driver. ++ * Copyright (c) 2021 Raspberry Pi Ltd. ++ * ++ */ ++#ifndef _RP1_CFE_ ++#define _RP1_CFE_ ++ ++#include <linux/types.h> ++#include <linux/media-bus-format.h> ++#include <linux/videodev2.h> ++ ++extern bool cfe_debug_verbose; ++ ++enum cfe_remap_types { ++ CFE_REMAP_16BIT, ++ CFE_REMAP_COMPRESSED, ++ CFE_NUM_REMAP, ++}; ++ ++#define CFE_FORMAT_FLAG_META_OUT BIT(0) ++#define CFE_FORMAT_FLAG_META_CAP BIT(1) ++#define CFE_FORMAT_FLAG_FE_OUT BIT(2) ++ ++struct cfe_fmt { ++ u32 fourcc; ++ u32 code; ++ u8 depth; ++ u8 csi_dt; ++ u32 remapCFE_NUM_REMAP; ++ u32 flags; ++}; ++ ++extern const struct v4l2_mbus_framefmt cfe_default_format; ++extern const struct v4l2_mbus_framefmt cfe_default_meta_format; ++ ++const struct cfe_fmt *find_format_by_code(u32 code); ++const struct cfe_fmt *find_format_by_pix(u32 pixelformat); ++u32 cfe_find_16bit_code(u32 code); ++u32 cfe_find_compressed_code(u32 code); ++ ++#endif +diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/cfe_fmts.h b/drivers/media/platform/raspberrypi/rp1_cfe/cfe_fmts.h +new file mode 100644 +index 000000000000..72516c93c5c5 +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe_fmts.h +@@ -0,0 +1,316 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * RP1 Camera Front End formats definition ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd. ++ * ++ */ ++#ifndef _CFE_FMTS_H_ ++#define _CFE_FMTS_H_ ++ ++#include "cfe.h" ++#include <media/mipi-csi2.h> ++ ++static const struct cfe_fmt formats = { ++ /* YUV Formats */ ++ { ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .code = MEDIA_BUS_FMT_YUYV8_1X16, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_YUV422_8B, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_UYVY, ++ .code = MEDIA_BUS_FMT_UYVY8_1X16, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_YUV422_8B, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YVYU, ++ .code = MEDIA_BUS_FMT_YVYU8_1X16, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_YUV422_8B, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_VYUY, ++ .code = MEDIA_BUS_FMT_VYUY8_1X16, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_YUV422_8B, ++ }, ++ { ++ /* RGB Formats */ ++ .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ ++ .code = MEDIA_BUS_FMT_RGB565_2X8_LE, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_RGB565, ++ }, ++ { .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ ++ .code = MEDIA_BUS_FMT_RGB565_2X8_BE, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_RGB565, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ ++ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_RGB555, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ ++ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_RGB555, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ ++ .code = MEDIA_BUS_FMT_RGB888_1X24, ++ .depth = 24, ++ .csi_dt = MIPI_CSI2_DT_RGB888, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ ++ .code = MEDIA_BUS_FMT_BGR888_1X24, ++ .depth = 24, ++ .csi_dt = MIPI_CSI2_DT_RGB888, ++ }, ++ { ++ .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 = MIPI_CSI2_DT_RAW8, ++ .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG8, ++ .code = MEDIA_BUS_FMT_SGBRG8_1X8, ++ .depth = 8, ++ .csi_dt = MIPI_CSI2_DT_RAW8, ++ .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG8, ++ .code = MEDIA_BUS_FMT_SGRBG8_1X8, ++ .depth = 8, ++ .csi_dt = MIPI_CSI2_DT_RAW8, ++ .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SRGGB8, ++ .code = MEDIA_BUS_FMT_SRGGB8_1X8, ++ .depth = 8, ++ .csi_dt = MIPI_CSI2_DT_RAW8, ++ .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR10P, ++ .code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .depth = 10, ++ .csi_dt = MIPI_CSI2_DT_RAW10, ++ .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG10P, ++ .code = MEDIA_BUS_FMT_SGBRG10_1X10, ++ .depth = 10, ++ .csi_dt = MIPI_CSI2_DT_RAW10, ++ .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG10P, ++ .code = MEDIA_BUS_FMT_SGRBG10_1X10, ++ .depth = 10, ++ .csi_dt = MIPI_CSI2_DT_RAW10, ++ .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SRGGB10P, ++ .code = MEDIA_BUS_FMT_SRGGB10_1X10, ++ .depth = 10, ++ .csi_dt = MIPI_CSI2_DT_RAW10, ++ .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR12P, ++ .code = MEDIA_BUS_FMT_SBGGR12_1X12, ++ .depth = 12, ++ .csi_dt = MIPI_CSI2_DT_RAW12, ++ .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG12P, ++ .code = MEDIA_BUS_FMT_SGBRG12_1X12, ++ .depth = 12, ++ .csi_dt = MIPI_CSI2_DT_RAW12, ++ .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG12P, ++ .code = MEDIA_BUS_FMT_SGRBG12_1X12, ++ .depth = 12, ++ .csi_dt = MIPI_CSI2_DT_RAW12, ++ .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SRGGB12P, ++ .code = MEDIA_BUS_FMT_SRGGB12_1X12, ++ .depth = 12, ++ .csi_dt = MIPI_CSI2_DT_RAW12, ++ .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR14P, ++ .code = MEDIA_BUS_FMT_SBGGR14_1X14, ++ .depth = 14, ++ .csi_dt = MIPI_CSI2_DT_RAW14, ++ .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG14P, ++ .code = MEDIA_BUS_FMT_SGBRG14_1X14, ++ .depth = 14, ++ .csi_dt = MIPI_CSI2_DT_RAW14, ++ .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG14P, ++ .code = MEDIA_BUS_FMT_SGRBG14_1X14, ++ .depth = 14, ++ .csi_dt = MIPI_CSI2_DT_RAW14, ++ .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SRGGB14P, ++ .code = MEDIA_BUS_FMT_SRGGB14_1X14, ++ .depth = 14, ++ .csi_dt = MIPI_CSI2_DT_RAW14, ++ .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR16, ++ .code = MEDIA_BUS_FMT_SBGGR16_1X16, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_RAW16, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG16, ++ .code = MEDIA_BUS_FMT_SGBRG16_1X16, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_RAW16, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG16, ++ .code = MEDIA_BUS_FMT_SGRBG16_1X16, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_RAW16, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SRGGB16, ++ .code = MEDIA_BUS_FMT_SRGGB16_1X16, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_RAW16, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, ++ }, ++ /* PiSP Compressed Mode 1 */ ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_RGGB, ++ .code = MEDIA_BUS_FMT_SRGGB16_1X16, ++ .depth = 8, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_BGGR, ++ .code = MEDIA_BUS_FMT_SBGGR16_1X16, ++ .depth = 8, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_GBRG, ++ .code = MEDIA_BUS_FMT_SGBRG16_1X16, ++ .depth = 8, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_GRBG, ++ .code = MEDIA_BUS_FMT_SGRBG16_1X16, ++ .depth = 8, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ }, ++ /* Greyscale format */ ++ { ++ .fourcc = V4L2_PIX_FMT_GREY, ++ .code = MEDIA_BUS_FMT_Y8_1X8, ++ .depth = 8, ++ .csi_dt = MIPI_CSI2_DT_RAW8, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_Y10P, ++ .code = MEDIA_BUS_FMT_Y10_1X10, ++ .depth = 10, ++ .csi_dt = MIPI_CSI2_DT_RAW10, ++ .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_Y12P, ++ .code = MEDIA_BUS_FMT_Y12_1X12, ++ .depth = 12, ++ .csi_dt = MIPI_CSI2_DT_RAW12, ++ .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_Y14P, ++ .code = MEDIA_BUS_FMT_Y14_1X14, ++ .depth = 14, ++ .csi_dt = MIPI_CSI2_DT_RAW14, ++ .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_Y16, ++ .code = MEDIA_BUS_FMT_Y16_1X16, ++ .depth = 16, ++ .csi_dt = MIPI_CSI2_DT_RAW16, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_MONO, ++ .code = MEDIA_BUS_FMT_Y16_1X16, ++ .depth = 8, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ }, ++ /* Embedded data format */ ++ { ++ .fourcc = V4L2_META_FMT_SENSOR_DATA, ++ .code = MEDIA_BUS_FMT_SENSOR_DATA, ++ .depth = 8, ++ .csi_dt = MIPI_CSI2_DT_EMBEDDED_8B, ++ .flags = CFE_FORMAT_FLAG_META_CAP, ++ }, ++ ++ /* Frontend formats */ ++ { ++ .fourcc = V4L2_META_FMT_RPI_FE_CFG, ++ .code = MEDIA_BUS_FMT_FIXED, ++ .flags = CFE_FORMAT_FLAG_META_OUT, ++ }, ++ { ++ .fourcc = V4L2_META_FMT_RPI_FE_STATS, ++ .code = MEDIA_BUS_FMT_FIXED, ++ .flags = CFE_FORMAT_FLAG_META_CAP, ++ }, ++}; ++ ++#endif /* _CFE_FMTS_H_ */ +diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c +new file mode 100644 +index 000000000000..015bd3feac8d +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c +@@ -0,0 +1,624 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * RP1 CSI-2 Driver ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd. ++ * ++ */ ++ ++#include <linux/delay.h> ++#include <linux/moduleparam.h> ++#include <linux/pm_runtime.h> ++#include <linux/seq_file.h> ++ ++#include <media/videobuf2-dma-contig.h> ++ ++#include "csi2.h" ++#include "cfe.h" ++ ++static bool csi2_track_errors; ++module_param_named(track_csi2_errors, csi2_track_errors, bool, 0); ++MODULE_PARM_DESC(track_csi2_errors, "track csi-2 errors"); ++ ++#define csi2_dbg_verbose(fmt, arg...) \ ++ do { \ ++ if (cfe_debug_verbose) \ ++ dev_dbg(csi2->v4l2_dev->dev, fmt, ##arg); \ ++ } while (0) ++#define csi2_dbg(fmt, arg...) dev_dbg(csi2->v4l2_dev->dev, fmt, ##arg) ++#define csi2_info(fmt, arg...) dev_info(csi2->v4l2_dev->dev, fmt, ##arg) ++#define csi2_err(fmt, arg...) dev_err(csi2->v4l2_dev->dev, fmt, ##arg) ++ ++/* CSI2-DMA registers */ ++#define CSI2_STATUS 0x000 ++#define CSI2_QOS 0x004 ++#define CSI2_DISCARDS_OVERFLOW 0x008 ++#define CSI2_DISCARDS_INACTIVE 0x00c ++#define CSI2_DISCARDS_UNMATCHED 0x010 ++#define CSI2_DISCARDS_LEN_LIMIT 0x014 ++ ++#define CSI2_DISCARDS_AMOUNT_SHIFT 0 ++#define CSI2_DISCARDS_AMOUNT_MASK GENMASK(23, 0) ++#define CSI2_DISCARDS_DT_SHIFT 24 ++#define CSI2_DISCARDS_DT_MASK GENMASK(29, 24) ++#define CSI2_DISCARDS_VC_SHIFT 30 ++#define CSI2_DISCARDS_VC_MASK GENMASK(31, 30) ++ ++#define CSI2_LLEV_PANICS 0x018 ++#define CSI2_ULEV_PANICS 0x01c ++#define CSI2_IRQ_MASK 0x020 ++#define CSI2_IRQ_MASK_IRQ_OVERFLOW BIT(0) ++#define CSI2_IRQ_MASK_IRQ_DISCARD_OVERFLOW BIT(1) ++#define CSI2_IRQ_MASK_IRQ_DISCARD_LENGTH_LIMIT BIT(2) ++#define CSI2_IRQ_MASK_IRQ_DISCARD_UNMATCHED BIT(3) ++#define CSI2_IRQ_MASK_IRQ_DISCARD_INACTIVE BIT(4) ++#define CSI2_IRQ_MASK_IRQ_ALL \ ++ (CSI2_IRQ_MASK_IRQ_OVERFLOW | CSI2_IRQ_MASK_IRQ_DISCARD_OVERFLOW | \ ++ CSI2_IRQ_MASK_IRQ_DISCARD_LENGTH_LIMIT | \ ++ CSI2_IRQ_MASK_IRQ_DISCARD_UNMATCHED | \ ++ CSI2_IRQ_MASK_IRQ_DISCARD_INACTIVE) ++ ++#define CSI2_CTRL 0x024 ++#define CSI2_CH_CTRL(x) ((x) * 0x40 + 0x28) ++#define CSI2_CH_ADDR0(x) ((x) * 0x40 + 0x2c) ++#define CSI2_CH_ADDR1(x) ((x) * 0x40 + 0x3c) ++#define CSI2_CH_STRIDE(x) ((x) * 0x40 + 0x30) ++#define CSI2_CH_LENGTH(x) ((x) * 0x40 + 0x34) ++#define CSI2_CH_DEBUG(x) ((x) * 0x40 + 0x38) ++#define CSI2_CH_FRAME_SIZE(x) ((x) * 0x40 + 0x40) ++#define CSI2_CH_COMP_CTRL(x) ((x) * 0x40 + 0x44) ++#define CSI2_CH_FE_FRAME_ID(x) ((x) * 0x40 + 0x48) ++ ++/* CSI2_STATUS */ ++#define IRQ_FS(x) (BIT(0) << (x)) ++#define IRQ_FE(x) (BIT(4) << (x)) ++#define IRQ_FE_ACK(x) (BIT(8) << (x)) ++#define IRQ_LE(x) (BIT(12) << (x)) ++#define IRQ_LE_ACK(x) (BIT(16) << (x)) ++#define IRQ_CH_MASK(x) (IRQ_FS(x) | IRQ_FE(x) | IRQ_FE_ACK(x) | IRQ_LE(x) | IRQ_LE_ACK(x)) ++#define IRQ_OVERFLOW BIT(20) ++#define IRQ_DISCARD_OVERFLOW BIT(21) ++#define IRQ_DISCARD_LEN_LIMIT BIT(22) ++#define IRQ_DISCARD_UNMATCHED BIT(23) ++#define IRQ_DISCARD_INACTIVE BIT(24) ++ ++/* CSI2_CTRL */ ++#define EOP_IS_EOL BIT(0) ++ ++/* CSI2_CH_CTRL */ ++#define DMA_EN BIT(0) ++#define FORCE BIT(3) ++#define AUTO_ARM BIT(4) ++#define IRQ_EN_FS BIT(13) ++#define IRQ_EN_FE BIT(14) ++#define IRQ_EN_FE_ACK BIT(15) ++#define IRQ_EN_LE BIT(16) ++#define IRQ_EN_LE_ACK BIT(17) ++#define FLUSH_FE BIT(28) ++#define PACK_LINE BIT(29) ++#define PACK_BYTES BIT(30) ++#define CH_MODE_MASK GENMASK(2, 1) ++#define VC_MASK GENMASK(6, 5) ++#define DT_MASK GENMASK(12, 7) ++#define LC_MASK GENMASK(27, 18) ++ ++/* CHx_COMPRESSION_CONTROL */ ++#define COMP_OFFSET_MASK GENMASK(15, 0) ++#define COMP_SHIFT_MASK GENMASK(19, 16) ++#define COMP_MODE_MASK GENMASK(25, 24) ++ ++static inline u32 csi2_reg_read(struct csi2_device *csi2, u32 offset) ++{ ++ return readl(csi2->base + offset); ++} ++ ++static inline void csi2_reg_write(struct csi2_device *csi2, u32 offset, u32 val) ++{ ++ writel(val, csi2->base + offset); ++ csi2_dbg_verbose("csi2: write 0x%04x -> 0x%03x\n", val, offset); ++} ++ ++static inline void set_field(u32 *valp, u32 field, u32 mask) ++{ ++ u32 val = *valp; ++ ++ val &= ~mask; ++ val |= (field << __ffs(mask)) & mask; ++ *valp = val; ++} ++ ++static int csi2_regs_show(struct seq_file *s, void *data) ++{ ++ struct csi2_device *csi2 = s->private; ++ unsigned int i; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(csi2->v4l2_dev->dev); ++ if (ret) ++ return ret; ++ ++#define DUMP(reg) seq_printf(s, #reg " \t0x%08x\n", csi2_reg_read(csi2, reg)) ++#define DUMP_CH(idx, reg) seq_printf(s, #reg "(%u) \t0x%08x\n", idx, csi2_reg_read(csi2, reg(idx))) ++ ++ DUMP(CSI2_STATUS); ++ DUMP(CSI2_DISCARDS_OVERFLOW); ++ DUMP(CSI2_DISCARDS_INACTIVE); ++ DUMP(CSI2_DISCARDS_UNMATCHED); ++ DUMP(CSI2_DISCARDS_LEN_LIMIT); ++ DUMP(CSI2_LLEV_PANICS); ++ DUMP(CSI2_ULEV_PANICS); ++ DUMP(CSI2_IRQ_MASK); ++ DUMP(CSI2_CTRL); ++ ++ for (i = 0; i < CSI2_NUM_CHANNELS; ++i) { ++ DUMP_CH(i, CSI2_CH_CTRL); ++ DUMP_CH(i, CSI2_CH_ADDR0); ++ DUMP_CH(i, CSI2_CH_ADDR1); ++ DUMP_CH(i, CSI2_CH_STRIDE); ++ DUMP_CH(i, CSI2_CH_LENGTH); ++ DUMP_CH(i, CSI2_CH_DEBUG); ++ DUMP_CH(i, CSI2_CH_FRAME_SIZE); ++ DUMP_CH(i, CSI2_CH_COMP_CTRL); ++ DUMP_CH(i, CSI2_CH_FE_FRAME_ID); ++ } ++ ++#undef DUMP ++#undef DUMP_CH ++ ++ pm_runtime_put(csi2->v4l2_dev->dev); ++ ++ return 0; ++} ++ ++DEFINE_SHOW_ATTRIBUTE(csi2_regs); ++ ++static int csi2_errors_show(struct seq_file *s, void *data) ++{ ++ struct csi2_device *csi2 = s->private; ++ unsigned long flags; ++ u32 discards_tableDISCARDS_TABLE_NUM_VCSDISCARDS_TABLE_NUM_ENTRIES; ++ u32 discards_dt_tableDISCARDS_TABLE_NUM_ENTRIES; ++ u32 overflows; ++ ++ spin_lock_irqsave(&csi2->errors_lock, flags); ++ ++ memcpy(discards_table, csi2->discards_table, sizeof(discards_table)); ++ memcpy(discards_dt_table, csi2->discards_dt_table, ++ sizeof(discards_dt_table)); ++ overflows = csi2->overflows; ++ ++ csi2->overflows = 0; ++ memset(csi2->discards_table, 0, sizeof(discards_table)); ++ memset(csi2->discards_dt_table, 0, sizeof(discards_dt_table)); ++ ++ spin_unlock_irqrestore(&csi2->errors_lock, flags); ++ ++ seq_printf(s, "Overflows %u\n", overflows); ++ seq_puts(s, "Discards:\n"); ++ seq_puts(s, "VC OVLF LEN UNMATCHED INACTIVE\n"); ++ ++ for (unsigned int vc = 0; vc < DISCARDS_TABLE_NUM_VCS; ++vc) { ++ seq_printf(s, "%u %10u %10u %10u %10u\n", vc, ++ discards_tablevcDISCARDS_TABLE_OVERFLOW, ++ discards_tablevcDISCARDS_TABLE_LENGTH_LIMIT, ++ discards_tablevcDISCARDS_TABLE_UNMATCHED, ++ discards_tablevcDISCARDS_TABLE_INACTIVE); ++ } ++ ++ seq_printf(s, "Last DT %10u %10u %10u %10u\n", ++ discards_dt_tableDISCARDS_TABLE_OVERFLOW, ++ discards_dt_tableDISCARDS_TABLE_LENGTH_LIMIT, ++ discards_dt_tableDISCARDS_TABLE_UNMATCHED, ++ discards_dt_tableDISCARDS_TABLE_INACTIVE); ++ ++ return 0; ++} ++ ++DEFINE_SHOW_ATTRIBUTE(csi2_errors); ++ ++static void csi2_isr_handle_errors(struct csi2_device *csi2, u32 status) ++{ ++ spin_lock(&csi2->errors_lock); ++ ++ if (status & IRQ_OVERFLOW) ++ csi2->overflows++; ++ ++ for (unsigned int i = 0; i < DISCARDS_TABLE_NUM_ENTRIES; ++i) { ++ static const u32 discard_bits = { ++ IRQ_DISCARD_OVERFLOW, ++ IRQ_DISCARD_LEN_LIMIT, ++ IRQ_DISCARD_UNMATCHED, ++ IRQ_DISCARD_INACTIVE, ++ }; ++ static const u8 discard_regs = { ++ CSI2_DISCARDS_OVERFLOW, ++ CSI2_DISCARDS_LEN_LIMIT, ++ CSI2_DISCARDS_UNMATCHED, ++ CSI2_DISCARDS_INACTIVE, ++ }; ++ u32 amount; ++ u8 dt, vc; ++ u32 v; ++ ++ if (!(status & discard_bitsi)) ++ continue; ++ ++ v = csi2_reg_read(csi2, discard_regsi); ++ csi2_reg_write(csi2, discard_regsi, 0); + -+ /* Load image pointers */ -+ reg_write_field(dev, UNICAM_ICTL, 1, UNICAM_LIP_MASK); ++ amount = (v & CSI2_DISCARDS_AMOUNT_MASK) >> ++ CSI2_DISCARDS_AMOUNT_SHIFT; ++ dt = (v & CSI2_DISCARDS_DT_MASK) >> CSI2_DISCARDS_DT_SHIFT; ++ vc = (v & CSI2_DISCARDS_VC_MASK) >> CSI2_DISCARDS_VC_SHIFT; + -+ /* Load embedded data buffer pointers if needed */ -+ if (dev->nodeMETADATA_PAD.streaming && dev->sensor_embedded_data) -+ reg_write_field(dev, UNICAM_DCS, 1, UNICAM_LDP); ++ csi2->discards_tablevci += amount; ++ csi2->discards_dt_tablei = dt; ++ } ++ ++ spin_unlock(&csi2->errors_lock); +} + -+static void unicam_disable(struct unicam_device *dev) ++void csi2_isr(struct csi2_device *csi2, bool *sof, bool *eof) +{ -+ /* Analogue lane control disable */ -+ reg_write_field(dev, UNICAM_ANA, 1, UNICAM_DDL); ++ unsigned int i; ++ u32 status; + -+ /* Stop the output engine */ -+ reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_SOE); ++ status = csi2_reg_read(csi2, CSI2_STATUS); ++ csi2_dbg_verbose("ISR: STA: 0x%x\n", status); + -+ /* Disable the data lanes. */ -+ reg_write(dev, UNICAM_DAT0, 0); -+ reg_write(dev, UNICAM_DAT1, 0); ++ /* Write value back to clear the interrupts */ ++ csi2_reg_write(csi2, CSI2_STATUS, status); + -+ if (dev->max_data_lanes > 2) { -+ reg_write(dev, UNICAM_DAT2, 0); -+ reg_write(dev, UNICAM_DAT3, 0); ++ for (i = 0; i < CSI2_NUM_CHANNELS; i++) { ++ u32 dbg; ++ ++ if ((status & IRQ_CH_MASK(i)) == 0) ++ continue; ++ ++ dbg = csi2_reg_read(csi2, CSI2_CH_DEBUG(i)); ++ ++ csi2_dbg_verbose("ISR: %u, %s%s%s%s%s frame: %u line: %u\n", ++ i, (status & IRQ_FS(i)) ? "FS " : "", ++ (status & IRQ_FE(i)) ? "FE " : "", ++ (status & IRQ_FE_ACK(i)) ? "FE_ACK " : "", ++ (status & IRQ_LE(i)) ? "LE " : "", ++ (status & IRQ_LE_ACK(i)) ? "LE_ACK " : "", ++ dbg >> 16, ++ csi2->num_linesi ? ++ ((dbg & 0xffff) % csi2->num_linesi) : ++ 0); ++ ++ sofi = !!(status & IRQ_FS(i)); ++ eofi = !!(status & IRQ_FE_ACK(i)); + } + -+ /* Peripheral reset */ -+ reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_CPR); -+ usleep_range(50, 100); -+ reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPR); ++ if (csi2_track_errors) ++ csi2_isr_handle_errors(csi2, status); ++} + -+ /* Disable peripheral */ -+ reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPE); ++void csi2_set_buffer(struct csi2_device *csi2, unsigned int channel, ++ dma_addr_t dmaaddr, unsigned int stride, unsigned int size) ++{ ++ u64 addr = dmaaddr; ++ /* ++ * ADDRESS0 must be written last as it triggers the double buffering ++ * mechanism for all buffer registers within the hardware. ++ */ ++ addr >>= 4; ++ csi2_reg_write(csi2, CSI2_CH_LENGTH(channel), size >> 4); ++ csi2_reg_write(csi2, CSI2_CH_STRIDE(channel), stride >> 4); ++ csi2_reg_write(csi2, CSI2_CH_ADDR1(channel), addr >> 32); ++ csi2_reg_write(csi2, CSI2_CH_ADDR0(channel), addr & 0xffffffff); ++} + -+ /* Clear ED setup */ -+ reg_write(dev, UNICAM_DCS, 0); ++void csi2_set_compression(struct csi2_device *csi2, unsigned int channel, ++ enum csi2_compression_mode mode, unsigned int shift, ++ unsigned int offset) ++{ ++ u32 compression = 0; + -+ /* Disable all lane clocks */ -+ clk_write(dev, 0); ++ set_field(&compression, COMP_OFFSET_MASK, offset); ++ set_field(&compression, COMP_SHIFT_MASK, shift); ++ set_field(&compression, COMP_MODE_MASK, mode); ++ csi2_reg_write(csi2, CSI2_CH_COMP_CTRL(channel), compression); +} + -+static void unicam_return_buffers(struct unicam_node *node, -+ enum vb2_buffer_state state) ++static int csi2_get_vc_dt_fallback(struct csi2_device *csi2, ++ unsigned int channel, u8 *vc, u8 *dt) +{ -+ struct unicam_buffer *buf, *tmp; -+ unsigned long flags; ++ struct v4l2_subdev *sd = &csi2->sd; ++ struct v4l2_subdev_state *state; ++ struct v4l2_mbus_framefmt *fmt; ++ const struct cfe_fmt *cfe_fmt; + -+ 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); -+ } ++ state = v4l2_subdev_get_locked_active_state(sd); + -+ 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); ++ /* Without Streams API, the channel number matches the sink pad */ ++ fmt = v4l2_subdev_get_pad_format(sd, state, channel); ++ if (!fmt) ++ return -EINVAL; + -+ node->cur_frm = NULL; -+ node->next_frm = NULL; -+ spin_unlock_irqrestore(&node->dma_queue_lock, flags); ++ cfe_fmt = find_format_by_code(fmt->code); ++ if (!cfe_fmt) ++ return -EINVAL; ++ ++ *vc = 0; ++ *dt = cfe_fmt->csi_dt; ++ ++ return 0; +} + -+static int unicam_start_streaming(struct vb2_queue *vq, unsigned int count) ++static int csi2_get_vc_dt(struct csi2_device *csi2, unsigned int channel, ++ u8 *vc, u8 *dt) +{ -+ struct unicam_node *node = vb2_get_drv_priv(vq); -+ struct unicam_device *dev = node->dev; -+ dma_addr_t buffer_addrMAX_NODES = { 0 }; -+ unsigned long flags; -+ unsigned int i; ++ struct v4l2_mbus_frame_desc remote_desc; ++ const struct media_pad *remote_pad; ++ struct v4l2_subdev *source_sd; + int ret; + -+ node->streaming = true; -+ if (!(dev->nodeIMAGE_PAD.open && dev->nodeIMAGE_PAD.streaming && -+ (!dev->nodeMETADATA_PAD.open || -+ dev->nodeMETADATA_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; ++ /* Without Streams API, the channel number matches the sink pad */ ++ remote_pad = media_pad_remote_pad_first(&csi2->padchannel); ++ if (!remote_pad) ++ return -EPIPE; ++ ++ source_sd = media_entity_to_v4l2_subdev(remote_pad->entity); ++ ++ ret = v4l2_subdev_call(source_sd, pad, get_frame_desc, ++ remote_pad->index, &remote_desc); ++ if (ret == -ENOIOCTLCMD) { ++ csi2_dbg("source does not support get_frame_desc, use fallback\n"); ++ return csi2_get_vc_dt_fallback(csi2, channel, vc, dt); ++ } else if (ret) { ++ csi2_err("Failed to get frame descriptor\n"); ++ return ret; + } + -+ dev->sequence = 0; -+ ret = unicam_runtime_get(dev); -+ if (ret < 0) { -+ unicam_dbg(3, dev, "unicam_runtime_get failed\n"); -+ goto err_streaming; ++ if (remote_desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { ++ csi2_err("Frame descriptor does not describe CSI-2 link"); ++ return -EINVAL; + } + -+ ret = media_pipeline_start(&node->video_dev.entity, &node->pipe); -+ if (ret < 0) { -+ unicam_err(dev, "Failed to start media pipeline: %d\n", ret); -+ goto err_pm_put; ++ if (remote_desc.num_entries != 1) { ++ csi2_err("Frame descriptor does not have a single entry"); ++ return -EINVAL; + } + -+ dev->active_data_lanes = dev->max_data_lanes; ++ *vc = remote_desc.entry0.bus.csi2.vc; ++ *dt = remote_desc.entry0.bus.csi2.dt; + -+ if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) { -+ struct v4l2_mbus_config mbus_config = { 0 }; ++ return 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 error_pipeline; -+ } ++void csi2_start_channel(struct csi2_device *csi2, unsigned int channel, ++ enum csi2_mode mode, bool auto_arm, ++ bool pack_bytes, unsigned int width, ++ unsigned int height) ++{ ++ u32 ctrl; ++ int ret; ++ u8 vc, dt; + -+ 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 error_pipeline; -+ } -+ } ++ ret = csi2_get_vc_dt(csi2, channel, &vc, &dt); ++ if (ret) ++ return; + -+ unicam_dbg(1, dev, "Running with %u data lanes\n", -+ dev->active_data_lanes); ++ csi2_dbg("%s %u\n", __func__, channel); + -+ 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 error_pipeline; -+ } ++ csi2_reg_write(csi2, CSI2_CH_CTRL(channel), 0); ++ csi2_reg_write(csi2, CSI2_CH_DEBUG(channel), 0); ++ csi2_reg_write(csi2, CSI2_STATUS, IRQ_CH_MASK(channel)); + -+ ret = clk_prepare_enable(dev->vpu_clock); -+ if (ret) { -+ unicam_err(dev, "Failed to enable VPU clock: %d\n", ret); -+ goto error_pipeline; -+ } ++ /* Enable channel and FS/FE interrupts. */ ++ ctrl = DMA_EN | IRQ_EN_FS | IRQ_EN_FE_ACK | PACK_LINE; ++ /* PACK_BYTES ensures no striding for embedded data. */ ++ if (pack_bytes) ++ ctrl |= PACK_BYTES; + -+ 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; -+ } ++ if (auto_arm) ++ ctrl |= AUTO_ARM; + -+ ret = clk_prepare_enable(dev->clock); -+ if (ret) { -+ unicam_err(dev, "Failed to enable CSI clock: %d\n", ret); -+ goto err_vpu_clock; ++ if (width && height) { ++ set_field(&ctrl, mode, CH_MODE_MASK); ++ csi2_reg_write(csi2, CSI2_CH_FRAME_SIZE(channel), ++ (height << 16) | width); ++ } else { ++ set_field(&ctrl, 0x0, CH_MODE_MASK); ++ csi2_reg_write(csi2, CSI2_CH_FRAME_SIZE(channel), 0); + } + -+ for (i = 0; i < ARRAY_SIZE(dev->node); i++) { -+ struct unicam_buffer *buf; ++ set_field(&ctrl, vc, VC_MASK); ++ set_field(&ctrl, dt, DT_MASK); ++ csi2_reg_write(csi2, CSI2_CH_CTRL(channel), ctrl); ++ csi2->num_lineschannel = height; ++} + -+ if (!dev->nodei.streaming) -+ continue; ++void csi2_stop_channel(struct csi2_device *csi2, unsigned int channel) ++{ ++ csi2_dbg("%s %u\n", __func__, channel); + -+ spin_lock_irqsave(&dev->nodei.dma_queue_lock, flags); -+ buf = list_first_entry(&dev->nodei.dma_queue, -+ struct unicam_buffer, list); -+ dev->nodei.cur_frm = buf; -+ dev->nodei.next_frm = buf; -+ list_del(&buf->list); -+ spin_unlock_irqrestore(&dev->nodei.dma_queue_lock, flags); ++ /* Channel disable. Use FORCE to allow stopping mid-frame. */ ++ csi2_reg_write(csi2, CSI2_CH_CTRL(channel), FORCE); ++ /* Latch the above change by writing to the ADDR0 register. */ ++ csi2_reg_write(csi2, CSI2_CH_ADDR0(channel), 0); ++ /* Write this again, the HW needs it! */ ++ csi2_reg_write(csi2, CSI2_CH_ADDR0(channel), 0); ++} + -+ buffer_addri = -+ vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); -+ } ++void csi2_open_rx(struct csi2_device *csi2) ++{ ++ csi2_reg_write(csi2, CSI2_IRQ_MASK, ++ csi2_track_errors ? CSI2_IRQ_MASK_IRQ_ALL : 0); + -+ unicam_start_rx(dev, buffer_addr); ++ dphy_start(&csi2->dphy); + -+ 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; -+ } ++ csi2_reg_write(csi2, CSI2_CTRL, ++ csi2->multipacket_line ? 0 : EOP_IS_EOL); ++} + -+ dev->clocks_enabled = true; -+ return 0; ++void csi2_close_rx(struct csi2_device *csi2) ++{ ++ dphy_stop(&csi2->dphy); + -+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); -+error_pipeline: -+ media_pipeline_stop(&node->video_dev.entity); -+err_pm_put: -+ unicam_runtime_put(dev); -+err_streaming: -+ unicam_return_buffers(node, VB2_BUF_STATE_QUEUED); -+ node->streaming = false; ++ csi2_reg_write(csi2, CSI2_IRQ_MASK, 0); ++} + -+ return ret; ++static int csi2_init_cfg(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state) ++{ ++ struct v4l2_mbus_framefmt *fmt; ++ ++ for (unsigned int i = 0; i < CSI2_NUM_CHANNELS; ++i) { ++ const struct v4l2_mbus_framefmt *def_fmt; ++ ++ /* CSI2_CH1_EMBEDDED */ ++ if (i == 1) ++ def_fmt = &cfe_default_meta_format; ++ else ++ def_fmt = &cfe_default_format; ++ ++ fmt = v4l2_subdev_get_pad_format(sd, state, i); ++ *fmt = *def_fmt; ++ ++ fmt = v4l2_subdev_get_pad_format(sd, state, i + CSI2_NUM_CHANNELS); ++ *fmt = *def_fmt; ++ } ++ ++ return 0; +} + -+static void unicam_stop_streaming(struct vb2_queue *vq) ++static int csi2_pad_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_format *format) +{ -+ struct unicam_node *node = vb2_get_drv_priv(vq); -+ struct unicam_device *dev = node->dev; ++ if (format->pad < CSI2_NUM_CHANNELS) { ++ /* ++ * Store the sink pad format and propagate it to the source pad. ++ */ + -+ node->streaming = false; ++ struct v4l2_mbus_framefmt *fmt; + -+ if (node->pad_id == IMAGE_PAD) { ++ fmt = v4l2_subdev_get_pad_format(sd, state, format->pad); ++ if (!fmt) ++ return -EINVAL; ++ ++ *fmt = format->format; ++ ++ fmt = v4l2_subdev_get_pad_format(sd, state, ++ format->pad + CSI2_NUM_CHANNELS); ++ if (!fmt) ++ return -EINVAL; ++ ++ format->format.field = V4L2_FIELD_NONE; ++ ++ *fmt = format->format; ++ } else { + /* -+ * Stop streaming the sensor and disable the peripheral. -+ * We cannot continue streaming embedded data with the -+ * image pad disabled. ++ * Only allow changing the source pad mbus code. + */ -+ if (v4l2_subdev_call(dev->sensor, video, s_stream, 0) < 0) -+ unicam_err(dev, "stream off failed in subdev\n"); + -+ unicam_disable(dev); ++ struct v4l2_mbus_framefmt *sink_fmt, *source_fmt; ++ u32 sink_code; ++ u32 code; + -+ media_pipeline_stop(&node->video_dev.entity); ++ sink_fmt = v4l2_subdev_get_pad_format(sd, state, ++ format->pad - CSI2_NUM_CHANNELS); ++ if (!sink_fmt) ++ return -EINVAL; + -+ 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); ++ source_fmt = v4l2_subdev_get_pad_format(sd, state, format->pad); ++ if (!source_fmt) ++ return -EINVAL; ++ ++ sink_code = sink_fmt->code; ++ code = format->format.code; + -+ } 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. ++ * If the source code from the user does not match the code in ++ * the sink pad, check that the source code matches either the ++ * 16-bit version or the compressed version of the sink code. + */ -+ unicam_wr_dma_addr(dev, node->dummy_buf_dma_addr, -+ DUMMY_BUF_SIZE, METADATA_PAD); ++ ++ if (code != sink_code && ++ (code == cfe_find_16bit_code(sink_code) || ++ code == cfe_find_compressed_code(sink_code))) ++ source_fmt->code = code; ++ ++ format->format.code = source_fmt->code; + } + -+ /* Clear all queued buffers for the node */ -+ unicam_return_buffers(node, VB2_BUF_STATE_ERROR); ++ return 0; +} + ++static const struct v4l2_subdev_pad_ops csi2_subdev_pad_ops = { ++ .init_cfg = csi2_init_cfg, ++ .get_fmt = v4l2_subdev_get_fmt, ++ .set_fmt = csi2_pad_set_fmt, ++ .link_validate = v4l2_subdev_link_validate_default, ++}; + -+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, ++static const struct media_entity_operations csi2_entity_ops = { ++ .link_validate = v4l2_subdev_link_validate, +}; + -+/* -+ * 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) ++static const struct v4l2_subdev_ops csi2_subdev_ops = { ++ .pad = &csi2_subdev_pad_ops, ++}; ++ ++int csi2_init(struct csi2_device *csi2, struct dentry *debugfs) +{ -+ struct unicam_node *node = video_drvdata(file); -+ struct unicam_device *dev = node->dev; -+ int ret; ++ unsigned int i, ret; + -+ mutex_lock(&node->lock); ++ spin_lock_init(&csi2->errors_lock); + -+ ret = v4l2_fh_open(file); -+ if (ret) { -+ unicam_err(dev, "v4l2_fh_open failed\n"); -+ goto unlock; -+ } ++ csi2->dphy.dev = csi2->v4l2_dev->dev; ++ dphy_probe(&csi2->dphy); + -+ node->open++; ++ debugfs_create_file("csi2_regs", 0444, debugfs, csi2, &csi2_regs_fops); + -+ if (!v4l2_fh_is_singular_file(file)) -+ goto unlock; ++ if (csi2_track_errors) ++ debugfs_create_file("csi2_errors", 0444, debugfs, csi2, ++ &csi2_errors_fops); + -+ ret = v4l2_subdev_call(dev->sensor, core, s_power, 1); -+ if (ret < 0 && ret != -ENOIOCTLCMD) { -+ v4l2_fh_release(file); -+ node->open--; -+ goto unlock; ++ for (i = 0; i < CSI2_NUM_CHANNELS * 2; i++) ++ csi2->padi.flags = i < CSI2_NUM_CHANNELS ? ++ MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&csi2->sd.entity, ARRAY_SIZE(csi2->pad), ++ csi2->pad); ++ if (ret) ++ return ret; ++ ++ /* Initialize subdev */ ++ v4l2_subdev_init(&csi2->sd, &csi2_subdev_ops); ++ csi2->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; ++ csi2->sd.entity.ops = &csi2_entity_ops; ++ csi2->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ csi2->sd.owner = THIS_MODULE; ++ snprintf(csi2->sd.name, sizeof(csi2->sd.name), "csi2"); ++ ++ ret = v4l2_subdev_init_finalize(&csi2->sd); ++ if (ret) ++ goto err_entity_cleanup; ++ ++ ret = v4l2_device_register_subdev(csi2->v4l2_dev, &csi2->sd); ++ if (ret) { ++ csi2_err("Failed register csi2 subdev (%d)\n", ret); ++ goto err_subdev_cleanup; + } + -+ ret = 0; ++ return 0; ++ ++err_subdev_cleanup: ++ v4l2_subdev_cleanup(&csi2->sd); ++err_entity_cleanup: ++ media_entity_cleanup(&csi2->sd.entity); + -+unlock: -+ mutex_unlock(&node->lock); + return ret; +} + -+static int unicam_v4l2_release(struct file *file) ++void csi2_uninit(struct csi2_device *csi2) +{ -+ struct unicam_node *node = video_drvdata(file); -+ struct unicam_device *dev = node->dev; -+ struct v4l2_subdev *sd = dev->sensor; -+ bool fh_singular; -+ int ret; ++ v4l2_device_unregister_subdev(&csi2->sd); ++ v4l2_subdev_cleanup(&csi2->sd); ++ media_entity_cleanup(&csi2->sd.entity); ++} +diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/csi2.h b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.h +new file mode 100644 +index 000000000000..4fff16ee9407 +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.h +@@ -0,0 +1,90 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * RP1 CSI-2 driver. ++ * Copyright (c) 2021 Raspberry Pi Ltd. ++ * ++ */ ++#ifndef _RP1_CSI2_ ++#define _RP1_CSI2_ + -+ mutex_lock(&node->lock); ++#include <linux/debugfs.h> ++#include <linux/io.h> ++#include <linux/types.h> ++#include <media/v4l2-device.h> ++#include <media/v4l2-subdev.h> + -+ fh_singular = v4l2_fh_is_singular_file(file); ++#include "dphy.h" + -+ ret = _vb2_fop_release(file, NULL); ++#define CSI2_NUM_CHANNELS 4 + -+ if (fh_singular) -+ v4l2_subdev_call(sd, core, s_power, 0); ++#define DISCARDS_TABLE_NUM_VCS 4 + -+ node->open--; -+ mutex_unlock(&node->lock); ++enum csi2_mode { ++ CSI2_MODE_NORMAL = 0, ++ CSI2_MODE_REMAP = 1, ++ CSI2_MODE_COMPRESSED = 2, ++ CSI2_MODE_FE_STREAMING = 3, ++}; + -+ return ret; -+} ++enum csi2_compression_mode { ++ CSI2_COMPRESSION_DELTA = 1, ++ CSI2_COMPRESSION_SIMPLE = 2, ++ CSI2_COMPRESSION_COMBINED = 3, ++}; + -+/* 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, ++struct csi2_cfg { ++ u16 width; ++ u16 height; ++ u32 stride; ++ u32 buffer_size; +}; + -+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); ++enum discards_table_index { ++ DISCARDS_TABLE_OVERFLOW = 0, ++ DISCARDS_TABLE_LENGTH_LIMIT, ++ DISCARDS_TABLE_UNMATCHED, ++ DISCARDS_TABLE_INACTIVE, ++ DISCARDS_TABLE_NUM_ENTRIES, ++}; + -+ if (unicam->sensor) { -+ unicam_info(unicam, "Rejecting subdev %s (Already set!!)", -+ subdev->name); -+ return 0; -+ } ++struct csi2_device { ++ /* Parent V4l2 device */ ++ struct v4l2_device *v4l2_dev; + -+ unicam->sensor = subdev; -+ unicam_dbg(1, unicam, "Using sensor %s for capture\n", subdev->name); ++ void __iomem *base; + -+ return 0; -+} ++ struct dphy_data dphy; + -+static void unicam_release(struct kref *kref) ++ enum v4l2_mbus_type bus_type; ++ unsigned int bus_flags; ++ bool multipacket_line; ++ unsigned int num_linesCSI2_NUM_CHANNELS; ++ ++ struct media_pad padCSI2_NUM_CHANNELS * 2; ++ struct v4l2_subdev sd; ++ ++ /* lock for csi2 errors counters */ ++ spinlock_t errors_lock; ++ u32 overflows; ++ u32 discards_tableDISCARDS_TABLE_NUM_VCSDISCARDS_TABLE_NUM_ENTRIES; ++ u32 discards_dt_tableDISCARDS_TABLE_NUM_ENTRIES; ++}; ++ ++void csi2_isr(struct csi2_device *csi2, bool *sof, bool *eof); ++void csi2_set_buffer(struct csi2_device *csi2, unsigned int channel, ++ dma_addr_t dmaaddr, unsigned int stride, ++ unsigned int size); ++void csi2_set_compression(struct csi2_device *csi2, unsigned int channel, ++ enum csi2_compression_mode mode, unsigned int shift, ++ unsigned int offset); ++void csi2_start_channel(struct csi2_device *csi2, unsigned int channel, ++ enum csi2_mode mode, bool auto_arm, ++ bool pack_bytes, unsigned int width, ++ unsigned int height); ++void csi2_stop_channel(struct csi2_device *csi2, unsigned int channel); ++void csi2_open_rx(struct csi2_device *csi2); ++void csi2_close_rx(struct csi2_device *csi2); ++int csi2_init(struct csi2_device *csi2, struct dentry *debugfs); ++void csi2_uninit(struct csi2_device *csi2); ++ ++#endif +diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/dphy.c b/drivers/media/platform/raspberrypi/rp1_cfe/dphy.c +new file mode 100644 +index 000000000000..28ea3215fff5 +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/dphy.c +@@ -0,0 +1,177 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * RP1 CSI-2 Driver ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd. ++ * ++ */ ++ ++#include <linux/delay.h> ++#include <linux/dev_printk.h> ++#include <linux/pm_runtime.h> ++ ++#include "dphy.h" ++ ++#define dphy_dbg(fmt, arg...) dev_dbg(dphy->dev, fmt, ##arg) ++#define dphy_info(fmt, arg...) dev_info(dphy->dev, fmt, ##arg) ++#define dphy_err(fmt, arg...) dev_err(dphy->dev, fmt, ##arg) ++ ++/* DW dphy Host registers */ ++#define VERSION 0x000 ++#define N_LANES 0x004 ++#define RESETN 0x008 ++#define PHY_SHUTDOWNZ 0x040 ++#define PHY_RSTZ 0x044 ++#define PHY_RX 0x048 ++#define PHY_STOPSTATE 0x04c ++#define PHY_TST_CTRL0 0x050 ++#define PHY_TST_CTRL1 0x054 ++#define PHY2_TST_CTRL0 0x058 ++#define PHY2_TST_CTRL1 0x05c ++ ++/* DW dphy Host Transactions */ ++#define DPHY_HS_RX_CTRL_LANE0_OFFSET 0x44 ++#define DPHY_PLL_INPUT_DIV_OFFSET 0x17 ++#define DPHY_PLL_LOOP_DIV_OFFSET 0x18 ++#define DPHY_PLL_DIV_CTRL_OFFSET 0x19 ++ ++static u32 dw_csi2_host_read(struct dphy_data *dphy, u32 offset) +{ -+ struct unicam_device *unicam = -+ container_of(kref, struct unicam_device, kref); ++ return readl(dphy->base + offset); ++} + -+ v4l2_ctrl_handler_free(&unicam->ctrl_handler); -+ media_device_cleanup(&unicam->mdev); ++static void dw_csi2_host_write(struct dphy_data *dphy, u32 offset, u32 data) ++{ ++ writel(data, dphy->base + offset); ++} + -+ if (unicam->sensor_config) -+ v4l2_subdev_free_pad_config(unicam->sensor_config); ++static void set_tstclr(struct dphy_data *dphy, u32 val) ++{ ++ u32 ctrl0 = dw_csi2_host_read(dphy, PHY_TST_CTRL0); + -+ kfree(unicam); ++ dw_csi2_host_write(dphy, PHY_TST_CTRL0, (ctrl0 & ~1) | val); +} + -+static void unicam_put(struct unicam_device *unicam) ++static void set_tstclk(struct dphy_data *dphy, u32 val) +{ -+ kref_put(&unicam->kref, unicam_release); ++ u32 ctrl0 = dw_csi2_host_read(dphy, PHY_TST_CTRL0); ++ ++ dw_csi2_host_write(dphy, PHY_TST_CTRL0, (ctrl0 & ~2) | (val << 1)); +} + -+static void unicam_get(struct unicam_device *unicam) ++static uint8_t get_tstdout(struct dphy_data *dphy) +{ -+ kref_get(&unicam->kref); ++ u32 ctrl1 = dw_csi2_host_read(dphy, PHY_TST_CTRL1); ++ ++ return ((ctrl1 >> 8) & 0xff); +} + -+static void unicam_node_release(struct video_device *vdev) ++static void set_testen(struct dphy_data *dphy, u32 val) +{ -+ struct unicam_node *node = video_get_drvdata(vdev); ++ u32 ctrl1 = dw_csi2_host_read(dphy, PHY_TST_CTRL1); + -+ unicam_put(node->dev); ++ dw_csi2_host_write(dphy, PHY_TST_CTRL1, ++ (ctrl1 & ~(1 << 16)) | (val << 16)); +} + -+static int unicam_set_default_format(struct unicam_device *unicam, -+ struct unicam_node *node, -+ int pad_id, -+ const struct unicam_fmt **ret_fmt) ++static void set_testdin(struct dphy_data *dphy, u32 val) +{ -+ struct v4l2_mbus_framefmt mbus_fmt = {0}; -+ const struct unicam_fmt *fmt; -+ int ret; ++ u32 ctrl1 = dw_csi2_host_read(dphy, PHY_TST_CTRL1); + -+ 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; -+ } ++ dw_csi2_host_write(dphy, PHY_TST_CTRL1, (ctrl1 & ~0xff) | val); ++} + -+ 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); ++static uint8_t dphy_transaction(struct dphy_data *dphy, u8 test_code, ++ uint8_t test_data) ++{ ++ /* See page 101 of the MIPI DPHY databook. */ ++ set_tstclk(dphy, 1); ++ set_testen(dphy, 0); ++ set_testdin(dphy, test_code); ++ set_testen(dphy, 1); ++ set_tstclk(dphy, 0); ++ set_testen(dphy, 0); ++ set_testdin(dphy, test_data); ++ set_tstclk(dphy, 1); ++ return get_tstdout(dphy); ++} + -+ if (fmt) { -+ 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; -+ } ++static void dphy_set_hsfreqrange(struct dphy_data *dphy, uint32_t mbps) ++{ ++ /* See Table 5-1 on page 65 of dphy databook */ ++ static const u16 hsfreqrange_table2 = { ++ { 89, 0b000000 }, { 99, 0b010000 }, { 109, 0b100000 }, ++ { 129, 0b000001 }, { 139, 0b010001 }, { 149, 0b100001 }, ++ { 169, 0b000010 }, { 179, 0b010010 }, { 199, 0b100010 }, ++ { 219, 0b000011 }, { 239, 0b010011 }, { 249, 0b100011 }, ++ { 269, 0b000100 }, { 299, 0b010100 }, { 329, 0b000101 }, ++ { 359, 0b010101 }, { 399, 0b100101 }, { 449, 0b000110 }, ++ { 499, 0b010110 }, { 549, 0b000111 }, { 599, 0b010111 }, ++ { 649, 0b001000 }, { 699, 0b011000 }, { 749, 0b001001 }, ++ { 799, 0b011001 }, { 849, 0b101001 }, { 899, 0b111001 }, ++ { 949, 0b001010 }, { 999, 0b011010 }, { 1049, 0b101010 }, ++ { 1099, 0b111010 }, { 1149, 0b001011 }, { 1199, 0b011011 }, ++ { 1249, 0b101011 }, { 1299, 0b111011 }, { 1349, 0b001100 }, ++ { 1399, 0b011100 }, { 1449, 0b101100 }, { 1500, 0b111100 }, ++ }; ++ unsigned int i; + -+ if (fmt) -+ 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; -+ } ++ if (mbps < 80 || mbps > 1500) ++ dphy_err("DPHY: Datarate %u Mbps out of range\n", mbps); + -+ *ret_fmt = fmt; ++ for (i = 0; i < ARRAY_SIZE(hsfreqrange_table) - 1; i++) { ++ if (mbps <= hsfreqrange_tablei0) ++ break; ++ } + -+ return 0; ++ dphy_transaction(dphy, DPHY_HS_RX_CTRL_LANE0_OFFSET, ++ hsfreqrange_tablei1 << 1); +} + -+static void unicam_mc_set_default_format(struct unicam_node *node, int pad_id) ++static void dphy_init(struct dphy_data *dphy) +{ -+ if (pad_id == IMAGE_PAD) { -+ struct v4l2_pix_format *pix_fmt = &node->v_fmt.fmt.pix; ++ dw_csi2_host_write(dphy, PHY_RSTZ, 0); ++ dw_csi2_host_write(dphy, PHY_SHUTDOWNZ, 0); ++ set_tstclk(dphy, 1); ++ set_testen(dphy, 0); ++ set_tstclr(dphy, 1); ++ usleep_range(15, 20); ++ set_tstclr(dphy, 0); ++ usleep_range(15, 20); + -+ pix_fmt->width = 640; -+ pix_fmt->height = 480; -+ pix_fmt->field = V4L2_FIELD_NONE; -+ pix_fmt->colorspace = V4L2_COLORSPACE_SRGB; -+ pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; -+ pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; -+ pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; -+ pix_fmt->pixelformat = formats0.fourcc; -+ unicam_calc_format_size_bpl(node->dev, &formats0, -+ &node->v_fmt); -+ node->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ dphy_set_hsfreqrange(dphy, dphy->dphy_rate); + -+ node->fmt = &formats0; -+ } else { -+ const struct unicam_fmt *fmt; ++ usleep_range(5, 10); ++ dw_csi2_host_write(dphy, PHY_SHUTDOWNZ, 1); ++ usleep_range(5, 10); ++ dw_csi2_host_write(dphy, PHY_RSTZ, 1); ++} + -+ /* 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->fmt = fmt; ++void dphy_start(struct dphy_data *dphy) ++{ ++ dw_csi2_host_write(dphy, N_LANES, (dphy->active_lanes - 1)); ++ dphy_init(dphy); ++ dw_csi2_host_write(dphy, RESETN, 0xffffffff); ++ usleep_range(10, 50); ++} + -+ node->v_fmt.fmt.meta.buffersize = UNICAM_EMBEDDED_SIZE; -+ node->embedded_lines = 1; -+ node->v_fmt.type = V4L2_BUF_TYPE_META_CAPTURE; -+ } ++void dphy_stop(struct dphy_data *dphy) ++{ ++ /* Set only one lane (lane 0) as active (ON) */ ++ dw_csi2_host_write(dphy, N_LANES, 0); ++ dw_csi2_host_write(dphy, RESETN, 0); +} + -+static int register_node(struct unicam_device *unicam, struct unicam_node *node, -+ enum v4l2_buf_type type, int pad_id) ++void dphy_probe(struct dphy_data *dphy) +{ -+ struct video_device *vdev; -+ struct vb2_queue *q; -+ int ret; ++ u32 host_ver; ++ u8 host_ver_major, host_ver_minor; + -+ node->dev = unicam; -+ node->pad_id = pad_id; ++ host_ver = dw_csi2_host_read(dphy, VERSION); ++ host_ver_major = (u8)((host_ver >> 24) - '0'); ++ host_ver_minor = (u8)((host_ver >> 16) - '0'); ++ host_ver_minor = host_ver_minor * 10; ++ host_ver_minor += (u8)((host_ver >> 8) - '0'); + -+ if (!unicam->mc_api) { -+ const struct unicam_fmt *fmt; ++ dphy_info("DW dphy Host HW v%u.%u\n", host_ver_major, host_ver_minor); ++} +diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/dphy.h b/drivers/media/platform/raspberrypi/rp1_cfe/dphy.h +new file mode 100644 +index 000000000000..9d7a80b3f684 +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/dphy.h +@@ -0,0 +1,27 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (c) 2021 Raspberry Pi Ltd. ++ * ++ */ + -+ ret = unicam_set_default_format(unicam, node, pad_id, &fmt); -+ if (ret) -+ return ret; -+ node->fmt = fmt; -+ /* Read current subdev format */ -+ if (fmt) -+ unicam_reset_format(node); -+ } else { -+ unicam_mc_set_default_format(node, pad_id); -+ } ++#ifndef _RP1_DPHY_ ++#define _RP1_DPHY_ + -+ if (!unicam->mc_api && -+ v4l2_subdev_has_op(unicam->sensor, video, s_std)) { -+ v4l2_std_id tvnorms; ++#include <linux/io.h> ++#include <linux/types.h> + -+ if (WARN_ON(!v4l2_subdev_has_op(unicam->sensor, video, -+ g_tvnorms))) -+ /* -+ * Subdevice should not advertise s_std but not -+ * g_tvnorms -+ */ -+ return -EINVAL; ++struct dphy_data { ++ struct device *dev; + -+ ret = v4l2_subdev_call(unicam->sensor, video, -+ g_tvnorms, &tvnorms); -+ if (WARN_ON(ret)) -+ return -EINVAL; -+ node->video_dev.tvnorms |= tvnorms; -+ } ++ void __iomem *base; + -+ spin_lock_init(&node->dma_queue_lock); -+ mutex_init(&node->lock); ++ u32 dphy_rate; ++ u32 max_lanes; ++ u32 active_lanes; ++}; + -+ vdev = &node->video_dev; -+ if (pad_id == IMAGE_PAD) { -+ if (!unicam->mc_api) { -+ /* Add controls from the subdevice */ -+ ret = v4l2_ctrl_add_handler(&unicam->ctrl_handler, -+ unicam->sensor->ctrl_handler, -+ NULL, -+ true); -+ if (ret < 0) -+ return ret; -+ } ++void dphy_probe(struct dphy_data *dphy); ++void dphy_start(struct dphy_data *dphy); ++void dphy_stop(struct dphy_data *dphy); + -+ /* -+ * 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; -+ } ++#endif +diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/pisp_common.h b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_common.h +new file mode 100644 +index 000000000000..e91aa2ed3659 +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_common.h +@@ -0,0 +1,69 @@ ++/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ ++/* ++ * RP1 PiSP common definitions. ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd. ++ * ++ */ ++#ifndef _PISP_COMMON_H_ ++#define _PISP_COMMON_H_ + -+ 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; ++#include "pisp_types.h" + -+ ret = vb2_queue_init(q); -+ if (ret) { -+ unicam_err(unicam, "vb2_queue_init() failed\n"); -+ return ret; -+ } ++struct pisp_bla_config { ++ u16 black_level_r; ++ u16 black_level_gr; ++ u16 black_level_gb; ++ u16 black_level_b; ++ u16 output_black_level; ++ u8 pad2; ++}; + -+ INIT_LIST_HEAD(&node->dma_queue); ++struct pisp_wbg_config { ++ u16 gain_r; ++ u16 gain_g; ++ u16 gain_b; ++ u8 pad2; ++}; + -+ vdev->release = unicam_node_release; -+ vdev->fops = &unicam_fops; -+ vdev->ioctl_ops = unicam->mc_api ? &unicam_mc_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; -+ if (unicam->mc_api) { -+ vdev->device_caps |= V4L2_CAP_IO_MC; -+ vdev->entity.ops = &unicam_mc_entity_ops; -+ } ++struct pisp_compress_config { ++ /* value subtracted from incoming data */ ++ u16 offset; ++ u8 pad; ++ /* 1 => Companding; 2 => Delta (recommended); 3 => Combined (for HDR) */ ++ u8 mode; ++}; + -+ /* Define the device names */ -+ snprintf(vdev->name, sizeof(vdev->name), "%s-%s", UNICAM_MODULE_NAME, -+ pad_id == IMAGE_PAD ? "image" : "embedded"); ++struct pisp_decompress_config { ++ /* value added to reconstructed data */ ++ u16 offset; ++ u8 pad; ++ /* 1 => Companding; 2 => Delta (recommended); 3 => Combined (for HDR) */ ++ u8 mode; ++}; + -+ 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); ++enum pisp_axi_flags { ++ /* ++ * round down bursts to end at a 32-byte boundary, to align following ++ * bursts ++ */ ++ PISP_AXI_FLAG_ALIGN = 128, ++ /* for FE writer: force WSTRB high, to pad output to 16-byte boundary */ ++ PISP_AXI_FLAG_PAD = 64, ++ /* for FE writer: Use Output FIFO level to trigger "panic" */ ++ PISP_AXI_FLAG_PANIC = 32, ++}; + -+ 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 (!unicam->mc_api) { -+ 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); ++struct pisp_axi_config { ++ /* ++ * burst length minus one, which must be in the range 0:15; OR'd with ++ * flags ++ */ ++ u8 maxlen_flags; ++ /* { prot2:0, cache3:0 } fields, echoed on AXI bus */ ++ u8 cache_prot; ++ /* QoS field(s) (4x4 bits for FE writer; 4 bits for other masters) */ ++ u16 qos; ++}; + -+ if (pad_id == METADATA_PAD || -+ !v4l2_subdev_has_op(unicam->sensor, pad, -+ enum_frame_size)) -+ v4l2_disable_ioctl(&node->video_dev, -+ VIDIOC_ENUM_FRAMESIZES); ++#endif /* _PISP_COMMON_H_ */ +diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c +new file mode 100644 +index 000000000000..93dc4ec4e689 +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c +@@ -0,0 +1,565 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * PiSP Front End driver. ++ * Copyright (c) 2021 Raspberry Pi Ltd. ++ * ++ */ + -+ if (node->pad_id == METADATA_PAD || -+ !v4l2_subdev_has_op(unicam->sensor, pad, set_selection)) -+ v4l2_disable_ioctl(&node->video_dev, -+ VIDIOC_S_SELECTION); ++#include <linux/bitops.h> ++#include <linux/delay.h> ++#include <linux/moduleparam.h> ++#include <linux/pm_runtime.h> ++#include <linux/seq_file.h> + -+ if (node->pad_id == METADATA_PAD || -+ !v4l2_subdev_has_op(unicam->sensor, pad, get_selection)) -+ v4l2_disable_ioctl(&node->video_dev, -+ VIDIOC_G_SELECTION); -+ } ++#include <media/videobuf2-dma-contig.h> + -+ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); -+ if (ret) { -+ unicam_err(unicam, "Unable to register video device %s\n", -+ vdev->name); ++#include "pisp_fe.h" ++#include "cfe.h" ++ ++#define FE_VERSION 0x000 ++#define FE_CONTROL 0x004 ++#define FE_STATUS 0x008 ++#define FE_FRAME_STATUS 0x00c ++#define FE_ERROR_STATUS 0x010 ++#define FE_OUTPUT_STATUS 0x014 ++#define FE_INT_EN 0x018 ++#define FE_INT_STATUS 0x01c ++ ++/* CONTROL */ ++#define FE_CONTROL_QUEUE BIT(0) ++#define FE_CONTROL_ABORT BIT(1) ++#define FE_CONTROL_RESET BIT(2) ++#define FE_CONTROL_LATCH_REGS BIT(3) ++ ++/* INT_EN / INT_STATUS */ ++#define FE_INT_EOF BIT(0) ++#define FE_INT_SOF BIT(1) ++#define FE_INT_LINES0 BIT(8) ++#define FE_INT_LINES1 BIT(9) ++#define FE_INT_STATS BIT(16) ++#define FE_INT_QREADY BIT(24) ++ ++/* STATUS */ ++#define FE_STATUS_QUEUED BIT(0) ++#define FE_STATUS_WAITING BIT(1) ++#define FE_STATUS_ACTIVE BIT(2) ++ ++#define PISP_FE_CONFIG_BASE_OFFSET 0x0040 ++ ++#define PISP_FE_ENABLE_STATS_CLUSTER \ ++ (PISP_FE_ENABLE_STATS_CROP | PISP_FE_ENABLE_DECIMATE | \ ++ PISP_FE_ENABLE_BLC | PISP_FE_ENABLE_CDAF_STATS | \ ++ PISP_FE_ENABLE_AWB_STATS | PISP_FE_ENABLE_RGBY | \ ++ PISP_FE_ENABLE_LSC | PISP_FE_ENABLE_AGC_STATS) ++ ++#define PISP_FE_ENABLE_OUTPUT_CLUSTER(i) \ ++ ((PISP_FE_ENABLE_CROP0 | PISP_FE_ENABLE_DOWNSCALE0 | \ ++ PISP_FE_ENABLE_COMPRESS0 | PISP_FE_ENABLE_OUTPUT0) << (4 * (i))) ++ ++struct pisp_fe_config_param { ++ u32 dirty_flags; ++ u32 dirty_flags_extra; ++ size_t offset; ++ size_t size; ++}; ++ ++static const struct pisp_fe_config_param pisp_fe_config_map = { ++ /* *_dirty_flag_extra types */ ++ { 0, PISP_FE_DIRTY_GLOBAL, offsetof(struct pisp_fe_config, global), ++ sizeof(struct pisp_fe_global_config) }, ++ { 0, PISP_FE_DIRTY_FLOATING, offsetof(struct pisp_fe_config, floating_stats), ++ sizeof(struct pisp_fe_floating_stats_config) }, ++ { 0, PISP_FE_DIRTY_OUTPUT_AXI, offsetof(struct pisp_fe_config, output_axi), ++ sizeof(struct pisp_fe_output_axi_config) }, ++ /* *_dirty_flag types */ ++ { PISP_FE_ENABLE_INPUT, 0, offsetof(struct pisp_fe_config, input), ++ sizeof(struct pisp_fe_input_config) }, ++ { PISP_FE_ENABLE_DECOMPRESS, 0, offsetof(struct pisp_fe_config, decompress), ++ sizeof(struct pisp_decompress_config) }, ++ { PISP_FE_ENABLE_DECOMPAND, 0, offsetof(struct pisp_fe_config, decompand), ++ sizeof(struct pisp_fe_decompand_config) }, ++ { PISP_FE_ENABLE_BLA, 0, offsetof(struct pisp_fe_config, bla), ++ sizeof(struct pisp_bla_config) }, ++ { PISP_FE_ENABLE_DPC, 0, offsetof(struct pisp_fe_config, dpc), ++ sizeof(struct pisp_fe_dpc_config) }, ++ { PISP_FE_ENABLE_STATS_CROP, 0, offsetof(struct pisp_fe_config, stats_crop), ++ sizeof(struct pisp_fe_crop_config) }, ++ { PISP_FE_ENABLE_BLC, 0, offsetof(struct pisp_fe_config, blc), ++ sizeof(struct pisp_bla_config) }, ++ { PISP_FE_ENABLE_CDAF_STATS, 0, offsetof(struct pisp_fe_config, cdaf_stats), ++ sizeof(struct pisp_fe_cdaf_stats_config) }, ++ { PISP_FE_ENABLE_AWB_STATS, 0, offsetof(struct pisp_fe_config, awb_stats), ++ sizeof(struct pisp_fe_awb_stats_config) }, ++ { PISP_FE_ENABLE_RGBY, 0, offsetof(struct pisp_fe_config, rgby), ++ sizeof(struct pisp_fe_rgby_config) }, ++ { PISP_FE_ENABLE_LSC, 0, offsetof(struct pisp_fe_config, lsc), ++ sizeof(struct pisp_fe_lsc_config) }, ++ { PISP_FE_ENABLE_AGC_STATS, 0, offsetof(struct pisp_fe_config, agc_stats), ++ sizeof(struct pisp_agc_statistics) }, ++ { PISP_FE_ENABLE_CROP0, 0, offsetof(struct pisp_fe_config, ch0.crop), ++ sizeof(struct pisp_fe_crop_config) }, ++ { PISP_FE_ENABLE_DOWNSCALE0, 0, offsetof(struct pisp_fe_config, ch0.downscale), ++ sizeof(struct pisp_fe_downscale_config) }, ++ { PISP_FE_ENABLE_COMPRESS0, 0, offsetof(struct pisp_fe_config, ch0.compress), ++ sizeof(struct pisp_compress_config) }, ++ { PISP_FE_ENABLE_OUTPUT0, 0, offsetof(struct pisp_fe_config, ch0.output), ++ sizeof(struct pisp_fe_output_config) }, ++ { PISP_FE_ENABLE_CROP1, 0, offsetof(struct pisp_fe_config, ch1.crop), ++ sizeof(struct pisp_fe_crop_config) }, ++ { PISP_FE_ENABLE_DOWNSCALE1, 0, offsetof(struct pisp_fe_config, ch1.downscale), ++ sizeof(struct pisp_fe_downscale_config) }, ++ { PISP_FE_ENABLE_COMPRESS1, 0, offsetof(struct pisp_fe_config, ch1.compress), ++ sizeof(struct pisp_compress_config) }, ++ { PISP_FE_ENABLE_OUTPUT1, 0, offsetof(struct pisp_fe_config, ch1.output), ++ sizeof(struct pisp_fe_output_config) }, ++}; ++ ++#define pisp_fe_dbg_verbose(fmt, arg...) \ ++ do { \ ++ if (cfe_debug_verbose) \ ++ dev_dbg(fe->v4l2_dev->dev, fmt, ##arg); \ ++ } while (0) ++#define pisp_fe_dbg(fmt, arg...) dev_dbg(fe->v4l2_dev->dev, fmt, ##arg) ++#define pisp_fe_info(fmt, arg...) dev_info(fe->v4l2_dev->dev, fmt, ##arg) ++#define pisp_fe_err(fmt, arg...) dev_err(fe->v4l2_dev->dev, fmt, ##arg) ++ ++static inline u32 pisp_fe_reg_read(struct pisp_fe_device *fe, u32 offset) ++{ ++ return readl(fe->base + offset); ++} ++ ++static inline void pisp_fe_reg_write(struct pisp_fe_device *fe, u32 offset, ++ u32 val) ++{ ++ writel(val, fe->base + offset); ++ pisp_fe_dbg_verbose("fe: write 0x%04x -> 0x%03x\n", val, offset); ++} ++ ++static inline void pisp_fe_reg_write_relaxed(struct pisp_fe_device *fe, u32 offset, ++ u32 val) ++{ ++ writel_relaxed(val, fe->base + offset); ++ pisp_fe_dbg_verbose("fe: write 0x%04x -> 0x%03x\n", val, offset); ++} ++ ++static int pisp_regs_show(struct seq_file *s, void *data) ++{ ++ struct pisp_fe_device *fe = s->private; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(fe->v4l2_dev->dev); ++ if (ret) + 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; ++ pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_LATCH_REGS); + -+ if (pad_id != METADATA_PAD || unicam->sensor_embedded_data) { -+ ret = media_create_pad_link(&unicam->sensor->entity, -+ node->src_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); -+ } ++#define DUMP(reg) seq_printf(s, #reg " \t0x%08x\n", pisp_fe_reg_read(fe, reg)) ++ DUMP(FE_VERSION); ++ DUMP(FE_CONTROL); ++ DUMP(FE_STATUS); ++ DUMP(FE_FRAME_STATUS); ++ DUMP(FE_ERROR_STATUS); ++ DUMP(FE_OUTPUT_STATUS); ++ DUMP(FE_INT_EN); ++ DUMP(FE_INT_STATUS); ++#undef DUMP + -+ return ret; ++ pm_runtime_put(fe->v4l2_dev->dev); ++ ++ return 0; +} + -+static void unregister_nodes(struct unicam_device *unicam) ++DEFINE_SHOW_ATTRIBUTE(pisp_regs); ++ ++static void pisp_config_write(struct pisp_fe_device *fe, ++ struct pisp_fe_config *config, ++ unsigned int start_offset, ++ unsigned int size) ++{ ++ const unsigned int max_offset = ++ offsetof(struct pisp_fe_config, chPISP_FE_NUM_OUTPUTS); ++ unsigned int i, end_offset; ++ u32 *cfg = (u32 *)config; ++ ++ start_offset = min(start_offset, max_offset); ++ end_offset = min(start_offset + size, max_offset); ++ ++ cfg += start_offset >> 2; ++ for (i = start_offset; i < end_offset; i += 4, cfg++) ++ pisp_fe_reg_write_relaxed(fe, PISP_FE_CONFIG_BASE_OFFSET + i, ++ *cfg); ++} ++ ++void pisp_fe_isr(struct pisp_fe_device *fe, bool *sof, bool *eof) +{ ++ u32 status, int_status, out_status, frame_status, error_status; + unsigned int i; + -+ for (i = 0; i < ARRAY_SIZE(unicam->node); i++) { -+ struct unicam_node *node = &unicam->nodei; ++ pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_LATCH_REGS); ++ status = pisp_fe_reg_read(fe, FE_STATUS); ++ out_status = pisp_fe_reg_read(fe, FE_OUTPUT_STATUS); ++ frame_status = pisp_fe_reg_read(fe, FE_FRAME_STATUS); ++ error_status = pisp_fe_reg_read(fe, FE_ERROR_STATUS); + -+ 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); -+ } ++ int_status = pisp_fe_reg_read(fe, FE_INT_STATUS); ++ pisp_fe_reg_write(fe, FE_INT_STATUS, int_status); + -+ if (node->registered) { -+ node->registered = false; -+ video_unregister_device(&node->video_dev); -+ } ++ pisp_fe_dbg_verbose("%s: status 0x%x out 0x%x frame 0x%x error 0x%x int 0x%x\n", ++ __func__, status, out_status, frame_status, error_status, ++ int_status); ++ ++ /* We do not report interrupts for the input/stream pad. */ ++ for (i = 0; i < FE_NUM_PADS - 1; i++) { ++ sofi = !!(int_status & FE_INT_SOF); ++ eofi = !!(int_status & FE_INT_EOF); + } +} + -+static int unicam_async_complete(struct v4l2_async_notifier *notifier) ++static bool pisp_fe_validate_output(struct pisp_fe_config const *cfg, ++ unsigned int c, struct v4l2_format const *f) +{ -+ struct unicam_device *unicam = to_unicam_device(notifier->v4l2_dev); -+ unsigned int i, source_pads = 0; -+ int ret; ++ unsigned int wbytes; + -+ unicam->v4l2_dev.notify = unicam_notify; ++ wbytes = cfg->chc.output.format.width; ++ if (cfg->chc.output.format.format & PISP_IMAGE_FORMAT_BPS_MASK) ++ wbytes *= 2; + -+ unicam->sensor_config = v4l2_subdev_alloc_pad_config(unicam->sensor); -+ if (!unicam->sensor_config) -+ return -ENOMEM; ++ /* Check output image dimensions are nonzero and not too big */ ++ if (cfg->chc.output.format.width < 2 || ++ cfg->chc.output.format.height < 2 || ++ cfg->chc.output.format.height > f->fmt.pix.height || ++ cfg->chc.output.format.stride > f->fmt.pix.bytesperline || ++ wbytes > f->fmt.pix.bytesperline) ++ return false; + -+ for (i = 0; i < unicam->sensor->entity.num_pads; i++) { -+ if (unicam->sensor->entity.padsi.flags & MEDIA_PAD_FL_SOURCE) { -+ if (source_pads < MAX_NODES) { -+ unicam->nodesource_pads.src_pad_id = i; -+ unicam_dbg(3, unicam, "source pad %u is index %u\n", -+ source_pads, i); -+ } -+ source_pads++; -+ } -+ } -+ if (!source_pads) { -+ unicam_err(unicam, "No source pads on sensor.\n"); -+ goto unregister; -+ } ++ /* Check for zero-sized crops, which could cause lockup */ ++ if ((cfg->global.enables & PISP_FE_ENABLE_CROP(c)) && ++ ((cfg->chc.crop.offset_x >= (cfg->input.format.width & ~1) || ++ cfg->chc.crop.offset_y >= cfg->input.format.height || ++ cfg->chc.crop.width < 2 || ++ cfg->chc.crop.height < 2))) ++ return false; + -+ ret = register_node(unicam, &unicam->nodeIMAGE_PAD, -+ V4L2_BUF_TYPE_VIDEO_CAPTURE, IMAGE_PAD); -+ if (ret) { -+ unicam_err(unicam, "Unable to register image video device.\n"); -+ goto unregister; -+ } ++ if ((cfg->global.enables & PISP_FE_ENABLE_DOWNSCALE(c)) && ++ (cfg->chc.downscale.output_width < 2 || ++ cfg->chc.downscale.output_height < 2)) ++ return false; + -+ if (source_pads >= 2) { -+ unicam->sensor_embedded_data = true; ++ return true; ++} + -+ ret = register_node(unicam, &unicam->nodeMETADATA_PAD, -+ V4L2_BUF_TYPE_META_CAPTURE, METADATA_PAD); -+ if (ret) { -+ unicam_err(unicam, "Unable to register metadata video device.\n"); -+ goto unregister; ++static bool pisp_fe_validate_stats(struct pisp_fe_config const *cfg) ++{ ++ /* Check for zero-sized crop, which could cause lockup */ ++ return (!(cfg->global.enables & PISP_FE_ENABLE_STATS_CROP) || ++ (cfg->stats_crop.offset_x < (cfg->input.format.width & ~1) && ++ cfg->stats_crop.offset_y < cfg->input.format.height && ++ cfg->stats_crop.width >= 2 && ++ cfg->stats_crop.height >= 2)); ++} ++ ++int pisp_fe_validate_config(struct pisp_fe_device *fe, ++ struct pisp_fe_config *cfg, ++ struct v4l2_format const *f0, ++ struct v4l2_format const *f1) ++{ ++ unsigned int i; ++ ++ /* ++ * Check the input is enabled, streaming and has nonzero size; ++ * to avoid cases where the hardware might lock up or try to ++ * read inputs from memory (which this driver doesn't support). ++ */ ++ if (!(cfg->global.enables & PISP_FE_ENABLE_INPUT) || ++ cfg->input.streaming != 1 || cfg->input.format.width < 2 || ++ cfg->input.format.height < 2) { ++ pisp_fe_err("%s: Input config not valid", __func__); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < PISP_FE_NUM_OUTPUTS; i++) { ++ if (!(cfg->global.enables & PISP_FE_ENABLE_OUTPUT(i))) { ++ if (cfg->global.enables & ++ PISP_FE_ENABLE_OUTPUT_CLUSTER(i)) { ++ pisp_fe_err("%s: Output %u not valid", ++ __func__, i); ++ return -EINVAL; ++ } ++ continue; + } ++ ++ if (!pisp_fe_validate_output(cfg, i, i ? f1 : f0)) ++ return -EINVAL; + } + -+ if (unicam->mc_api) -+ ret = v4l2_device_register_subdev_nodes(&unicam->v4l2_dev); -+ else -+ ret = v4l2_device_register_ro_subdev_nodes(&unicam->v4l2_dev); -+ if (ret) { -+ unicam_err(unicam, "Unable to register subdev nodes.\n"); -+ goto unregister; ++ if ((cfg->global.enables & PISP_FE_ENABLE_STATS_CLUSTER) && ++ !pisp_fe_validate_stats(cfg)) { ++ pisp_fe_err("%s: Stats config not valid", __func__); ++ return -EINVAL; + } + -+ /* -+ * 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 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) ++void pisp_fe_submit_job(struct pisp_fe_device *fe, struct vb2_buffer **vb2_bufs, ++ struct pisp_fe_config *cfg) +{ -+ 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; ++ unsigned int i; ++ u64 addr; ++ u32 status; + -+ 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; ++ /* ++ * Check output buffers exist and outputs are correctly configured. ++ * If valid, set the buffer's DMA address; otherwise disable. ++ */ ++ for (i = 0; i < PISP_FE_NUM_OUTPUTS; i++) { ++ struct vb2_buffer *buf = vb2_bufsFE_OUTPUT0_PAD + i; ++ ++ if (!(cfg->global.enables & PISP_FE_ENABLE_OUTPUT(i))) ++ continue; ++ ++ addr = vb2_dma_contig_plane_dma_addr(buf, 0); ++ cfg->output_bufferi.addr_lo = addr & 0xffffffff; ++ cfg->output_bufferi.addr_hi = addr >> 32; + } + -+ /* 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; ++ if (vb2_bufsFE_STATS_PAD) { ++ addr = vb2_dma_contig_plane_dma_addr(vb2_bufsFE_STATS_PAD, 0); ++ cfg->stats_buffer.addr_lo = addr & 0xffffffff; ++ cfg->stats_buffer.addr_hi = addr >> 32; + } + -+ unicam_dbg(3, dev, "ep_node is %pOF\n", ep_node); ++ /* Set up ILINES interrupts 3/4 of the way down each output */ ++ cfg->ch0.output.ilines = ++ max(0x80u, (3u * cfg->ch0.output.format.height) >> 2); ++ cfg->ch1.output.ilines = ++ max(0x80u, (3u * cfg->ch1.output.format.height) >> 2); + -+ 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; ++ /* ++ * The hardware must have consumed the previous config by now. ++ * This read of status also serves as a memory barrier before the ++ * sequence of relaxed writes which follow. ++ */ ++ status = pisp_fe_reg_read(fe, FE_STATUS); ++ pisp_fe_dbg_verbose("%s: status = 0x%x\n", __func__, status); ++ if (WARN_ON(status & FE_STATUS_QUEUED)) ++ return; ++ ++ /* ++ * Unconditionally write buffers, global and input parameters. ++ * Write cropping and output parameters whenever they are enabled. ++ * Selectively write other parameters that have been marked as ++ * changed through the dirty flags. ++ */ ++ pisp_config_write(fe, cfg, 0, ++ offsetof(struct pisp_fe_config, decompress)); ++ cfg->dirty_flags_extra &= ~PISP_FE_DIRTY_GLOBAL; ++ cfg->dirty_flags &= ~PISP_FE_ENABLE_INPUT; ++ cfg->dirty_flags |= (cfg->global.enables & ++ (PISP_FE_ENABLE_STATS_CROP | ++ PISP_FE_ENABLE_OUTPUT_CLUSTER(0) | ++ PISP_FE_ENABLE_OUTPUT_CLUSTER(1))); ++ for (i = 0; i < ARRAY_SIZE(pisp_fe_config_map); i++) { ++ const struct pisp_fe_config_param *p = &pisp_fe_config_mapi; ++ ++ if (cfg->dirty_flags & p->dirty_flags || ++ cfg->dirty_flags_extra & p->dirty_flags_extra) ++ pisp_config_write(fe, cfg, p->offset, p->size); + } + -+ unicam_dbg(1, dev, "found subdevice %pOF\n", sensor_node); ++ /* This final non-relaxed write serves as a memory barrier */ ++ pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_QUEUE); ++} + -+ /* Parse the local endpoint and validate its configuration. */ -+ v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), &ep); ++void pisp_fe_start(struct pisp_fe_device *fe) ++{ ++ pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_RESET); ++ pisp_fe_reg_write(fe, FE_INT_STATUS, ~0); ++ pisp_fe_reg_write(fe, FE_INT_EN, FE_INT_EOF | FE_INT_SOF | FE_INT_LINES0 | FE_INT_LINES1); ++ fe->inframe_count = 0; ++} + -+ unicam_dbg(3, dev, "parsed local endpoint, bus_type %u\n", -+ ep.bus_type); ++void pisp_fe_stop(struct pisp_fe_device *fe) ++{ ++ pisp_fe_reg_write(fe, FE_INT_EN, 0); ++ pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_ABORT); ++ usleep_range(1000, 2000); ++ WARN_ON(pisp_fe_reg_read(fe, FE_STATUS)); ++ pisp_fe_reg_write(fe, FE_INT_STATUS, ~0); ++} + -+ dev->bus_type = ep.bus_type; ++static int pisp_fe_init_cfg(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state) ++{ ++ struct v4l2_mbus_framefmt *fmt; + -+ switch (ep.bus_type) { -+ case V4L2_MBUS_CSI2_DPHY: -+ switch (ep.bus.mipi_csi2.num_data_lanes) { -+ case 1: -+ case 2: -+ case 4: -+ break; ++ fmt = v4l2_subdev_get_pad_format(sd, state, FE_STREAM_PAD); ++ *fmt = cfe_default_format; ++ fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16; + -+ default: -+ unicam_err(dev, "subdevice %pOF: %u data lanes not supported\n", -+ sensor_node, -+ ep.bus.mipi_csi2.num_data_lanes); -+ goto cleanup_exit; -+ } ++ fmt = v4l2_subdev_get_pad_format(sd, state, FE_CONFIG_PAD); ++ *fmt = cfe_default_meta_format; ++ fmt->code = MEDIA_BUS_FMT_FIXED; + -+ for (lane = 0; lane < ep.bus.mipi_csi2.num_data_lanes; lane++) { -+ if (ep.bus.mipi_csi2.data_laneslane != lane + 1) { -+ unicam_err(dev, "subdevice %pOF: data lanes reordering not supported\n", -+ sensor_node); -+ goto cleanup_exit; -+ } -+ } ++ fmt = v4l2_subdev_get_pad_format(sd, state, FE_OUTPUT0_PAD); ++ *fmt = cfe_default_format; ++ fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16; + -+ 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); -+ } ++ fmt = v4l2_subdev_get_pad_format(sd, state, FE_OUTPUT1_PAD); ++ *fmt = cfe_default_format; ++ fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16; + -+ dev->max_data_lanes = ep.bus.mipi_csi2.num_data_lanes; -+ dev->bus_flags = ep.bus.mipi_csi2.flags; ++ fmt = v4l2_subdev_get_pad_format(sd, state, FE_STATS_PAD); ++ *fmt = cfe_default_meta_format; ++ fmt->code = MEDIA_BUS_FMT_FIXED; + -+ break; ++ return 0; ++} + -+ 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; -+ } ++static int pisp_fe_pad_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *fmt; ++ const struct cfe_fmt *cfe_fmt; + -+ dev->max_data_lanes = 1; -+ dev->bus_flags = ep.bus.mipi_csi1.strobe; -+ break; ++ /* TODO: format propagation to source pads */ ++ /* TODO: format validation */ + -+ default: -+ /* Unsupported bus type */ -+ unicam_err(dev, "subdevice %pOF: unsupported bus type %u\n", -+ sensor_node, ep.bus_type); -+ goto cleanup_exit; -+ } ++ switch (format->pad) { ++ case FE_STREAM_PAD: ++ cfe_fmt = find_format_by_code(format->format.code); ++ if (!cfe_fmt || !(cfe_fmt->flags & CFE_FORMAT_FLAG_FE_OUT)) ++ cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SRGGB16_1X16); + -+ 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); ++ format->format.code = cfe_fmt->code; ++ format->format.field = V4L2_FIELD_NONE; + -+ /* Initialize and register the async notifier. */ -+ v4l2_async_notifier_init(&dev->notifier); -+ dev->notifier.ops = &unicam_async_ops; ++ fmt = v4l2_subdev_get_pad_format(sd, state, FE_STREAM_PAD); ++ *fmt = format->format; + -+ dev->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; -+ dev->asd.match.fwnode = fwnode_graph_get_remote_endpoint(of_fwnode_handle(ep_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; -+ } ++ fmt = v4l2_subdev_get_pad_format(sd, state, FE_OUTPUT0_PAD); ++ *fmt = format->format; + -+ ret = v4l2_async_notifier_register(&dev->v4l2_dev, &dev->notifier); -+ if (ret) { -+ unicam_err(dev, "Error registering async notifier: %d\n", ret); -+ ret = -EINVAL; -+ } ++ fmt = v4l2_subdev_get_pad_format(sd, state, FE_OUTPUT1_PAD); ++ *fmt = format->format; + -+cleanup_exit: -+ of_node_put(sensor_node); -+ of_node_put(ep_node); ++ return 0; + -+ return ret; -+} ++ case FE_OUTPUT0_PAD: ++ case FE_OUTPUT1_PAD: { ++ /* ++ * TODO: we should allow scaling and cropping by allowing the ++ * user to set the size here. ++ */ ++ struct v4l2_mbus_framefmt *sink_fmt, *source_fmt; ++ u32 sink_code; ++ u32 code; + -+static int unicam_probe(struct platform_device *pdev) -+{ -+ struct unicam_device *unicam; -+ int ret; ++ sink_fmt = v4l2_subdev_get_pad_format(sd, state, FE_STREAM_PAD); ++ if (!sink_fmt) ++ return -EINVAL; + -+ unicam = kzalloc(sizeof(*unicam), GFP_KERNEL); -+ if (!unicam) -+ return -ENOMEM; ++ source_fmt = v4l2_subdev_get_pad_format(sd, state, format->pad); ++ if (!source_fmt) ++ return -EINVAL; + -+ kref_init(&unicam->kref); -+ unicam->pdev = pdev; ++ sink_code = sink_fmt->code; ++ code = format->format.code; + -+ /* -+ * Adopt the current setting of the module parameter, and check if -+ * device tree requests it. -+ */ -+ unicam->mc_api = media_controller; -+ if (of_property_read_bool(pdev->dev.of_node, "brcm,media-controller")) -+ unicam->mc_api = true; ++ /* ++ * If the source code from the user does not match the code in ++ * the sink pad, check that the source code matches the ++ * compressed version of the sink code. ++ */ + -+ 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; -+ } ++ if (code != sink_code && ++ code == cfe_find_compressed_code(sink_code)) ++ source_fmt->code = code; + -+ 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; ++ return 0; + } + -+ 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; ++ case FE_CONFIG_PAD: ++ case FE_STATS_PAD: ++ default: ++ return v4l2_subdev_get_fmt(sd, state, format); + } ++} + -+ 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; -+ } ++static const struct v4l2_subdev_pad_ops pisp_fe_subdev_pad_ops = { ++ .init_cfg = pisp_fe_init_cfg, ++ .get_fmt = v4l2_subdev_get_fmt, ++ .set_fmt = pisp_fe_pad_set_fmt, ++ .link_validate = v4l2_subdev_link_validate_default, ++}; + -+ ret = platform_get_irq(pdev, 0); -+ if (ret <= 0) { -+ dev_err(&pdev->dev, "No IRQ resource\n"); -+ ret = -EINVAL; -+ goto err_unicam_put; -+ } ++static const struct media_entity_operations pisp_fe_entity_ops = { ++ .link_validate = v4l2_subdev_link_validate, ++}; + -+ 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; -+ } ++static const struct v4l2_subdev_ops pisp_fe_subdev_ops = { ++ .pad = &pisp_fe_subdev_pad_ops, ++}; + -+ 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; ++int pisp_fe_init(struct pisp_fe_device *fe, struct dentry *debugfs) ++{ ++ int ret; + -+ media_device_init(&unicam->mdev); ++ debugfs_create_file("pisp_regs", 0444, debugfs, fe, &pisp_regs_fops); + -+ unicam->v4l2_dev.mdev = &unicam->mdev; ++ fe->hw_revision = pisp_fe_reg_read(fe, FE_VERSION); ++ pisp_fe_info("PiSP FE HW v%u.%u\n", ++ (fe->hw_revision >> 24) & 0xff, ++ (fe->hw_revision >> 20) & 0x0f); + -+ ret = v4l2_device_register(&pdev->dev, &unicam->v4l2_dev); -+ if (ret) { -+ unicam_err(unicam, -+ "Unable to register v4l2 device.\n"); -+ goto err_unicam_put; -+ } ++ fe->padFE_STREAM_PAD.flags = ++ MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; ++ fe->padFE_CONFIG_PAD.flags = MEDIA_PAD_FL_SINK; ++ fe->padFE_OUTPUT0_PAD.flags = MEDIA_PAD_FL_SOURCE; ++ fe->padFE_OUTPUT1_PAD.flags = MEDIA_PAD_FL_SOURCE; ++ fe->padFE_STATS_PAD.flags = MEDIA_PAD_FL_SOURCE; + -+ ret = media_device_register(&unicam->mdev); -+ if (ret < 0) { -+ unicam_err(unicam, -+ "Unable to register media-controller device.\n"); -+ goto err_v4l2_unregister; -+ } ++ ret = media_entity_pads_init(&fe->sd.entity, ARRAY_SIZE(fe->pad), ++ fe->pad); ++ if (ret) ++ return ret; + -+ /* Reserve space for the controls */ -+ ret = v4l2_ctrl_handler_init(&unicam->ctrl_handler, 16); -+ if (ret < 0) -+ goto err_media_unregister; ++ /* Initialize subdev */ ++ v4l2_subdev_init(&fe->sd, &pisp_fe_subdev_ops); ++ fe->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; ++ fe->sd.entity.ops = &pisp_fe_entity_ops; ++ fe->sd.entity.name = "pisp-fe"; ++ fe->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ fe->sd.owner = THIS_MODULE; ++ snprintf(fe->sd.name, sizeof(fe->sd.name), "pisp-fe"); + -+ /* set the driver data in platform device */ -+ platform_set_drvdata(pdev, unicam); ++ ret = v4l2_subdev_init_finalize(&fe->sd); ++ if (ret) ++ goto err_entity_cleanup; + -+ ret = of_unicam_connect_subdevs(unicam); ++ ret = v4l2_device_register_subdev(fe->v4l2_dev, &fe->sd); + if (ret) { -+ dev_err(&pdev->dev, "Failed to connect subdevs\n"); -+ goto err_media_unregister; ++ pisp_fe_err("Failed register pisp fe subdev (%d)\n", ret); ++ goto err_subdev_cleanup; + } + -+ /* Enable the block power domain */ -+ pm_runtime_enable(&pdev->dev); ++ /* Must be in IDLE state (STATUS == 0) here. */ ++ WARN_ON(pisp_fe_reg_read(fe, FE_STATUS)); + + 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); ++err_subdev_cleanup: ++ v4l2_subdev_cleanup(&fe->sd); ++err_entity_cleanup: ++ media_entity_cleanup(&fe->sd.entity); + + return ret; +} + -+static int unicam_remove(struct platform_device *pdev) ++void pisp_fe_uninit(struct pisp_fe_device *fe) +{ -+ struct unicam_device *unicam = platform_get_drvdata(pdev); -+ -+ unicam_dbg(2, unicam, "%s\n", __func__); ++ v4l2_device_unregister_subdev(&fe->sd); ++ v4l2_subdev_cleanup(&fe->sd); ++ media_entity_cleanup(&fe->sd.entity); ++} +diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.h b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.h +new file mode 100644 +index 000000000000..12760cb55af4 +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.h +@@ -0,0 +1,53 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * PiSP Front End driver. ++ * Copyright (c) 2021 Raspberry Pi Ltd. ++ * ++ */ ++#ifndef _PISP_FE_H_ ++#define _PISP_FE_H_ + -+ v4l2_async_notifier_unregister(&unicam->notifier); -+ v4l2_device_unregister(&unicam->v4l2_dev); -+ media_device_unregister(&unicam->mdev); -+ unregister_nodes(unicam); ++#include <linux/debugfs.h> ++#include <linux/io.h> ++#include <linux/types.h> ++#include <linux/videodev2.h> + -+ pm_runtime_disable(&pdev->dev); ++#include <media/media-device.h> ++#include <media/v4l2-device.h> ++#include <media/v4l2-subdev.h> + -+ return 0; -+} ++#include "pisp_fe_config.h" + -+static const struct of_device_id unicam_of_match = { -+ { .compatible = "brcm,bcm2835-unicam", }, -+ { /* sentinel */ }, ++enum pisp_fe_pads { ++ FE_STREAM_PAD, ++ FE_CONFIG_PAD, ++ FE_OUTPUT0_PAD, ++ FE_OUTPUT1_PAD, ++ FE_STATS_PAD, ++ FE_NUM_PADS +}; -+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), -+ }, ++struct pisp_fe_device { ++ /* Parent V4l2 device */ ++ struct v4l2_device *v4l2_dev; ++ void __iomem *base; ++ u32 hw_revision; ++ ++ u16 inframe_count; ++ struct media_pad padFE_NUM_PADS; ++ struct v4l2_subdev sd; +}; + -+module_platform_driver(unicam_driver); ++void pisp_fe_isr(struct pisp_fe_device *fe, bool *sof, bool *eof); ++int pisp_fe_validate_config(struct pisp_fe_device *fe, ++ struct pisp_fe_config *cfg, ++ struct v4l2_format const *f0, ++ struct v4l2_format const *f1); ++void pisp_fe_submit_job(struct pisp_fe_device *fe, struct vb2_buffer **vb2_bufs, ++ struct pisp_fe_config *cfg); ++void pisp_fe_start(struct pisp_fe_device *fe); ++void pisp_fe_stop(struct pisp_fe_device *fe); ++int pisp_fe_init(struct pisp_fe_device *fe, struct dentry *debugfs); ++void pisp_fe_uninit(struct pisp_fe_device *fe); + -+MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com>"); -+MODULE_DESCRIPTION("BCM2835 Unicam driver"); -+MODULE_LICENSE("GPL"); -+MODULE_VERSION(UNICAM_VERSION); -diff --git a/drivers/media/platform/bcm2835/vc4-regs-unicam.h b/drivers/media/platform/bcm2835/vc4-regs-unicam.h ++#endif +diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe_config.h b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe_config.h new file mode 100644 -index 000000000000..ae059a171d0f +index 000000000000..4b76f640894b --- /dev/null -+++ b/drivers/media/platform/bcm2835/vc4-regs-unicam.h -@@ -0,0 +1,253 @@ -+/* SPDX-License-Identifier: GPL-2.0-only */ -+ ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe_config.h +@@ -0,0 +1,272 @@ ++/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* -+ * Copyright (C) 2017-2020 Raspberry Pi Trading. -+ * Dave Stevenson <dave.stevenson@raspberrypi.com> ++ * RP1 PiSP Front End Driver Configuration structures ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd. ++ * + */ ++#ifndef _PISP_FE_CONFIG_ ++#define _PISP_FE_CONFIG_ ++ ++#include <media/raspberrypi/pisp_common.h> ++ ++#include "pisp_statistics.h" ++ ++#define PISP_FE_NUM_OUTPUTS 2 ++ ++enum pisp_fe_enable { ++ PISP_FE_ENABLE_INPUT = 0x000001, ++ PISP_FE_ENABLE_DECOMPRESS = 0x000002, ++ PISP_FE_ENABLE_DECOMPAND = 0x000004, ++ PISP_FE_ENABLE_BLA = 0x000008, ++ PISP_FE_ENABLE_DPC = 0x000010, ++ PISP_FE_ENABLE_STATS_CROP = 0x000020, ++ PISP_FE_ENABLE_DECIMATE = 0x000040, ++ PISP_FE_ENABLE_BLC = 0x000080, ++ PISP_FE_ENABLE_CDAF_STATS = 0x000100, ++ PISP_FE_ENABLE_AWB_STATS = 0x000200, ++ PISP_FE_ENABLE_RGBY = 0x000400, ++ PISP_FE_ENABLE_LSC = 0x000800, ++ PISP_FE_ENABLE_AGC_STATS = 0x001000, ++ PISP_FE_ENABLE_CROP0 = 0x010000, ++ PISP_FE_ENABLE_DOWNSCALE0 = 0x020000, ++ PISP_FE_ENABLE_COMPRESS0 = 0x040000, ++ PISP_FE_ENABLE_OUTPUT0 = 0x080000, ++ PISP_FE_ENABLE_CROP1 = 0x100000, ++ PISP_FE_ENABLE_DOWNSCALE1 = 0x200000, ++ PISP_FE_ENABLE_COMPRESS1 = 0x400000, ++ PISP_FE_ENABLE_OUTPUT1 = 0x800000 ++}; ++ ++#define PISP_FE_ENABLE_CROP(i) (PISP_FE_ENABLE_CROP0 << (4 * (i))) ++#define PISP_FE_ENABLE_DOWNSCALE(i) (PISP_FE_ENABLE_DOWNSCALE0 << (4 * (i))) ++#define PISP_FE_ENABLE_COMPRESS(i) (PISP_FE_ENABLE_COMPRESS0 << (4 * (i))) ++#define PISP_FE_ENABLE_OUTPUT(i) (PISP_FE_ENABLE_OUTPUT0 << (4 * (i))) ++ ++/* ++ * We use the enable flags to show when blocks are "dirty", but we need some ++ * extra ones too. ++ */ ++enum pisp_fe_dirty { ++ PISP_FE_DIRTY_GLOBAL = 0x0001, ++ PISP_FE_DIRTY_FLOATING = 0x0002, ++ PISP_FE_DIRTY_OUTPUT_AXI = 0x0004 ++}; ++ ++struct pisp_fe_global_config { ++ u32 enables; ++ u8 bayer_order; ++ u8 pad3; ++}; ++ ++struct pisp_fe_input_axi_config { ++ /* burst length minus one, in the range 0..15; OR'd with flags */ ++ u8 maxlen_flags; ++ /* { prot2:0, cache3:0 } fields */ ++ u8 cache_prot; ++ /* QoS (only 4 LS bits are used) */ ++ u16 qos; ++}; ++ ++struct pisp_fe_output_axi_config { ++ /* burst length minus one, in the range 0..15; OR'd with flags */ ++ u8 maxlen_flags; ++ /* { prot2:0, cache3:0 } fields */ ++ u8 cache_prot; ++ /* QoS (4 bitfields of 4 bits each for different panic levels) */ ++ u16 qos; ++ /* For Panic mode: Output FIFO panic threshold */ ++ u16 thresh; ++ /* For Panic mode: Output FIFO statistics throttle threshold */ ++ u16 throttle; ++}; ++ ++struct pisp_fe_input_config { ++ u8 streaming; ++ u8 pad3; ++ struct pisp_image_format_config format; ++ struct pisp_fe_input_axi_config axi; ++ /* Extra cycles delay before issuing each burst request */ ++ u8 holdoff; ++ u8 pad23; ++}; ++ ++struct pisp_fe_output_config { ++ struct pisp_image_format_config format; ++ u16 ilines; ++ u8 pad2; ++}; ++ ++struct pisp_fe_input_buffer_config { ++ u32 addr_lo; ++ u32 addr_hi; ++ u16 frame_id; ++ u16 pad; ++}; ++ ++#define PISP_FE_DECOMPAND_LUT_SIZE 65 ++ ++struct pisp_fe_decompand_config { ++ u16 lutPISP_FE_DECOMPAND_LUT_SIZE; ++ u16 pad; ++}; ++ ++struct pisp_fe_dpc_config { ++ u8 coeff_level; ++ u8 coeff_range; ++ u8 coeff_range2; ++#define PISP_FE_DPC_FLAG_FOLDBACK 1 ++#define PISP_FE_DPC_FLAG_VFLAG 2 ++ u8 flags; ++}; ++ ++#define PISP_FE_LSC_LUT_SIZE 16 ++ ++struct pisp_fe_lsc_config { ++ u8 shift; ++ u8 pad0; ++ u16 scale; ++ u16 centre_x; ++ u16 centre_y; ++ u16 lutPISP_FE_LSC_LUT_SIZE; ++}; ++ ++struct pisp_fe_rgby_config { ++ u16 gain_r; ++ u16 gain_g; ++ u16 gain_b; ++ u8 maxflag; ++ u8 pad; ++}; ++ ++struct pisp_fe_agc_stats_config { ++ u16 offset_x; ++ u16 offset_y; ++ u16 size_x; ++ u16 size_y; ++ /* each weight only 4 bits */ ++ u8 weightsPISP_AGC_STATS_NUM_ZONES / 2; ++ u16 row_offset_x; ++ u16 row_offset_y; ++ u16 row_size_x; ++ u16 row_size_y; ++ u8 row_shift; ++ u8 float_shift; ++ u8 pad12; ++}; ++ ++struct pisp_fe_awb_stats_config { ++ u16 offset_x; ++ u16 offset_y; ++ u16 size_x; ++ u16 size_y; ++ u8 shift; ++ u8 pad3; ++ u16 r_lo; ++ u16 r_hi; ++ u16 g_lo; ++ u16 g_hi; ++ u16 b_lo; ++ u16 b_hi; ++}; ++ ++struct pisp_fe_floating_stats_region { ++ u16 offset_x; ++ u16 offset_y; ++ u16 size_x; ++ u16 size_y; ++}; ++ ++struct pisp_fe_floating_stats_config { ++ struct pisp_fe_floating_stats_region ++ regionsPISP_FLOATING_STATS_NUM_ZONES; ++}; ++ ++#define PISP_FE_CDAF_NUM_WEIGHTS 8 ++ ++struct pisp_fe_cdaf_stats_config { ++ u16 noise_constant; ++ u16 noise_slope; ++ u16 offset_x; ++ u16 offset_y; ++ u16 size_x; ++ u16 size_y; ++ u16 skip_x; ++ u16 skip_y; ++ u32 mode; ++}; ++ ++struct pisp_fe_stats_buffer_config { ++ u32 addr_lo; ++ u32 addr_hi; ++}; ++ ++struct pisp_fe_crop_config { ++ u16 offset_x; ++ u16 offset_y; ++ u16 width; ++ u16 height; ++}; + -+#ifndef VC4_REGS_UNICAM_H -+#define VC4_REGS_UNICAM_H ++enum pisp_fe_downscale_flags { ++ DOWNSCALE_BAYER = ++ 1, /* downscale the four Bayer components independently... */ ++ DOWNSCALE_BIN = ++ 2 /* ...without trying to preserve their spatial relationship */ ++}; ++ ++struct pisp_fe_downscale_config { ++ u8 xin; ++ u8 xout; ++ u8 yin; ++ u8 yout; ++ u8 flags; /* enum pisp_fe_downscale_flags */ ++ u8 pad3; ++ u16 output_width; ++ u16 output_height; ++}; + ++struct pisp_fe_output_buffer_config { ++ u32 addr_lo; ++ u32 addr_hi; ++}; ++ ++/* Each of the two output channels/branches: */ ++struct pisp_fe_output_branch_config { ++ struct pisp_fe_crop_config crop; ++ struct pisp_fe_downscale_config downscale; ++ struct pisp_compress_config compress; ++ struct pisp_fe_output_config output; ++ u32 pad; ++}; ++ ++/* And finally one to rule them all: */ ++struct pisp_fe_config { ++ /* I/O configuration: */ ++ struct pisp_fe_stats_buffer_config stats_buffer; ++ struct pisp_fe_output_buffer_config output_bufferPISP_FE_NUM_OUTPUTS; ++ struct pisp_fe_input_buffer_config input_buffer; ++ /* processing configuration: */ ++ struct pisp_fe_global_config global; ++ struct pisp_fe_input_config input; ++ struct pisp_decompress_config decompress; ++ struct pisp_fe_decompand_config decompand; ++ struct pisp_bla_config bla; ++ struct pisp_fe_dpc_config dpc; ++ struct pisp_fe_crop_config stats_crop; ++ u32 spare1; /* placeholder for future decimate configuration */ ++ struct pisp_bla_config blc; ++ struct pisp_fe_rgby_config rgby; ++ struct pisp_fe_lsc_config lsc; ++ struct pisp_fe_agc_stats_config agc_stats; ++ struct pisp_fe_awb_stats_config awb_stats; ++ struct pisp_fe_cdaf_stats_config cdaf_stats; ++ struct pisp_fe_floating_stats_config floating_stats; ++ struct pisp_fe_output_axi_config output_axi; ++ struct pisp_fe_output_branch_config chPISP_FE_NUM_OUTPUTS; ++ /* non-register fields: */ ++ u32 dirty_flags; /* these use pisp_fe_enable */ ++ u32 dirty_flags_extra; /* these use pisp_fe_dirty */ ++}; ++ ++#endif /* _PISP_FE_CONFIG_ */ +diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/pisp_statistics.h b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_statistics.h +new file mode 100644 +index 000000000000..d8d7fcb57fec +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_statistics.h +@@ -0,0 +1,62 @@ ++/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* -+ * 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. ++ * RP1 PiSP Front End statistics definitions ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd. ++ * + */ -+#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 ++#ifndef _PISP_FE_STATISTICS_H_ ++#define _PISP_FE_STATISTICS_H_ ++ ++#define PISP_FLOATING_STATS_NUM_ZONES 4 ++#define PISP_AGC_STATS_NUM_BINS 1024 ++#define PISP_AGC_STATS_SIZE 16 ++#define PISP_AGC_STATS_NUM_ZONES (PISP_AGC_STATS_SIZE * PISP_AGC_STATS_SIZE) ++#define PISP_AGC_STATS_NUM_ROW_SUMS 512 ++ ++struct pisp_agc_statistics_zone { ++ u64 Y_sum; ++ u32 counted; ++ u32 pad; ++}; ++ ++struct pisp_agc_statistics { ++ u32 row_sumsPISP_AGC_STATS_NUM_ROW_SUMS; ++ /* ++ * 32-bits per bin means an image (just less than) 16384x16384 pixels ++ * in size can weight every pixel from 0 to 15. ++ */ ++ u32 histogramPISP_AGC_STATS_NUM_BINS; ++ struct pisp_agc_statistics_zone floatingPISP_FLOATING_STATS_NUM_ZONES; ++}; ++ ++#define PISP_AWB_STATS_SIZE 32 ++#define PISP_AWB_STATS_NUM_ZONES (PISP_AWB_STATS_SIZE * PISP_AWB_STATS_SIZE) ++ ++struct pisp_awb_statistics_zone { ++ u32 R_sum; ++ u32 G_sum; ++ u32 B_sum; ++ u32 counted; ++}; ++ ++struct pisp_awb_statistics { ++ struct pisp_awb_statistics_zone zonesPISP_AWB_STATS_NUM_ZONES; ++ struct pisp_awb_statistics_zone floatingPISP_FLOATING_STATS_NUM_ZONES; ++}; ++ ++#define PISP_CDAF_STATS_SIZE 8 ++#define PISP_CDAF_STATS_NUM_FOMS (PISP_CDAF_STATS_SIZE * PISP_CDAF_STATS_SIZE) + ++struct pisp_cdaf_statistics { ++ u64 fomsPISP_CDAF_STATS_NUM_FOMS; ++ u64 floatingPISP_FLOATING_STATS_NUM_ZONES; ++}; ++ ++struct pisp_statistics { ++ struct pisp_awb_statistics awb; ++ struct pisp_agc_statistics agc; ++ struct pisp_cdaf_statistics cdaf; ++}; ++ ++#endif /* _PISP_FE_STATISTICS_H_ */ +diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/pisp_types.h b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_types.h +new file mode 100644 +index 000000000000..93d2d3c27a56 +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_types.h +@@ -0,0 +1,144 @@ ++/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* -+ * 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. ++ * RP1 PiSP Front End image definitions. ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd. + * -+ * 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) ++#ifndef _PISP_FE_TYPES_H_ ++#define _PISP_FE_TYPES_H_ ++ ++/* This definition must match the format description in the hardware exactly! */ ++struct pisp_image_format_config { ++ /* size in pixels */ ++ u16 width, height; ++ /* must match struct pisp_image_format below */ ++ u32 format; ++ s32 stride; ++ /* some planar image formats will need a second stride */ ++ s32 stride2; ++}; ++ ++static_assert(sizeof(struct pisp_image_format_config) == 16); ++ ++enum pisp_bayer_order { ++ /* ++ * Note how bayer_order&1 tells you if G is on the even pixels of the ++ * checkerboard or not, and bayer_order&2 tells you if R is on the even ++ * rows or is swapped with B. Note that if the top (of the 8) bits is ++ * set, this denotes a monochrome or greyscale image, and the lower bits ++ * should all be ignored. ++ */ ++ PISP_BAYER_ORDER_RGGB = 0, ++ PISP_BAYER_ORDER_GBRG = 1, ++ PISP_BAYER_ORDER_BGGR = 2, ++ PISP_BAYER_ORDER_GRBG = 3, ++ PISP_BAYER_ORDER_GREYSCALE = 128 ++}; ++ ++enum pisp_image_format { ++ /* ++ * Precise values are mostly tbd. Generally these will be portmanteau ++ * values comprising bit fields and flags. This format must be shared ++ * throughout the PiSP. ++ */ ++ PISP_IMAGE_FORMAT_BPS_8 = 0x00000000, ++ PISP_IMAGE_FORMAT_BPS_10 = 0x00000001, ++ PISP_IMAGE_FORMAT_BPS_12 = 0x00000002, ++ PISP_IMAGE_FORMAT_BPS_16 = 0x00000003, ++ PISP_IMAGE_FORMAT_BPS_MASK = 0x00000003, ++ ++ PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED = 0x00000000, ++ PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR = 0x00000010, ++ PISP_IMAGE_FORMAT_PLANARITY_PLANAR = 0x00000020, ++ PISP_IMAGE_FORMAT_PLANARITY_MASK = 0x00000030, ++ ++ PISP_IMAGE_FORMAT_SAMPLING_444 = 0x00000000, ++ PISP_IMAGE_FORMAT_SAMPLING_422 = 0x00000100, ++ PISP_IMAGE_FORMAT_SAMPLING_420 = 0x00000200, ++ PISP_IMAGE_FORMAT_SAMPLING_MASK = 0x00000300, ++ ++ PISP_IMAGE_FORMAT_ORDER_NORMAL = 0x00000000, ++ PISP_IMAGE_FORMAT_ORDER_SWAPPED = 0x00001000, ++ ++ PISP_IMAGE_FORMAT_SHIFT_0 = 0x00000000, ++ PISP_IMAGE_FORMAT_SHIFT_1 = 0x00010000, ++ PISP_IMAGE_FORMAT_SHIFT_2 = 0x00020000, ++ PISP_IMAGE_FORMAT_SHIFT_3 = 0x00030000, ++ PISP_IMAGE_FORMAT_SHIFT_4 = 0x00040000, ++ PISP_IMAGE_FORMAT_SHIFT_5 = 0x00050000, ++ PISP_IMAGE_FORMAT_SHIFT_6 = 0x00060000, ++ PISP_IMAGE_FORMAT_SHIFT_7 = 0x00070000, ++ PISP_IMAGE_FORMAT_SHIFT_8 = 0x00080000, ++ PISP_IMAGE_FORMAT_SHIFT_MASK = 0x000f0000, ++ ++ PISP_IMAGE_FORMAT_UNCOMPRESSED = 0x00000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_1 = 0x01000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_2 = 0x02000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_3 = 0x03000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MASK = 0x03000000, ++ ++ PISP_IMAGE_FORMAT_HOG_SIGNED = 0x04000000, ++ PISP_IMAGE_FORMAT_HOG_UNSIGNED = 0x08000000, ++ PISP_IMAGE_FORMAT_INTEGRAL_IMAGE = 0x10000000, ++ PISP_IMAGE_FORMAT_WALLPAPER_ROLL = 0x20000000, ++ PISP_IMAGE_FORMAT_THREE_CHANNEL = 0x40000000, ++ ++ /* Lastly a few specific instantiations of the above. */ ++ PISP_IMAGE_FORMAT_SINGLE_16 = PISP_IMAGE_FORMAT_BPS_16, ++ PISP_IMAGE_FORMAT_THREE_16 = ++ PISP_IMAGE_FORMAT_BPS_16 | PISP_IMAGE_FORMAT_THREE_CHANNEL ++}; ++ ++#define PISP_IMAGE_FORMAT_bps_8(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_8) ++#define PISP_IMAGE_FORMAT_bps_10(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_10) ++#define PISP_IMAGE_FORMAT_bps_12(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_12) ++#define PISP_IMAGE_FORMAT_bps_16(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_16) ++#define PISP_IMAGE_FORMAT_bps(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) ? \ ++ 8 + (2 << (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) - 1)) : \ ++ 8) ++#define PISP_IMAGE_FORMAT_shift(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_SHIFT_MASK) / PISP_IMAGE_FORMAT_SHIFT_1) ++#define PISP_IMAGE_FORMAT_three_channel(fmt) \ ++ ((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL) ++#define PISP_IMAGE_FORMAT_single_channel(fmt) \ ++ (!((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL)) ++#define PISP_IMAGE_FORMAT_compressed(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_COMPRESSION_MASK) != \ ++ PISP_IMAGE_FORMAT_UNCOMPRESSED) ++#define PISP_IMAGE_FORMAT_sampling_444(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_444) ++#define PISP_IMAGE_FORMAT_sampling_422(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_422) ++#define PISP_IMAGE_FORMAT_sampling_420(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_420) ++#define PISP_IMAGE_FORMAT_order_normal(fmt) \ ++ (!((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED)) ++#define PISP_IMAGE_FORMAT_order_swapped(fmt) \ ++ ((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED) ++#define PISP_IMAGE_FORMAT_interleaved(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED) ++#define PISP_IMAGE_FORMAT_semiplanar(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR) ++#define PISP_IMAGE_FORMAT_planar(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_PLANAR) ++#define PISP_IMAGE_FORMAT_wallpaper(fmt) \ ++ ((fmt) & PISP_IMAGE_FORMAT_WALLPAPER_ROLL) ++#define PISP_IMAGE_FORMAT_HOG(fmt) \ ++ ((fmt) & \ ++ (PISP_IMAGE_FORMAT_HOG_SIGNED | PISP_IMAGE_FORMAT_HOG_UNSIGNED)) ++ ++#define PISP_WALLPAPER_WIDTH 128 // in bytes ++ ++#endif /* _PISP_FE_TYPES_H_ */ +diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c +index 5de6b6694f53..a504a69ea25f 100644 +--- a/drivers/media/platform/video-mux.c ++++ b/drivers/media/platform/video-mux.c +@@ -20,10 +20,27 @@ + #include <media/v4l2-mc.h> + #include <media/v4l2-subdev.h> + ++struct video_mux_asd { ++ struct v4l2_async_connection base; ++ unsigned int port; ++}; + -+/* 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) ++static inline struct video_mux_asd *to_video_mux_asd(struct v4l2_async_connection *asd) ++{ ++ return container_of(asd, struct video_mux_asd, base); ++} + -+#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) ++struct video_mux_pad_cfg { ++ unsigned int num_lanes; ++ bool non_continuous; ++ struct v4l2_subdev *source; ++}; + -+/* 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) + struct video_mux { + struct v4l2_subdev subdev; + struct v4l2_async_notifier notifier; + struct media_pad *pads; ++ struct video_mux_pad_cfg *cfg; + struct mux_control *mux; + struct mutex lock; + int active; +@@ -301,10 +318,34 @@ static int video_mux_init_cfg(struct v4l2_subdev *sd, + return 0; + } + ++static int video_mux_get_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) ++{ ++ struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); ++ int ret; + -+/* 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) ++ ret = v4l2_subdev_call(vmux->cfgvmux->active.source, pad, get_mbus_config, ++ 0, cfg); + -+/* 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) ++ if (ret != -ENOIOCTLCMD) ++ return ret; + -+/* UNICAM_CLT Register */ -+#define UNICAM_CLT1_MASK GENMASK(7, 0) -+#define UNICAM_CLT2_MASK GENMASK(15, 8) ++ cfg->type = V4L2_MBUS_CSI2_DPHY; ++ cfg->bus.mipi_csi2.num_data_lanes = vmux->cfgvmux->active.num_lanes; + -+/* 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) ++ /* Support for non-continuous CSI-2 clock is missing in pdate mode */ ++ if (vmux->cfgvmux->active.non_continuous) ++ cfg->bus.mipi_csi2.flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK; + -+#define UNICAM_DAT_MASK_ALL (UNICAM_DLSTE + UNICAM_DLFO) ++ return 0; ++}; + -+/* UNICAM_DLT Register */ -+#define UNICAM_DLT1_MASK GENMASK(7, 0) -+#define UNICAM_DLT2_MASK GENMASK(15, 8) -+#define UNICAM_DLT3_MASK GENMASK(23, 16) + static const struct v4l2_subdev_pad_ops video_mux_pad_ops = { + .init_cfg = video_mux_init_cfg, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = video_mux_set_format, ++ .get_mbus_config = video_mux_get_mbus_config, + }; + + static const struct v4l2_subdev_ops video_mux_subdev_ops = { +@@ -317,6 +358,9 @@ static int video_mux_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_async_connection *asd) + { + struct video_mux *vmux = notifier_to_video_mux(notifier); ++ unsigned int port = to_video_mux_asd(asd)->port; + -+/* 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) ++ vmux->cfgport.source = sd; + + return v4l2_create_fwnode_links(sd, &vmux->subdev); + } +@@ -334,7 +378,7 @@ static int video_mux_async_register(struct video_mux *vmux, + v4l2_async_subdev_nf_init(&vmux->notifier, &vmux->subdev); + + for (i = 0; i < num_input_pads; i++) { +- struct v4l2_async_connection *asd; ++ struct video_mux_asd *asd; + struct fwnode_handle *ep, *remote_ep; + + ep = fwnode_graph_get_endpoint_by_id( +@@ -352,8 +396,7 @@ static int video_mux_async_register(struct video_mux *vmux, + fwnode_handle_put(remote_ep); + + asd = v4l2_async_nf_add_fwnode_remote(&vmux->notifier, ep, +- struct v4l2_async_connection); +- ++ struct video_mux_asd); + fwnode_handle_put(ep); + + if (IS_ERR(asd)) { +@@ -362,6 +405,8 @@ static int video_mux_async_register(struct video_mux *vmux, + if (ret != -EEXIST) + goto err_nf_cleanup; + } + -+/* 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) ++ asd->port = i; + } + + vmux->notifier.ops = &video_mux_notify_ops; +@@ -387,6 +432,9 @@ static int video_mux_probe(struct platform_device *pdev) + { + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; ++ struct v4l2_fwnode_endpoint fwnode_ep = { ++ .bus_type = V4L2_MBUS_CSI2_DPHY ++ }; + struct device_node *ep; + struct video_mux *vmux; + unsigned int num_pads = 0; +@@ -433,10 +481,27 @@ static int video_mux_probe(struct platform_device *pdev) + if (!vmux->pads) + return -ENOMEM; + +- for (i = 0; i < num_pads; i++) ++ vmux->cfg = devm_kcalloc(dev, num_pads, sizeof(*vmux->cfg), GFP_KERNEL); ++ if (!vmux->cfg) ++ return -ENOMEM; + -+/* UNICAM_ISTA Register */ -+#define UNICAM_FSI BIT(0) -+#define UNICAM_FEI BIT(1) -+#define UNICAM_LCI BIT(2) ++ for (i = 0; i < num_pads; i++) { + vmux->padsi.flags = (i < num_pads - 1) ? MEDIA_PAD_FL_SINK + : MEDIA_PAD_FL_SOURCE; + ++ ep = of_graph_get_endpoint_by_regs(pdev->dev.of_node, i, 0); ++ if (ep) { ++ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &fwnode_ep); ++ if (!ret) { ++ /* Get number of data lanes */ ++ vmux->cfgi.num_lanes = fwnode_ep.bus.mipi_csi2.num_data_lanes; ++ vmux->cfgi.non_continuous = fwnode_ep.bus.mipi_csi2.flags & ++ V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK; ++ } ++ of_node_put(ep); ++ } ++ } + -+#define UNICAM_ISTA_MASK_ALL (UNICAM_FSI + UNICAM_FEI + UNICAM_LCI) + vmux->subdev.entity.function = MEDIA_ENT_F_VID_MUX; + ret = media_entity_pads_init(&vmux->subdev.entity, num_pads, + vmux->pads); +diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig +index 07bdf649c60d..75186e63322c 100644 +--- a/drivers/media/rc/Kconfig ++++ b/drivers/media/rc/Kconfig +@@ -319,6 +319,7 @@ config IR_PWM_TX + tristate "PWM IR transmitter" + depends on LIRC + depends on PWM ++ depends on HIGH_RES_TIMERS + depends on OF + help + Say Y if you want to use a PWM based IR transmitter. This is +diff --git a/drivers/media/rc/pwm-ir-tx.c b/drivers/media/rc/pwm-ir-tx.c +index 7732054c4621..f8fdbc83b7e8 100644 +--- a/drivers/media/rc/pwm-ir-tx.c ++++ b/drivers/media/rc/pwm-ir-tx.c +@@ -10,6 +10,8 @@ + #include <linux/slab.h> + #include <linux/of.h> + #include <linux/platform_device.h> ++#include <linux/hrtimer.h> ++#include <linux/completion.h> + #include <media/rc-core.h> + + #define DRIVER_NAME "pwm-ir-tx" +@@ -17,8 +19,14 @@ + + struct pwm_ir { + struct pwm_device *pwm; +- unsigned int carrier; +- unsigned int duty_cycle; ++ struct hrtimer timer; ++ struct completion tx_done; ++ struct pwm_state *state; ++ u32 carrier; ++ u32 duty_cycle; ++ const unsigned int *txbuf; ++ unsigned int txbuf_len; ++ unsigned int txbuf_index; + }; + + static const struct of_device_id pwm_ir_of_match = { +@@ -48,8 +56,8 @@ static int pwm_ir_set_carrier(struct rc_dev *dev, u32 carrier) + return 0; + } + +-static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf, +- unsigned int count) ++static int pwm_ir_tx_sleep(struct rc_dev *dev, unsigned int *txbuf, ++ unsigned int count) + { + struct pwm_ir *pwm_ir = dev->priv; + struct pwm_device *pwm = pwm_ir->pwm; +@@ -67,7 +75,7 @@ static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf, + + for (i = 0; i < count; i++) { + state.enabled = !(i % 2); +- pwm_apply_state(pwm, &state); ++ pwm_apply_might_sleep(pwm, &state); + + edge = ktime_add_us(edge, txbufi); + delta = ktime_us_delta(edge, ktime_get()); +@@ -76,11 +84,67 @@ static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf, + } + + state.enabled = false; +- pwm_apply_state(pwm, &state); ++ pwm_apply_might_sleep(pwm, &state); + + return count; + } + ++static int pwm_ir_tx_atomic(struct rc_dev *dev, unsigned int *txbuf, ++ unsigned int count) ++{ ++ struct pwm_ir *pwm_ir = dev->priv; ++ struct pwm_device *pwm = pwm_ir->pwm; ++ struct pwm_state state; + -+/* 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) ++ pwm_init_state(pwm, &state); + -+/* 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) ++ state.period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, pwm_ir->carrier); ++ pwm_set_relative_duty_cycle(&state, pwm_ir->duty_cycle, 100); + -+/* 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) ++ pwm_ir->txbuf = txbuf; ++ pwm_ir->txbuf_len = count; ++ pwm_ir->txbuf_index = 0; ++ pwm_ir->state = &state; + -+/* UNICAM_DBCTL Register */ -+#define UNICAM_DBEN BIT(0) -+#define UNICAM_BUF0_IE BIT(1) -+#define UNICAM_BUF1_IE BIT(2) ++ hrtimer_start(&pwm_ir->timer, 0, HRTIMER_MODE_REL); + -+/* UNICAM_CMP0,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) ++ wait_for_completion(&pwm_ir->tx_done); + -+/* UNICAM_MISC register */ -+#define UNICAM_FL0 BIT(6) -+#define UNICAM_FL1 BIT(9) ++ return count; ++} + -+#endif ++static enum hrtimer_restart pwm_ir_timer(struct hrtimer *timer) ++{ ++ struct pwm_ir *pwm_ir = container_of(timer, struct pwm_ir, timer); ++ ktime_t now; ++ ++ /* ++ * If we happen to hit an odd latency spike, loop through the ++ * pulses until we catch up. ++ */ ++ do { ++ u64 ns; ++ ++ pwm_ir->state->enabled = !(pwm_ir->txbuf_index % 2); ++ pwm_apply_atomic(pwm_ir->pwm, pwm_ir->state); ++ ++ if (pwm_ir->txbuf_index >= pwm_ir->txbuf_len) { ++ complete(&pwm_ir->tx_done); ++ ++ return HRTIMER_NORESTART; ++ } ++ ++ ns = US_TO_NS(pwm_ir->txbufpwm_ir->txbuf_index); ++ hrtimer_add_expires_ns(timer, ns); ++ ++ pwm_ir->txbuf_index++; ++ ++ now = timer->base->get_time(); ++ } while (hrtimer_get_expires_tv64(timer) < now); ++ ++ return HRTIMER_RESTART; ++} ++ + static int pwm_ir_probe(struct platform_device *pdev) + { + struct pwm_ir *pwm_ir; +@@ -102,10 +166,19 @@ static int pwm_ir_probe(struct platform_device *pdev) + if (!rcdev) + return -ENOMEM; + ++ if (pwm_might_sleep(pwm_ir->pwm)) { ++ dev_info(&pdev->dev, "TX will not be accurate as PWM device might sleep\n"); ++ rcdev->tx_ir = pwm_ir_tx_sleep; ++ } else { ++ init_completion(&pwm_ir->tx_done); ++ hrtimer_init(&pwm_ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ pwm_ir->timer.function = pwm_ir_timer; ++ rcdev->tx_ir = pwm_ir_tx_atomic; ++ } ++ + rcdev->priv = pwm_ir; + rcdev->driver_name = DRIVER_NAME; + rcdev->device_name = DEVICE_NAME; +- rcdev->tx_ir = pwm_ir_tx; + rcdev->s_tx_duty_cycle = pwm_ir_set_duty_cycle; + rcdev->s_tx_carrier = pwm_ir_set_carrier; + diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig -index 857ef4ace6e9..deae75ea3c44 100644 +index 4656afae5bb4..328ea94d14f9 100644 --- a/drivers/media/spi/Kconfig +++ b/drivers/media/spi/Kconfig -@@ -25,6 +25,7 @@ menu "Media SPI Adapters" +@@ -9,6 +9,7 @@ menu "Media SPI Adapters" config CXD2880_SPI_DRV tristate "Sony CXD2880 SPI support" depends on DVB_CORE && SPI @@ -85145,10 +135795,10 @@ help Choose if you would like to have SPI interface support for Sony CXD2880. diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c -index c278b9b0f102..05f2297cf583 100644 +index f7884bb56fcc..b0a2fd7e13aa 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c -@@ -1953,6 +1953,10 @@ static const struct usb_device_id rtl28xxu_id_table = { +@@ -1964,6 +1964,10 @@ static const struct usb_device_id rtl28xxu_id_table = { &rtl28xxu_props, "Compro VideoMate U650F", NULL) }, { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd394, &rtl28xxu_props, "MaxMedia HU394-T", NULL) }, @@ -85159,11 +135809,11 @@ { 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 --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c -index 41f8410d08d6..2099a4d814e4 100644 ---- a/drivers/media/v4l2-core/v4l2-ctrls.c -+++ b/drivers/media/v4l2-core/v4l2-ctrls.c -@@ -275,6 +275,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id) +diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c +index 8696eb1cdd61..6d826474fe57 100644 +--- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c ++++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c +@@ -228,6 +228,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "Flash", "Cloudy", "Shade", @@ -85171,85 +135821,69 @@ NULL, }; static const char * const camera_iso_sensitivity_auto = { -@@ -1021,6 +1022,7 @@ const char *v4l2_ctrl_get_name(u32 id) - 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"; - -@@ -1130,6 +1132,7 @@ const char *v4l2_ctrl_get_name(u32 id) - case V4L2_CID_TEST_PATTERN_GREENR: return "Green (Red) Pixel Value"; - case V4L2_CID_TEST_PATTERN_BLUE: return "Blue Pixel Value"; - case V4L2_CID_TEST_PATTERN_GREENB: return "Green (Blue) Pixel Value"; -+ case V4L2_CID_NOTIFY_GAINS: return "Notify Gains"; - - /* Image processing controls */ - /* Keep the order of the 'case's the same as in v4l2-controls.h! */ -@@ -1461,6 +1464,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, - 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; -@@ -1934,6 +1940,9 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, - 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) -@@ -2644,6 +2653,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, - 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 --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c -index 6d6d30dbbe68..2ee902f64ddc 100644 +index f4d9d6279094..0ba33c03bb21 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c -@@ -1301,6 +1301,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) +@@ -1298,6 +1298,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) + case V4L2_PIX_FMT_RGBX1010102: descr = "32-bit RGBX 10-10-10-2"; break; + case V4L2_PIX_FMT_RGBA1010102: descr = "32-bit RGBA 10-10-10-2"; break; + case V4L2_PIX_FMT_ARGB2101010: descr = "32-bit ARGB 2-10-10-10"; break; ++ case V4L2_PIX_FMT_BGR48: descr = "48-bit BGR 16-16-16"; break; ++ case V4L2_PIX_FMT_RGB48: descr = "48-bit RGB 16-16-16"; break; + case V4L2_PIX_FMT_BGR48_12: descr = "12-bit Depth BGR"; break; + case V4L2_PIX_FMT_ABGR64_12: descr = "12-bit Depth BGRA"; break; + case V4L2_PIX_FMT_GREY: descr = "8-bit Greyscale"; break; +@@ -1311,6 +1313,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) 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_IPU3_Y10: descr = "10-bit greyscale (IPU3 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; -@@ -1343,6 +1345,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) - 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; +@@ -1365,6 +1369,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) + case V4L2_PIX_FMT_NV12MT: descr = "Y/UV 4:2:0 (64x32 MB, N-C)"; break; + case V4L2_PIX_FMT_NV12MT_16X16: descr = "Y/UV 4:2:0 (16x16 MB, N-C)"; break; + case V4L2_PIX_FMT_P012M: descr = "12-bit Y/UV 4:2:0 (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; -@@ -1420,6 +1424,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) - 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; +@@ -1452,6 +1458,11 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) + case V4L2_PIX_FMT_Y210: descr = "10-bit YUYV Packed"; break; + case V4L2_PIX_FMT_Y212: descr = "12-bit YUYV Packed"; break; + case V4L2_PIX_FMT_Y216: descr = "16-bit YUYV Packed"; break; + case V4L2_META_FMT_SENSOR_DATA: descr = "Sensor Ancillary Metadata"; break; + case V4L2_META_FMT_BCM2835_ISP_STATS: descr = "BCM2835 ISP Image Statistics"; break; ++ case V4L2_META_FMT_RPI_BE_CFG: descr = "PiSP BE Config format"; break; ++ case V4L2_META_FMT_RPI_FE_CFG: descr = "PiSP FE Config format"; break; ++ case V4L2_META_FMT_RPI_FE_STATS: descr = "PiSP FE Statistics format"; break; default: /* Compressed formats */ +@@ -1510,6 +1521,17 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) + case V4L2_PIX_FMT_AV1_FRAME: descr = "AV1 Frame"; break; + case V4L2_PIX_FMT_MT2110T: descr = "Mediatek 10bit Tile Mode"; break; + case V4L2_PIX_FMT_MT2110R: descr = "Mediatek 10bit Raster Mode"; break; ++ case V4L2_PIX_FMT_RPI_BE: descr = "PiSP Opaque Format"; break; ++ case V4L2_PIX_FMT_PISP_COMP1_RGGB: ++ case V4L2_PIX_FMT_PISP_COMP1_GRBG: ++ case V4L2_PIX_FMT_PISP_COMP1_GBRG: ++ case V4L2_PIX_FMT_PISP_COMP1_BGGR: ++ case V4L2_PIX_FMT_PISP_COMP1_MONO: descr = "PiSP Bayer Compressed Format"; break; ++ case V4L2_PIX_FMT_PISP_COMP2_RGGB: ++ case V4L2_PIX_FMT_PISP_COMP2_GRBG: ++ case V4L2_PIX_FMT_PISP_COMP2_GBRG: ++ case V4L2_PIX_FMT_PISP_COMP2_BGGR: ++ case V4L2_PIX_FMT_PISP_COMP2_MONO: descr = "PiSP Bayer Comp 2"; break; + default: + if (fmt->description0) + return; diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c -index b221b4e438a1..fb8708ddc1dc 100644 +index 0cc30397fbad..55444b9b3a5a 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -301,9 +301,10 @@ static void __v4l2_m2m_try_queue(struct v4l2_m2m_dev *m2m_dev, @@ -85266,7 +135900,7 @@ return; } -@@ -491,8 +492,6 @@ void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, +@@ -492,8 +493,6 @@ void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, * holding capture buffers. Those should use * v4l2_m2m_buf_done_and_job_finish() instead. */ @@ -85275,75 +135909,8 @@ 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 --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c -index fbf0dcb313c8..bf3aa9252458 100644 ---- a/drivers/media/v4l2-core/v4l2-subdev.c -+++ b/drivers/media/v4l2-core/v4l2-subdev.c -@@ -768,21 +768,55 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd, - struct v4l2_subdev_format *source_fmt, - struct v4l2_subdev_format *sink_fmt) - { -+ bool pass = true; -+ - /* The width, height and code must match. */ -- if (source_fmt->format.width != sink_fmt->format.width -- || source_fmt->format.height != sink_fmt->format.height -- || source_fmt->format.code != sink_fmt->format.code) -- return -EPIPE; -+ if (source_fmt->format.width != sink_fmt->format.width) { -+ dev_dbg(sd->entity.graph_obj.mdev->dev, -+ "%s: width does not match (source %u, sink %u)\n", -+ __func__, -+ source_fmt->format.width, sink_fmt->format.width); -+ pass = false; -+ } -+ -+ if (source_fmt->format.height != sink_fmt->format.height) { -+ dev_dbg(sd->entity.graph_obj.mdev->dev, -+ "%s: height does not match (source %u, sink %u)\n", -+ __func__, -+ source_fmt->format.height, sink_fmt->format.height); -+ pass = false; -+ } -+ -+ if (source_fmt->format.code != sink_fmt->format.code) { -+ dev_dbg(sd->entity.graph_obj.mdev->dev, -+ "%s: media bus code does not match (source 0x%8.8x, sink 0x%8.8x)\n", -+ __func__, -+ source_fmt->format.code, sink_fmt->format.code); -+ pass = false; -+ } - - /* The field order must match, or the sink field order must be NONE - * to support interlaced hardware connected to bridges that support - * progressive formats only. - */ - if (source_fmt->format.field != sink_fmt->format.field && -- sink_fmt->format.field != V4L2_FIELD_NONE) -- return -EPIPE; -+ sink_fmt->format.field != V4L2_FIELD_NONE) { -+ dev_dbg(sd->entity.graph_obj.mdev->dev, -+ "%s: field does not match (source %u, sink %u)\n", -+ __func__, -+ source_fmt->format.field, sink_fmt->format.field); -+ pass = false; -+ } - -- return 0; -+ if (pass) -+ return 0; -+ -+ dev_dbg(sd->entity.graph_obj.mdev->dev, -+ "%s: link was \"%s\":%u -> \"%s\":%u\n", __func__, -+ link->source->entity->name, link->source->index, -+ link->sink->entity->name, link->sink->index); -+ -+ return -EPIPE; - } - EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default); - diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig -index 15680c3c9279..947c2ab6fff3 100644 +index 6b653487d954..cc9eae073fc1 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -11,6 +11,14 @@ config MFD_CORE @@ -85361,46 +135928,505 @@ config MFD_CS5535 tristate "AMD CS5535 and CS5536 southbridge core functions" select MFD_CORE +@@ -1178,6 +1186,16 @@ config MFD_SY7636A + To enable support for building sub-devices as modules, + choose M here. + ++config MFD_RASPBERRYPI_POE_HAT ++ tristate "Raspberry Pi PoE HAT MFD" ++ depends on I2C ++ select MFD_SIMPLE_MFD_I2C ++ help ++ This module supports the PWM fan controller found on the Raspberry Pi ++ POE and POE+ HAT boards, and the power supply driver on the POE+ HAT. ++ (Functionally it relies on MFD_SIMPLE_MFD_I2C to provide the framework ++ that loads the child drivers). ++ + config MFD_RDC321X + tristate "RDC R-321x southbridge" + select MFD_CORE +@@ -2321,6 +2339,17 @@ config MFD_INTEL_M10_BMC_PMCI + additional drivers must be enabled in order to use the functionality + of the device. + ++config MFD_RP1 ++ tristate "RP1 MFD driver" ++ depends on PCI ++ select MFD_CORE ++ help ++ Support for the RP1 peripheral chip. ++ ++ This driver provides support for the Raspberry Pi RP1 peripheral chip. ++ It is responsible for enabling the Device Tree node once the PCIe endpoint ++ has been configured, and handling interrupts. ++ + config MFD_RSMU_I2C + tristate "Renesas Synchronization Management Unit with I2C" + depends on I2C && OF diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile -index fb1df45a301e..b2eb091e9703 100644 +index 700b3600eb79..3eff03c6d6ba 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile -@@ -263,6 +263,7 @@ obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o - obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o - obj-$(CONFIG_MFD_STMFX) += stmfx.o +@@ -268,6 +268,7 @@ obj-$(CONFIG_MFD_STMFX) += stmfx.o obj-$(CONFIG_MFD_KHADAS_MCU) += khadas-mcu.o + obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o + obj-$(CONFIG_MFD_QCOM_PM8008) += qcom-pm8008.o +obj-$(CONFIG_MFD_RPISENSE_CORE) += rpisense-core.o obj-$(CONFIG_LPC_CHIP3) += lpc_sunway_chip3.o obj-$(CONFIG_SUNWAY_SUPERIO_AST2400) += sunway_ast2400.o +@@ -287,3 +288,5 @@ rsmu-i2c-objs := rsmu_core.o rsmu_i2c.o + rsmu-spi-objs := rsmu_core.o rsmu_spi.o + obj-$(CONFIG_MFD_RSMU_I2C) += rsmu-i2c.o + obj-$(CONFIG_MFD_RSMU_SPI) += rsmu-spi.o ++ ++obj-$(CONFIG_MFD_RP1) += rp1.o diff --git a/drivers/mfd/bcm2835-pm.c b/drivers/mfd/bcm2835-pm.c -index 42fe67f1538e..f66f92fe28c3 100644 +index 3cb2b9423121..8b31775da7b6 100644 --- a/drivers/mfd/bcm2835-pm.c +++ b/drivers/mfd/bcm2835-pm.c -@@ -50,6 +50,17 @@ static int bcm2835_pm_probe(struct platform_device *pdev) - if (ret) - return ret; +@@ -69,12 +69,30 @@ static int bcm2835_pm_get_pdata(struct platform_device *pdev, + return 0; + } -+ /* 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); -+ } ++static const struct of_device_id bcm2835_pm_of_match = { ++ { .compatible = "brcm,bcm2835-pm-wdt", }, ++ { .compatible = "brcm,bcm2835-pm", }, ++ { .compatible = "brcm,bcm2711-pm", }, ++ { .compatible = "brcm,bcm2712-pm", .data = (const void *)1}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match); ++ + static int bcm2835_pm_probe(struct platform_device *pdev) + { ++ const struct of_device_id *of_id; + struct device *dev = &pdev->dev; + struct bcm2835_pm *pm; ++ bool is_2712; + int ret; + ++ of_id = of_match_node(bcm2835_pm_of_match, pdev->dev.of_node); ++ if (!of_id) { ++ dev_err(&pdev->dev, "Failed to match compatible string\n"); ++ return -EINVAL; + } ++ is_2712 = !!of_id->data; + - /* We'll use the presence of the AXI ASB regs in the + pm = devm_kzalloc(dev, sizeof(*pm), GFP_KERNEL); + if (!pm) + return -ENOMEM; +@@ -97,21 +115,13 @@ static int bcm2835_pm_probe(struct platform_device *pdev) * bcm2835-pm binding as the key for whether we can reference * the full PM register range and support power domains. + */ +- if (pm->asb) ++ if (pm->asb || is_2712) + return devm_mfd_add_devices(dev, -1, bcm2835_power_devs, + ARRAY_SIZE(bcm2835_power_devs), + NULL, 0, NULL); + return 0; + } + +-static const struct of_device_id bcm2835_pm_of_match = { +- { .compatible = "brcm,bcm2835-pm-wdt", }, +- { .compatible = "brcm,bcm2835-pm", }, +- { .compatible = "brcm,bcm2711-pm", }, +- {}, +-}; +-MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match); +- + static struct platform_driver bcm2835_pm_driver = { + .probe = bcm2835_pm_probe, + .driver = { +diff --git a/drivers/mfd/rp1.c b/drivers/mfd/rp1.c +new file mode 100644 +index 000000000000..0a498a670a81 +--- /dev/null ++++ b/drivers/mfd/rp1.c +@@ -0,0 +1,376 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2018-22 Raspberry Pi Ltd. ++ * All rights reserved. ++ */ ++ ++#include <linux/clk.h> ++#include <linux/clkdev.h> ++#include <linux/clk-provider.h> ++#include <linux/completion.h> ++#include <linux/etherdevice.h> ++#include <linux/err.h> ++#include <linux/interrupt.h> ++#include <linux/io.h> ++#include <linux/irq.h> ++#include <linux/irqchip/chained_irq.h> ++#include <linux/irqdomain.h> ++#include <linux/mfd/core.h> ++#include <linux/mmc/host.h> ++#include <linux/module.h> ++#include <linux/msi.h> ++#include <linux/of_platform.h> ++#include <linux/pci.h> ++#include <linux/platform_device.h> ++#include <linux/rp1_platform.h> ++#include <linux/reset.h> ++#include <linux/slab.h> ++ ++#include <dt-bindings/mfd/rp1.h> ++ ++/* TO DO: ++ * 1. Occasional shutdown crash - RP1 being closed before its children? ++ * 2. DT mode interrupt handling. ++ */ ++ ++#define RP1_DRIVER_NAME "rp1" ++ ++#define PCI_VENDOR_ID_RPI 0x1de4 ++#define PCI_DEVICE_ID_RP1_C0 0x0001 ++#define PCI_DEVICE_REV_RP1_C0 2 ++ ++#define RP1_ACTUAL_IRQS RP1_INT_END ++#define RP1_IRQS RP1_ACTUAL_IRQS ++ ++#define RP1_SYSCLK_RATE 200000000 ++#define RP1_SYSCLK_FPGA_RATE 60000000 ++ ++// Don't want to include the whole sysinfo reg header ++#define SYSINFO_CHIP_ID_OFFSET 0x00000000 ++#define SYSINFO_PLATFORM_OFFSET 0x00000004 ++ ++#define REG_RW 0x000 ++#define REG_SET 0x800 ++#define REG_CLR 0xc00 ++ ++// MSIX CFG registers start at 0x8 ++#define MSIX_CFG(x) (0x8 + (4 * (x))) ++ ++#define MSIX_CFG_IACK_EN BIT(3) ++#define MSIX_CFG_IACK BIT(2) ++#define MSIX_CFG_TEST BIT(1) ++#define MSIX_CFG_ENABLE BIT(0) ++ ++#define INTSTATL 0x108 ++#define INTSTATH 0x10c ++ ++struct rp1_dev { ++ struct pci_dev *pdev; ++ struct device *dev; ++ resource_size_t bar_start; ++ resource_size_t bar_end; ++ struct clk *sys_clk; ++ struct irq_domain *domain; ++ struct irq_data *pcie_irqds64; ++ void __iomem *msix_cfg_regs; ++}; ++ ++static bool rp1_level_triggered_irqRP1_ACTUAL_IRQS = { 0 }; ++ ++static struct rp1_dev *g_rp1; ++static u32 g_chip_id, g_platform; ++ ++static void dump_bar(struct pci_dev *pdev, unsigned int bar) ++{ ++ dev_info(&pdev->dev, ++ "bar%d len 0x%llx, start 0x%llx, end 0x%llx, flags, 0x%lx\n", ++ bar, ++ pci_resource_len(pdev, bar), ++ pci_resource_start(pdev, bar), ++ pci_resource_end(pdev, bar), ++ pci_resource_flags(pdev, bar)); ++} ++ ++static void msix_cfg_set(struct rp1_dev *rp1, unsigned int hwirq, u32 value) ++{ ++ writel(value, rp1->msix_cfg_regs + REG_SET + MSIX_CFG(hwirq)); ++} ++ ++static void msix_cfg_clr(struct rp1_dev *rp1, unsigned int hwirq, u32 value) ++{ ++ writel(value, rp1->msix_cfg_regs + REG_CLR + MSIX_CFG(hwirq)); ++} ++ ++static void rp1_mask_irq(struct irq_data *irqd) ++{ ++ struct rp1_dev *rp1 = irqd->domain->host_data; ++ struct irq_data *pcie_irqd = rp1->pcie_irqdsirqd->hwirq; ++ ++ pci_msi_mask_irq(pcie_irqd); ++} ++ ++static void rp1_unmask_irq(struct irq_data *irqd) ++{ ++ struct rp1_dev *rp1 = irqd->domain->host_data; ++ struct irq_data *pcie_irqd = rp1->pcie_irqdsirqd->hwirq; ++ ++ pci_msi_unmask_irq(pcie_irqd); ++} ++ ++static int rp1_irq_set_type(struct irq_data *irqd, unsigned int type) ++{ ++ struct rp1_dev *rp1 = irqd->domain->host_data; ++ unsigned int hwirq = (unsigned int)irqd->hwirq; ++ int ret = 0; ++ ++ switch (type) { ++ case IRQ_TYPE_LEVEL_HIGH: ++ dev_dbg(rp1->dev, "MSIX IACK EN for irq %d\n", hwirq); ++ msix_cfg_set(rp1, hwirq, MSIX_CFG_IACK_EN); ++ rp1_level_triggered_irqhwirq = true; ++ break; ++ case IRQ_TYPE_EDGE_RISING: ++ msix_cfg_clr(rp1, hwirq, MSIX_CFG_IACK_EN); ++ rp1_level_triggered_irqhwirq = false; ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++static int rp1_irq_set_affinity(struct irq_data *irqd, const struct cpumask *dest, bool force) ++{ ++ struct rp1_dev *rp1 = irqd->domain->host_data; ++ struct irq_data *pcie_irqd = rp1->pcie_irqdsirqd->hwirq; ++ ++ return msi_domain_set_affinity(pcie_irqd, dest, force); ++} ++ ++static struct irq_chip rp1_irq_chip = { ++ .name = "rp1_irq_chip", ++ .irq_mask = rp1_mask_irq, ++ .irq_unmask = rp1_unmask_irq, ++ .irq_set_type = rp1_irq_set_type, ++ .irq_set_affinity = rp1_irq_set_affinity, ++}; ++ ++static void rp1_chained_handle_irq(struct irq_desc *desc) ++{ ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ struct rp1_dev *rp1 = desc->irq_data.chip_data; ++ unsigned int hwirq = desc->irq_data.hwirq & 0x3f; ++ int new_irq; ++ ++ rp1 = g_rp1; ++ ++ chained_irq_enter(chip, desc); ++ ++ new_irq = irq_linear_revmap(rp1->domain, hwirq); ++ generic_handle_irq(new_irq); ++ if (rp1_level_triggered_irqhwirq) ++ msix_cfg_set(rp1, hwirq, MSIX_CFG_IACK); ++ ++ chained_irq_exit(chip, desc); ++} ++ ++static int rp1_irq_xlate(struct irq_domain *d, struct device_node *node, ++ const u32 *intspec, unsigned int intsize, ++ unsigned long *out_hwirq, unsigned int *out_type) ++{ ++ struct rp1_dev *rp1 = d->host_data; ++ struct irq_data *pcie_irqd; ++ unsigned long hwirq; ++ int pcie_irq; ++ int ret; ++ ++ ret = irq_domain_xlate_twocell(d, node, intspec, intsize, ++ &hwirq, out_type); ++ if (!ret) { ++ pcie_irq = pci_irq_vector(rp1->pdev, hwirq); ++ pcie_irqd = irq_get_irq_data(pcie_irq); ++ rp1->pcie_irqdshwirq = pcie_irqd; ++ *out_hwirq = hwirq; ++ } ++ return ret; ++} ++ ++static int rp1_irq_activate(struct irq_domain *d, struct irq_data *irqd, ++ bool reserve) ++{ ++ struct rp1_dev *rp1 = d->host_data; ++ struct irq_data *pcie_irqd; ++ ++ pcie_irqd = rp1->pcie_irqdsirqd->hwirq; ++ msix_cfg_set(rp1, (unsigned int)irqd->hwirq, MSIX_CFG_ENABLE); ++ return irq_domain_activate_irq(pcie_irqd, reserve); ++} ++ ++static void rp1_irq_deactivate(struct irq_domain *d, struct irq_data *irqd) ++{ ++ struct rp1_dev *rp1 = d->host_data; ++ struct irq_data *pcie_irqd; ++ ++ pcie_irqd = rp1->pcie_irqdsirqd->hwirq; ++ msix_cfg_clr(rp1, (unsigned int)irqd->hwirq, MSIX_CFG_ENABLE); ++ return irq_domain_deactivate_irq(pcie_irqd); ++} ++ ++static const struct irq_domain_ops rp1_domain_ops = { ++ .xlate = rp1_irq_xlate, ++ .activate = rp1_irq_activate, ++ .deactivate = rp1_irq_deactivate, ++}; ++ ++static inline dma_addr_t rp1_io_to_phys(struct rp1_dev *rp1, unsigned int offset) ++{ ++ return rp1->bar_start + offset; ++} ++ ++static u32 rp1_reg_read(struct rp1_dev *rp1, unsigned int base_addr, u32 offset) ++{ ++ dma_addr_t phys = rp1_io_to_phys(rp1, base_addr); ++ void __iomem *regblock = ioremap(phys, 0x1000); ++ u32 value = readl(regblock + offset); ++ ++ iounmap(regblock); ++ return value; ++} ++ ++void rp1_get_platform(u32 *chip_id, u32 *platform) ++{ ++ if (chip_id) ++ *chip_id = g_chip_id; ++ if (platform) ++ *platform = g_platform; ++} ++EXPORT_SYMBOL_GPL(rp1_get_platform); ++ ++static int rp1_probe(struct pci_dev *pdev, const struct pci_device_id *id) ++{ ++ struct reset_control *reset; ++ struct platform_device *pcie_pdev; ++ struct device_node *rp1_node; ++ struct rp1_dev *rp1; ++ int err = 0; ++ int i; ++ ++ reset = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); ++ if (IS_ERR(reset)) ++ return PTR_ERR(reset); ++ reset_control_reset(reset); ++ ++ dump_bar(pdev, 0); ++ dump_bar(pdev, 1); ++ ++ if (pci_resource_len(pdev, 1) <= 0x10000) { ++ dev_err(&pdev->dev, ++ "Not initialised - is the firmware running?\n"); ++ return -EINVAL; ++ } ++ ++ /* enable pci device */ ++ err = pcim_enable_device(pdev); ++ if (err < 0) { ++ dev_err(&pdev->dev, "Enabling PCI device has failed: %d", ++ err); ++ return err; ++ } ++ ++ pci_set_master(pdev); ++ ++ err = pci_alloc_irq_vectors(pdev, RP1_IRQS, RP1_IRQS, ++ PCI_IRQ_MSIX); ++ if (err != RP1_IRQS) { ++ dev_err(&pdev->dev, "pci_alloc_irq_vectors failed - %d\n", err); ++ return err; ++ } ++ ++ rp1 = devm_kzalloc(&pdev->dev, sizeof(*rp1), GFP_KERNEL); ++ if (!rp1) ++ return -ENOMEM; ++ ++ rp1->pdev = pdev; ++ rp1->dev = &pdev->dev; ++ ++ pci_set_drvdata(pdev, rp1); ++ ++ rp1->bar_start = pci_resource_start(pdev, 1); ++ rp1->bar_end = pci_resource_end(pdev, 1); ++ ++ // Get chip id ++ g_chip_id = rp1_reg_read(rp1, RP1_SYSINFO_BASE, SYSINFO_CHIP_ID_OFFSET); ++ g_platform = rp1_reg_read(rp1, RP1_SYSINFO_BASE, SYSINFO_PLATFORM_OFFSET); ++ dev_info(&pdev->dev, "chip_id 0x%x%s\n", g_chip_id, ++ (g_platform & RP1_PLATFORM_FPGA) ? " FPGA" : ""); ++ if (g_chip_id != RP1_C0_CHIP_ID) { ++ dev_err(&pdev->dev, "wrong chip id (%x)\n", g_chip_id); ++ return -EINVAL; ++ } ++ ++ rp1_node = of_find_node_by_name(NULL, "rp1"); ++ if (!rp1_node) { ++ dev_err(&pdev->dev, "failed to find RP1 DT node\n"); ++ return -EINVAL; ++ } ++ ++ pcie_pdev = of_find_device_by_node(rp1_node->parent); ++ rp1->domain = irq_domain_add_linear(rp1_node, RP1_IRQS, ++ &rp1_domain_ops, rp1); ++ ++ g_rp1 = rp1; ++ ++ /* TODO can this go in the rp1 device tree entry? */ ++ rp1->msix_cfg_regs = ioremap(rp1_io_to_phys(rp1, RP1_PCIE_APBS_BASE), 0x1000); ++ ++ for (i = 0; i < RP1_IRQS; i++) { ++ int irq = irq_create_mapping(rp1->domain, i); ++ ++ if (irq < 0) { ++ dev_err(&pdev->dev, "failed to create irq mapping\n"); ++ return irq; ++ } ++ ++ irq_set_chip_data(irq, rp1); ++ irq_set_chip_and_handler(irq, &rp1_irq_chip, handle_level_irq); ++ irq_set_probe(irq); ++ irq_set_chained_handler(pci_irq_vector(pdev, i), ++ rp1_chained_handle_irq); ++ } ++ ++ if (rp1_node) ++ of_platform_populate(rp1_node, NULL, NULL, &pcie_pdev->dev); ++ ++ of_node_put(rp1_node); ++ ++ return 0; ++} ++ ++static void rp1_remove(struct pci_dev *pdev) ++{ ++ struct rp1_dev *rp1 = pci_get_drvdata(pdev); ++ ++ mfd_remove_devices(&pdev->dev); ++ ++ clk_unregister(rp1->sys_clk); ++} ++ ++static const struct pci_device_id dev_id_table = { ++ { PCI_DEVICE(PCI_VENDOR_ID_RPI, PCI_DEVICE_ID_RP1_C0), }, ++ { 0, } ++}; ++ ++static struct pci_driver rp1_driver = { ++ .name = RP1_DRIVER_NAME, ++ .id_table = dev_id_table, ++ .probe = rp1_probe, ++ .remove = rp1_remove, ++}; ++ ++module_pci_driver(rp1_driver); ++ ++MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.com>"); ++MODULE_DESCRIPTION("RP1 wrapper"); ++MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/rpisense-core.c b/drivers/mfd/rpisense-core.c new file mode 100644 -index 000000000000..6cfd63e5e8b8 +index 000000000000..87a319525a0f --- /dev/null +++ b/drivers/mfd/rpisense-core.c -@@ -0,0 +1,165 @@ +@@ -0,0 +1,163 @@ +/* + * Raspberry Pi Sense HAT core driver + * http://raspberrypi.org @@ -85451,8 +136477,7 @@ + } +} + -+static int rpisense_probe(struct i2c_client *i2c, -+ const struct i2c_device_id *id) ++static int rpisense_probe(struct i2c_client *i2c) +{ + int ret; + struct rpisense_js *rpisense_js; @@ -85498,12 +136523,11 @@ + return 0; +} + -+static int rpisense_remove(struct i2c_client *i2c) ++static void 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) @@ -85566,8 +136590,36 @@ +MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>"); +MODULE_LICENSE("GPL"); + +diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c +index 6eda79533208..7b98ee263967 100644 +--- a/drivers/mfd/simple-mfd-i2c.c ++++ b/drivers/mfd/simple-mfd-i2c.c +@@ -29,6 +29,15 @@ static const struct regmap_config regmap_config_8r_8v = { + .val_bits = 8, + }; + ++static const struct regmap_config regmap_config_16r_8v = { ++ .reg_bits = 16, ++ .val_bits = 8, ++}; ++ ++static const struct simple_mfd_data rpi_poe_core = { ++ .regmap_config = ®map_config_16r_8v, ++}; ++ + static int simple_mfd_i2c_probe(struct i2c_client *i2c) + { + const struct simple_mfd_data *simple_mfd_data; +@@ -88,6 +97,7 @@ static const struct of_device_id simple_mfd_i2c_of_match = { + { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a}, + { .compatible = "maxim,max5970", .data = &maxim_max5970}, + { .compatible = "maxim,max5978", .data = &maxim_max5970}, ++ { .compatible = "raspberrypi,poe-core", &rpi_poe_core }, + {} + }; + MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig -index fafa8b0d8099..5b01870e8f6f 100644 +index 7178d7da37e0..dd25ffdaffcf 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -9,6 +9,14 @@ config SENSORS_LIS3LV02D @@ -85586,23 +136638,23 @@ tristate "Analog Devices Digital Potentiometers" depends on (I2C || SPI) && SYSFS diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile -index d23231e73330..3fd91279bdd9 100644 +index 16fe31fbf7d4..8e59afc0b1a3 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile -@@ -11,6 +11,7 @@ obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o - obj-$(CONFIG_INTEL_MID_PTI) += pti.o +@@ -9,6 +9,7 @@ obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o + obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o + obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.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 --git a/drivers/misc/bcm2835_smi.c b/drivers/misc/bcm2835_smi.c new file mode 100644 -index 000000000000..f1a7f6a3e966 +index 000000000000..acb54c2224cd --- /dev/null +++ b/drivers/misc/bcm2835_smi.c -@@ -0,0 +1,955 @@ +@@ -0,0 +1,953 @@ +/** + * Broadcom Secondary Memory Interface driver + * @@ -85669,7 +136721,7 @@ + struct device *dev; + struct smi_settings settings; + __iomem void *smi_regs_ptr; -+ dma_addr_t smi_regs_busaddr; ++ phys_addr_t smi_regs_busaddr; + + struct dma_chan *dma_chan; + struct dma_slave_config dma_config; @@ -86294,7 +137346,7 @@ + inst->dev, + (void *)buf, + n_bytes, -+ DMA_MEM_TO_DEV); ++ DMA_TO_DEVICE); + struct scatterlist *sgl = + smi_scatterlist_from_buffer(inst, phy_addr, n_bytes, + &inst->buffer_sgl); @@ -86307,7 +137359,7 @@ + smi_dma_write_sgl(inst, sgl, 1, n_bytes); + + dma_unmap_single -+ (inst->dev, phy_addr, n_bytes, DMA_MEM_TO_DEV); ++ (inst->dev, phy_addr, n_bytes, DMA_TO_DEVICE); + } else if (n_bytes) { + smi_write_fifo(inst, (uint32_t *) buf, n_bytes); + } @@ -86353,7 +137405,7 @@ + if (n_bytes > DMA_THRESHOLD_BYTES) { + dma_addr_t phy_addr = dma_map_single(inst->dev, + buf, n_bytes, -+ DMA_DEV_TO_MEM); ++ DMA_FROM_DEVICE); + struct scatterlist *sgl = smi_scatterlist_from_buffer( + inst, phy_addr, n_bytes, + &inst->buffer_sgl); @@ -86363,7 +137415,7 @@ + goto out; + } + smi_dma_read_sgl(inst, sgl, 1, n_bytes); -+ dma_unmap_single(inst->dev, phy_addr, n_bytes, DMA_DEV_TO_MEM); ++ dma_unmap_single(inst->dev, phy_addr, n_bytes, DMA_FROM_DEVICE); + } else if (n_bytes) { + smi_read_fifo(inst, (uint32_t *)buf, n_bytes); + } @@ -86463,7 +137515,6 @@ + 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) @@ -86477,14 +137528,13 @@ + 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); ++ inst->smi_regs_ptr = devm_platform_get_and_ioremap_resource(pdev, 0, ++ &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); ++ inst->smi_regs_busaddr = ioresource->start; + + err = bcm2835_smi_dma_setup(inst); + if (err) @@ -86559,10 +137609,10 @@ +MODULE_DESCRIPTION("Device driver for BCM2835's secondary memory interface"); +MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>"); diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c -index 94caee49da99..da599f075bc2 100644 +index 32d49100dff5..00cb1f4ceadf 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c -@@ -165,6 +165,13 @@ static DEFINE_MUTEX(open_lock); +@@ -171,6 +171,13 @@ static DEFINE_MUTEX(open_lock); module_param(perdev_minors, int, 0444); MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device"); @@ -86576,15 +137626,78 @@ 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, -@@ -2897,6 +2904,7 @@ static int mmc_blk_probe(struct mmc_card *card) +@@ -880,6 +887,10 @@ static int mmc_blk_part_switch_pre(struct mmc_card *card, + if ((part_type & mask) == mask) { + if (card->ext_csd.cmdq_en) { + ret = mmc_cmdq_disable(card); ++ if (mmc_card_sd(card)) ++ ret = mmc_sd_cmdq_disable(card); ++ else ++ ret = mmc_cmdq_disable(card); + if (ret) + return ret; + } +@@ -897,8 +908,12 @@ static int mmc_blk_part_switch_post(struct mmc_card *card, + + if ((part_type & mask) == mask) { + mmc_retune_unpause(card->host); +- if (card->reenable_cmdq && !card->ext_csd.cmdq_en) +- ret = mmc_cmdq_enable(card); ++ if (card->reenable_cmdq && !card->ext_csd.cmdq_en) { ++ if (mmc_card_sd(card)) ++ ret = mmc_sd_cmdq_enable(card); ++ else ++ ret = mmc_cmdq_enable(card); ++ } + } + + return ret; +@@ -1094,7 +1109,10 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) + switch (mq_rq->drv_op) { + case MMC_DRV_OP_IOCTL: + if (card->ext_csd.cmdq_en) { +- ret = mmc_cmdq_disable(card); ++ if (mmc_card_sd(card)) ++ ret = mmc_sd_cmdq_disable(card); ++ else ++ ret = mmc_cmdq_disable(card); + if (ret) + break; + } +@@ -1112,8 +1130,12 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) + /* Always switch back to main area after RPMB access */ + if (rpmb_ioctl) + mmc_blk_part_switch(card, 0); +- else if (card->reenable_cmdq && !card->ext_csd.cmdq_en) +- mmc_cmdq_enable(card); ++ else if (card->reenable_cmdq && !card->ext_csd.cmdq_en) { ++ if (mmc_card_sd(card)) ++ mmc_sd_cmdq_enable(card); ++ else ++ mmc_cmdq_enable(card); ++ } + break; + case MMC_DRV_OP_BOOT_WP: + ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, +@@ -1940,7 +1962,7 @@ static void mmc_blk_mq_rw_recovery(struct mmc_queue *mq, struct request *req) + return; + } + +- if (rq_data_dir(req) == READ && brq->data.blocks > ++ if (0 && rq_data_dir(req) == READ && brq->data.blocks > + queue_physical_block_size(mq->queue) >> 9) { + /* Read one (native) sector at a time */ + mmc_blk_read_single(mq, req); +@@ -3006,6 +3028,8 @@ static int mmc_blk_probe(struct mmc_card *card) { - struct mmc_blk_data *md, *part_md; - char cap_str10; + struct mmc_blk_data *md; + int ret = 0; + char quirk_str24; ++ char cap_str10; /* * Check that the card supports the command class(es) we need. -@@ -2904,7 +2912,16 @@ static int mmc_blk_probe(struct mmc_card *card) +@@ -3013,7 +3037,16 @@ static int mmc_blk_probe(struct mmc_card *card) if (!(card->csd.cmdclass & CCC_BLOCK_READ)) return -ENODEV; @@ -86602,28 +137715,75 @@ card->complete_wq = alloc_workqueue("mmc_complete", WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); -@@ -2919,9 +2936,14 @@ static int mmc_blk_probe(struct mmc_card *card) +@@ -3028,6 +3061,17 @@ static int mmc_blk_probe(struct mmc_card *card) + goto out_free; + } - 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", ++ string_get_size((u64)get_capacity(md->disk), 512, STRING_UNITS_2, ++ cap_str, sizeof(cap_str)); + if (card->quirks) + snprintf(quirk_str, sizeof(quirk_str), + " (quirks 0x%08x)", card->quirks); + else + quirk_str0 = '\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)" : ""); ++ md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), + cap_str, md->read_only ? " (ro)" : "", quirk_str); - - if (mmc_blk_alloc_parts(card, md)) ++ + ret = mmc_blk_alloc_parts(card, md); + if (ret) goto out; +diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c +index 0af96548e7da..ee6c0fdbb3e9 100644 +--- a/drivers/mmc/core/bus.c ++++ b/drivers/mmc/core/bus.c +@@ -264,6 +264,8 @@ static void mmc_release_card(struct device *dev) + + sdio_free_common_cis(card); + ++ kfree(card->ext_reg_buf); ++ + kfree(card->info); + + kfree(card); +diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h +index b7754a1b8d97..c282b71668bd 100644 +--- a/drivers/mmc/core/card.h ++++ b/drivers/mmc/core/card.h +@@ -84,6 +84,7 @@ struct mmc_fixup { + #define CID_MANFID_TOSHIBA 0x11 + #define CID_MANFID_MICRON 0x13 + #define CID_MANFID_SAMSUNG 0x15 ++#define CID_MANFID_SAMSUNG_SD 0x1b + #define CID_MANFID_APACER 0x27 + #define CID_MANFID_KINGSTON 0x70 + #define CID_MANFID_HYNIX 0x90 diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c -index eb82f6aac951..6870e8bbd2ec 100644 +index a8c17b4cd737..0d59beadecb8 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c -@@ -1874,7 +1874,8 @@ EXPORT_SYMBOL(mmc_erase); +@@ -455,6 +455,7 @@ int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq) + goto out_err; + + trace_mmc_request_start(host, mrq); ++ led_trigger_event(host->led, LED_FULL); + + return 0; + +@@ -556,7 +557,11 @@ int mmc_cqe_recovery(struct mmc_host *host) + mmc_poll_for_busy(host->card, MMC_CQE_RECOVERY_TIMEOUT, true, MMC_BUSY_IO); + + memset(&cmd, 0, sizeof(cmd)); +- cmd.opcode = MMC_CMDQ_TASK_MGMT; ++ if (mmc_card_sd(host->card)) ++ cmd.opcode = SD_CMDQ_TASK_MGMT; ++ else ++ cmd.opcode = MMC_CMDQ_TASK_MGMT; ++ + cmd.arg = 1; /* Discard entire queue */ + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */ +@@ -1818,7 +1823,8 @@ EXPORT_SYMBOL(mmc_erase); int mmc_can_erase(struct mmc_card *card) { @@ -86633,13 +137793,72 @@ return 1; return 0; } +diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c +index 3a927452a650..450683646196 100644 +--- a/drivers/mmc/core/mmc.c ++++ b/drivers/mmc/core/mmc.c +@@ -1910,8 +1910,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, + host->cqe_enabled = true; + + if (card->ext_csd.cmdq_en) { +- pr_info("%s: Command Queue Engine enabled\n", +- mmc_hostname(host)); ++ pr_info("%s: Command Queue Engine enabled, %u tags\n", ++ mmc_hostname(host), card->ext_csd.cmdq_depth); + } else { + host->hsq_enabled = true; + pr_info("%s: Host Software Queue enabled\n", diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h -index d68e6e513a4f..e41bc00ece42 100644 +index cca71867bc4a..ddefedc9746e 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h -@@ -99,6 +99,14 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups = { - MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_TRIM_BROKEN), +@@ -15,6 +15,27 @@ + + #include "card.h" + ++static const struct mmc_fixup __maybe_unused mmc_sd_fixups = { ++ /* ++ * Kingston Canvas Go! Plus microSD cards never finish SD cache flush. ++ * This has so far only been observed on cards from 11/2019, while new ++ * cards from 2023/05 do not exhibit this behavior. ++ */ ++ _FIXUP_EXT("SD64G", CID_MANFID_KINGSTON_SD, 0x5449, 2019, 11, ++ 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd, ++ MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY), ++ ++ /* ++ * Samsung Pro Plus/EVO Plus/Pro Ultimate SD cards (2023) claim to cache ++ * flush OK, but become unresponsive afterwards. ++ */ ++ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_SAMSUNG_SD, 0x534d, 2023, CID_MONTH_ANY, ++ 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd, ++ MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY), ++ ++ END_FIXUP ++}; ++ + static const struct mmc_fixup __maybe_unused mmc_blk_fixups = { + #define INAND_CMD38_ARG_EXT_CSD 113 + #define INAND_CMD38_ARG_ERASE 0x00 +@@ -53,15 +74,6 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups = { + MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_BLK_NO_CMD23), + +- /* +- * Kingston Canvas Go! Plus microSD cards never finish SD cache flush. +- * This has so far only been observed on cards from 11/2019, while new +- * cards from 2023/05 do not exhibit this behavior. +- */ +- _FIXUP_EXT("SD64G", CID_MANFID_KINGSTON_SD, 0x5449, 2019, 11, +- 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd, +- MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY), +- + /* + * Some SD cards lockup while using CMD23 multiblock transfers. + */ +@@ -130,6 +142,14 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups = { + MMC_FIXUP(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, add_quirk_sd, + MMC_QUIRK_BROKEN_SD_DISCARD), + /* + * On some Kingston SD cards, multiple erases of less than 64 @@ -86652,11 +137871,568 @@ END_FIXUP }; +diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c +index c3e554344c99..bd0e14714e39 100644 +--- a/drivers/mmc/core/sd.c ++++ b/drivers/mmc/core/sd.c +@@ -26,6 +26,7 @@ + #include "host.h" + #include "bus.h" + #include "mmc_ops.h" ++#include "quirks.h" + #include "sd.h" + #include "sd_ops.h" + +@@ -714,7 +715,8 @@ MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid); + MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial); + MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr); + MMC_DEV_ATTR(rca, "0x%04x\n", card->rca); +- ++MMC_DEV_ATTR(ext_perf, "%02x\n", card->ext_perf.feature_support); ++MMC_DEV_ATTR(ext_power, "%02x\n", card->ext_power.feature_support); + + static ssize_t mmc_dsr_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -776,6 +778,8 @@ static struct attribute *sd_std_attrs = { + &dev_attr_ocr.attr, + &dev_attr_rca.attr, + &dev_attr_dsr.attr, ++ &dev_attr_ext_perf.attr, ++ &dev_attr_ext_power.attr, + NULL, + }; + +@@ -1015,98 +1019,16 @@ static bool mmc_sd_card_using_v18(struct mmc_card *card) + (SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50); + } + +-static int sd_write_ext_reg(struct mmc_card *card, u8 fno, u8 page, u16 offset, +- u8 reg_data) +-{ +- struct mmc_host *host = card->host; +- struct mmc_request mrq = {}; +- struct mmc_command cmd = {}; +- struct mmc_data data = {}; +- struct scatterlist sg; +- u8 *reg_buf; +- +- reg_buf = kzalloc(512, GFP_KERNEL); +- if (!reg_buf) +- return -ENOMEM; +- +- mrq.cmd = &cmd; +- mrq.data = &data; +- +- /* +- * Arguments of CMD49: +- * 31:31 MIO (0 = memory). +- * 30:27 FNO (function number). +- * 26:26 MW - mask write mode (0 = disable). +- * 25:18 page number. +- * 17:9 offset address. +- * 8:0 length (0 = 1 byte). +- */ +- cmd.arg = fno << 27 | page << 18 | offset << 9; +- +- /* The first byte in the buffer is the data to be written. */ +- reg_buf0 = reg_data; +- +- data.flags = MMC_DATA_WRITE; +- data.blksz = 512; +- data.blocks = 1; +- data.sg = &sg; +- data.sg_len = 1; +- sg_init_one(&sg, reg_buf, 512); +- +- cmd.opcode = SD_WRITE_EXTR_SINGLE; +- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; +- +- mmc_set_data_timeout(&data, card); +- mmc_wait_for_req(host, &mrq); +- +- kfree(reg_buf); +- +- /* +- * Note that, the SD card is allowed to signal busy on DAT0 up to 1s +- * after the CMD49. Although, let's leave this to be managed by the +- * caller. +- */ +- +- if (cmd.error) +- return cmd.error; +- if (data.error) +- return data.error; +- +- return 0; +-} +- +-static int sd_read_ext_reg(struct mmc_card *card, u8 fno, u8 page, +- u16 offset, u16 len, u8 *reg_buf) +-{ +- u32 cmd_args; +- +- /* +- * Command arguments of CMD48: +- * 31:31 MIO (0 = memory). +- * 30:27 FNO (function number). +- * 26:26 reserved (0). +- * 25:18 page number. +- * 17:9 offset address. +- * 8:0 length (0 = 1 byte, 1ff = 512 bytes). +- */ +- cmd_args = fno << 27 | page << 18 | offset << 9 | (len -1); +- +- return mmc_send_adtc_data(card, card->host, SD_READ_EXTR_SINGLE, +- cmd_args, reg_buf, 512); +-} +- + static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page, + u16 offset) + { + int err; + u8 *reg_buf; + +- reg_buf = kzalloc(512, GFP_KERNEL); +- if (!reg_buf) +- return -ENOMEM; ++ reg_buf = card->ext_reg_buf; + + /* Read the extension register for power management function. */ +- err = sd_read_ext_reg(card, fno, page, offset, 512, reg_buf); ++ err = mmc_sd_read_ext_reg(card, fno, page, offset, 512, reg_buf); + if (err) { + pr_warn("%s: error %d reading PM func of ext reg\n", + mmc_hostname(card->host), err); +@@ -1133,7 +1055,6 @@ static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page, + card->ext_power.offset = offset; + + out: +- kfree(reg_buf); + return err; + } + +@@ -1143,11 +1064,9 @@ static int sd_parse_ext_reg_perf(struct mmc_card *card, u8 fno, u8 page, + int err; + u8 *reg_buf; + +- reg_buf = kzalloc(512, GFP_KERNEL); +- if (!reg_buf) +- return -ENOMEM; ++ reg_buf = card->ext_reg_buf; + +- err = sd_read_ext_reg(card, fno, page, offset, 512, reg_buf); ++ err = mmc_sd_read_ext_reg(card, fno, page, offset, 512, reg_buf); + if (err) { + pr_warn("%s: error %d reading PERF func of ext reg\n", + mmc_hostname(card->host), err); +@@ -1173,16 +1092,25 @@ static int sd_parse_ext_reg_perf(struct mmc_card *card, u8 fno, u8 page, + if ((reg_buf4 & BIT(0)) && !mmc_card_broken_sd_cache(card)) + card->ext_perf.feature_support |= SD_EXT_PERF_CACHE; + +- /* Command queue support indicated via queue depth bits (0 to 4). */ +- if (reg_buf6 & 0x1f) ++ /* ++ * Command queue support indicated via queue depth bits (0 to 4). ++ * Qualify this with the other mandatory required features. ++ */ ++ if (reg_buf6 & 0x1f && card->ext_power.feature_support & SD_EXT_POWER_OFF_NOTIFY && ++ card->ext_perf.feature_support & SD_EXT_PERF_CACHE) { + card->ext_perf.feature_support |= SD_EXT_PERF_CMD_QUEUE; ++ card->ext_csd.cmdq_depth = reg_buf6 & 0x1f; ++ card->ext_csd.cmdq_support = true; ++ pr_debug("%s: Command Queue supported depth %u\n", ++ mmc_hostname(card->host), ++ card->ext_csd.cmdq_depth); ++ } + + card->ext_perf.fno = fno; + card->ext_perf.page = page; + card->ext_perf.offset = offset; + + out: +- kfree(reg_buf); + return err; + } + +@@ -1237,7 +1165,7 @@ static int sd_parse_ext_reg(struct mmc_card *card, u8 *gen_info_buf, + return 0; + } + +-static int sd_read_ext_regs(struct mmc_card *card) ++static int mmc_sd_read_ext_regs(struct mmc_card *card) + { + int err, i; + u8 num_ext, *gen_info_buf; +@@ -1249,15 +1177,21 @@ static int sd_read_ext_regs(struct mmc_card *card) + if (!(card->scr.cmds & SD_SCR_CMD48_SUPPORT)) + return 0; + +- gen_info_buf = kzalloc(512, GFP_KERNEL); ++ gen_info_buf = kzalloc(1024, GFP_KERNEL); + if (!gen_info_buf) + return -ENOMEM; + ++ card->ext_reg_buf = kzalloc(512, GFP_KERNEL); ++ if (!card->ext_reg_buf) { ++ err = -ENOMEM; ++ goto out; ++ } ++ + /* + * Read 512 bytes of general info, which is found at function number 0, + * at page 0 and with no offset. + */ +- err = sd_read_ext_reg(card, 0, 0, 0, 512, gen_info_buf); ++ err = mmc_sd_read_ext_reg(card, 0, 0, 0, 512, gen_info_buf); + if (err) { + pr_err("%s: error %d reading general info of SD ext reg\n", + mmc_hostname(card->host), err); +@@ -1274,14 +1208,23 @@ static int sd_read_ext_regs(struct mmc_card *card) + num_ext = gen_info_buf4; + + /* +- * We only support revision 0 and limit it to 512 bytes for simplicity. ++ * We only support revision 0 and up to the spec-defined maximum of 1K. + * No matter what, let's return zero to allow us to continue using the + * card, even if we can't support the features from the SD function + * extensions registers. + */ +- if (rev != 0 || len > 512) { +- pr_warn("%s: non-supported SD ext reg layout\n", +- mmc_hostname(card->host)); ++ if (rev != 0 || len > 1024) { ++ pr_warn("%s: non-supported SD ext reg layout rev %u length %u\n", ++ mmc_hostname(card->host), rev, len); ++ goto out; ++ } ++ ++ /* If the General Information block spills into the next page, read the rest */ ++ if (len > 512) ++ err = mmc_sd_read_ext_reg(card, 0, 1, 0, 512, &gen_info_buf512); ++ if (err) { ++ pr_err("%s: error %d reading page 1 of general info of SD ext reg\n", ++ mmc_hostname(card->host), err); + goto out; + } + +@@ -1319,9 +1262,7 @@ static int sd_flush_cache(struct mmc_host *host) + if (!sd_cache_enabled(host)) + return 0; + +- reg_buf = kzalloc(512, GFP_KERNEL); +- if (!reg_buf) +- return -ENOMEM; ++ reg_buf = card->ext_reg_buf; + + /* + * Set Flush Cache at bit 0 in the performance enhancement register at +@@ -1331,7 +1272,7 @@ static int sd_flush_cache(struct mmc_host *host) + page = card->ext_perf.page; + offset = card->ext_perf.offset + 261; + +- err = sd_write_ext_reg(card, fno, page, offset, BIT(0)); ++ err = mmc_sd_write_ext_reg(card, fno, page, offset, BIT(0)); + if (err) { + pr_warn("%s: error %d writing Cache Flush bit\n", + mmc_hostname(host), err); +@@ -1347,7 +1288,7 @@ static int sd_flush_cache(struct mmc_host *host) + * Read the Flush Cache bit. The card shall reset it, to confirm that + * it's has completed the flushing of the cache. + */ +- err = sd_read_ext_reg(card, fno, page, offset, 1, reg_buf); ++ err = mmc_sd_read_ext_reg(card, fno, page, offset, 1, reg_buf); + if (err) { + pr_warn("%s: error %d reading Cache Flush bit\n", + mmc_hostname(host), err); +@@ -1357,26 +1298,20 @@ static int sd_flush_cache(struct mmc_host *host) + if (reg_buf0 & BIT(0)) + err = -ETIMEDOUT; + out: +- kfree(reg_buf); + return err; + } + + static int sd_enable_cache(struct mmc_card *card) + { +- u8 *reg_buf; + int err; + + card->ext_perf.feature_enabled &= ~SD_EXT_PERF_CACHE; + +- reg_buf = kzalloc(512, GFP_KERNEL); +- if (!reg_buf) +- return -ENOMEM; +- + /* + * Set Cache Enable at bit 0 in the performance enhancement register at + * 260 bytes offset. + */ +- err = sd_write_ext_reg(card, card->ext_perf.fno, card->ext_perf.page, ++ err = mmc_sd_write_ext_reg(card, card->ext_perf.fno, card->ext_perf.page, + card->ext_perf.offset + 260, BIT(0)); + if (err) { + pr_warn("%s: error %d writing Cache Enable bit\n", +@@ -1390,7 +1325,6 @@ static int sd_enable_cache(struct mmc_card *card) + card->ext_perf.feature_enabled |= SD_EXT_PERF_CACHE; + + out: +- kfree(reg_buf); + return err; + } + +@@ -1475,6 +1409,9 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, + goto free_card; + } + ++ /* Apply quirks prior to card setup */ ++ mmc_fixup_device(card, mmc_sd_fixups); ++ + err = mmc_sd_setup_card(host, card, oldcard != NULL); + if (err) + goto free_card; +@@ -1547,7 +1484,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, + cont: + if (!oldcard) { + /* Read/parse the extension registers. */ +- err = sd_read_ext_regs(card); ++ err = mmc_sd_read_ext_regs(card); + if (err) + goto free_card; + } +@@ -1559,13 +1496,41 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, + goto free_card; + } + ++ /* Enable command queueing if supported */ ++ if (card->ext_csd.cmdq_support && host->caps2 & MMC_CAP2_CQE) { ++ /* ++ * Right now the MMC block layer uses DCMDs to issue ++ * cache-flush commands specific to eMMC devices. ++ * Turning off DCMD support avoids generating Illegal Command ++ * errors on SD, and flushing is instead done synchronously ++ * by mmc_blk_issue_flush(). ++ */ ++ host->caps2 &= ~MMC_CAP2_CQE_DCMD; ++ err = mmc_sd_cmdq_enable(card); ++ if (err && err != -EBADMSG) ++ goto free_card; ++ if (err) { ++ pr_warn("%s: Enabling CMDQ failed\n", ++ mmc_hostname(card->host)); ++ card->ext_csd.cmdq_support = false; ++ card->ext_csd.cmdq_depth = 0; ++ } ++ } ++ card->reenable_cmdq = card->ext_csd.cmdq_en; ++ + if (host->cqe_ops && !host->cqe_enabled) { + err = host->cqe_ops->cqe_enable(host, card); + if (!err) { + host->cqe_enabled = true; +- host->hsq_enabled = true; +- pr_info("%s: Host Software Queue enabled\n", +- mmc_hostname(host)); ++ ++ if (card->ext_csd.cmdq_en) { ++ pr_info("%s: Command Queue Engine enabled, %u tags\n", ++ mmc_hostname(host), card->ext_csd.cmdq_depth); ++ } else { ++ host->hsq_enabled = true; ++ pr_info("%s: Host Software Queue enabled\n", ++ mmc_hostname(host)); ++ } + } + } + +@@ -1646,7 +1611,7 @@ static int sd_busy_poweroff_notify_cb(void *cb_data, bool *busy) + * one byte offset and is one byte long. The Power Off Notification + * Ready is bit 0. + */ +- err = sd_read_ext_reg(card, card->ext_power.fno, card->ext_power.page, ++ err = mmc_sd_read_ext_reg(card, card->ext_power.fno, card->ext_power.page, + card->ext_power.offset + 1, 1, data->reg_buf); + if (err) { + pr_warn("%s: error %d reading status reg of PM func\n", +@@ -1672,7 +1637,7 @@ static int sd_poweroff_notify(struct mmc_card *card) + * Set the Power Off Notification bit in the power management settings + * register at 2 bytes offset. + */ +- err = sd_write_ext_reg(card, card->ext_power.fno, card->ext_power.page, ++ err = mmc_sd_write_ext_reg(card, card->ext_power.fno, card->ext_power.page, + card->ext_power.offset + 2, BIT(0)); + if (err) { + pr_warn("%s: error %d writing Power Off Notify bit\n", +diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c +index a59cd592f06e..4371112537fb 100644 +--- a/drivers/mmc/core/sd_ops.c ++++ b/drivers/mmc/core/sd_ops.c +@@ -8,6 +8,7 @@ + #include <linux/slab.h> + #include <linux/types.h> + #include <linux/export.h> ++#include <linux/ktime.h> + #include <linux/scatterlist.h> + + #include <linux/mmc/host.h> +@@ -365,3 +366,136 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr) + + return 0; + } ++ ++ ++int mmc_sd_write_ext_reg(struct mmc_card *card, u8 fno, u8 page, u16 offset, ++ u8 reg_data) ++{ ++ struct mmc_host *host = card->host; ++ struct mmc_request mrq = {}; ++ struct mmc_command cmd = {}; ++ struct mmc_data data = {}; ++ struct scatterlist sg; ++ u8 *reg_buf; ++ ++ reg_buf = card->ext_reg_buf; ++ memset(reg_buf, 0, 512); ++ ++ mrq.cmd = &cmd; ++ mrq.data = &data; ++ ++ /* ++ * Arguments of CMD49: ++ * 31:31 MIO (0 = memory). ++ * 30:27 FNO (function number). ++ * 26:26 MW - mask write mode (0 = disable). ++ * 25:18 page number. ++ * 17:9 offset address. ++ * 8:0 length (0 = 1 byte). ++ */ ++ cmd.arg = fno << 27 | page << 18 | offset << 9; ++ ++ /* The first byte in the buffer is the data to be written. */ ++ reg_buf0 = reg_data; ++ ++ data.flags = MMC_DATA_WRITE; ++ data.blksz = 512; ++ data.blocks = 1; ++ data.sg = &sg; ++ data.sg_len = 1; ++ sg_init_one(&sg, reg_buf, 512); ++ ++ cmd.opcode = SD_WRITE_EXTR_SINGLE; ++ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; ++ ++ mmc_set_data_timeout(&data, card); ++ mmc_wait_for_req(host, &mrq); ++ ++ /* ++ * Note that, the SD card is allowed to signal busy on DAT0 up to 1s ++ * after the CMD49. Although, let's leave this to be managed by the ++ * caller. ++ */ ++ ++ if (cmd.error) ++ return cmd.error; ++ if (data.error) ++ return data.error; ++ ++ return 0; ++} ++ ++int mmc_sd_read_ext_reg(struct mmc_card *card, u8 fno, u8 page, ++ u16 offset, u16 len, u8 *reg_buf) ++{ ++ u32 cmd_args; ++ ++ /* ++ * Command arguments of CMD48: ++ * 31:31 MIO (0 = memory). ++ * 30:27 FNO (function number). ++ * 26:26 reserved (0). ++ * 25:18 page number. ++ * 17:9 offset address. ++ * 8:0 length (0 = 1 byte, 1ff = 512 bytes). ++ */ ++ cmd_args = fno << 27 | page << 18 | offset << 9 | (len - 1); ++ ++ return mmc_send_adtc_data(card, card->host, SD_READ_EXTR_SINGLE, ++ cmd_args, reg_buf, 512); ++} ++ ++static int mmc_sd_cmdq_switch(struct mmc_card *card, bool enable) ++{ ++ int err; ++ u8 reg = 0; ++ u8 *reg_buf = card->ext_reg_buf; ++ ktime_t timeout; ++ /* ++ * SD offers two command queueing modes - sequential (in-order) and ++ * voluntary (out-of-order). Apps Class A2 performance is only ++ * guaranteed for voluntary CQ (bit 1 = 0), so use that in preference ++ * to sequential. ++ */ ++ if (enable) ++ reg = BIT(0); ++ ++ /* Performance enhancement register byte 262 controls command queueing */ ++ err = mmc_sd_write_ext_reg(card, card->ext_perf.fno, card->ext_perf.page, ++ card->ext_perf.offset + 262, reg); ++ if (err) ++ goto out; ++ ++ /* Poll the register - cards may have a lazy init/deinit sequence. */ ++ timeout = ktime_add_ms(ktime_get(), 10); ++ while (1) { ++ err = mmc_sd_read_ext_reg(card, card->ext_perf.fno, card->ext_perf.page, ++ card->ext_perf.offset + 262, 1, reg_buf); ++ if (err) ++ break; ++ if ((reg_buf0 & BIT(0)) == reg) ++ break; ++ if (ktime_after(ktime_get(), timeout)) { ++ err = -EBADMSG; ++ break; ++ } ++ usleep_range(100, 200); ++ } ++out: ++ if (!err) ++ card->ext_csd.cmdq_en = enable; ++ ++ return err; ++} ++ ++int mmc_sd_cmdq_enable(struct mmc_card *card) ++{ ++ return mmc_sd_cmdq_switch(card, true); ++} ++EXPORT_SYMBOL_GPL(mmc_sd_cmdq_enable); ++ ++int mmc_sd_cmdq_disable(struct mmc_card *card) ++{ ++ return mmc_sd_cmdq_switch(card, false); ++} ++EXPORT_SYMBOL_GPL(mmc_sd_cmdq_disable); +diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h +index 7667fc223b74..1b8138368a81 100644 +--- a/drivers/mmc/core/sd_ops.h ++++ b/drivers/mmc/core/sd_ops.h +@@ -21,6 +21,12 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca); + int mmc_app_send_scr(struct mmc_card *card); + int mmc_app_sd_status(struct mmc_card *card, void *ssr); + int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card); ++int mmc_sd_cmdq_enable(struct mmc_card *card); ++int mmc_sd_cmdq_disable(struct mmc_card *card); ++int mmc_sd_write_ext_reg(struct mmc_card *card, u8 fno, u8 page, u16 offset, ++ u8 reg_data); ++int mmc_sd_read_ext_reg(struct mmc_card *card, u8 fno, u8 page, ++ u16 offset, u16 len, u8 *reg_buf); + + #endif + diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig -index 30ff42fd173e..c077890df8ab 100644 +index bc7e2ad37002..0c457ca28998 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig -@@ -5,6 +5,45 @@ +@@ -5,6 +5,46 @@ comment "MMC/SD/SDIO Host Controller Drivers" @@ -86692,6 +138468,7 @@ +config MMC_BCM2835_SDHOST + tristate "Support for the SDHost controller on BCM2708/9" + depends on ARCH_BCM2835 ++ select MMC_HSQ + help + This selects the SDHost controller on BCM2835/6. + @@ -86702,11 +138479,19 @@ config MMC_DEBUG bool "MMC host drivers debugging" depends on MMC != n +@@ -1001,6 +1041,7 @@ config MMC_SDHCI_BRCMSTB + depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST + depends on MMC_SDHCI_PLTFM + select MMC_CQHCI ++ select OF_DYNAMIC + default ARCH_BRCMSTB || BMIPS_GENERIC + help + This selects support for the SDIO/SD/MMC Host Controller on diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile -index 451c25fc2c69..ecf787b7e277 100644 +index a693fa3d3f1c..23aa2d13ef70 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile -@@ -24,6 +24,8 @@ obj-$(CONFIG_MMC_SDHCI_F_SDH30) += sdhci_f_sdh30.o +@@ -22,6 +22,8 @@ obj-$(CONFIG_MMC_SDHCI_F_SDH30) += sdhci_f_sdh30.o obj-$(CONFIG_MMC_SDHCI_MILBEAUT) += sdhci-milbeaut.o obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o obj-$(CONFIG_MMC_SDHCI_AM654) += sdhci_am654.o @@ -86717,10 +138502,10 @@ obj-$(CONFIG_MMC_ALCOR) += alcor.o diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c new file mode 100644 -index 000000000000..cdc1318e5936 +index 000000000000..fc9f7886eb21 --- /dev/null +++ b/drivers/mmc/host/bcm2835-mmc.c -@@ -0,0 +1,1576 @@ +@@ -0,0 +1,1562 @@ +/* + * BCM2835 MMC host driver. + * @@ -88044,7 +139829,6 @@ + + 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 */ + @@ -88079,10 +139863,7 @@ + } +#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_req_size = min_t(size_t, 524288, dma_max_mapping_size(dev)); + mmc->max_seg_size = mmc->max_req_size; + mmc->max_blk_size = 512; + mmc->max_blk_count = 65535; @@ -88128,7 +139909,6 @@ + struct resource *iomem; + struct bcm2835_host *host; + struct mmc_host *mmc; -+ const __be32 *addr; + int ret; + + mmc = mmc_alloc_host(sizeof(*host), dev); @@ -88141,24 +139921,13 @@ + 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); ++ host->ioaddr = devm_platform_get_and_ioremap_resource(pdev, 0, &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); ++ host->bus_addr = iomem->start; + +#ifndef FORCE_PIO + if (node) { @@ -88198,7 +139967,9 @@ + } + + if (node) { -+ mmc_of_parse(mmc); ++ ret = mmc_of_parse(mmc); ++ if (ret) ++ goto err; + + /* Read any custom properties */ + of_property_read_u32(node, @@ -88299,10 +140070,10 @@ +MODULE_AUTHOR("Gellert Weisz"); diff --git a/drivers/mmc/host/bcm2835-sdhost.c b/drivers/mmc/host/bcm2835-sdhost.c new file mode 100644 -index 000000000000..2c4124082785 +index 000000000000..8e95a9df2f88 --- /dev/null +++ b/drivers/mmc/host/bcm2835-sdhost.c -@@ -0,0 +1,2208 @@ +@@ -0,0 +1,2220 @@ +/* + * BCM2835 SD host driver. + * @@ -88362,6 +140133,7 @@ + +/* For mmc_card_blockaddr */ +#include "../core/card.h" ++#include "mmc_hsq.h" + +#define DRIVER_NAME "sdhost-bcm2835" + @@ -88547,20 +140319,27 @@ +#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) ++static void log_init(struct device *dev) +{ ++ struct device_node *np; ++ + 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"); ++ ++ np = of_find_compatible_node(NULL, NULL, ++ "brcm,bcm2835-system-timer"); ++ timer_base = of_iomap(np, 0); ++ ++ if (timer_base) { ++ 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); ++ else ++ pr_err("sdhost: failed to allocate log buf\n"); ++ } else { ++ pr_err("sdhost: failed to remap timer - wrong dtb?\n"); + } -+ else -+ pr_err("sdhost: failed to allocate log buf\n"); +} + +static void log_event_impl(const char *event, u32 param1, u32 param2) @@ -88750,6 +140529,7 @@ + bcm2835_sdhost_write(host, SDCDIV_MAX_CDIV, SDCDIV); +} + ++#if 0 // todo fix +static void bcm2835_sdhost_reset(struct mmc_host *mmc) +{ + struct bcm2835_host *host = mmc_priv(mmc); @@ -88761,6 +140541,7 @@ + + spin_unlock_irqrestore(&host->lock, flags); +} ++#endif + +static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); + @@ -90081,7 +141862,7 @@ +static struct mmc_host_ops bcm2835_sdhost_ops = { + .request = bcm2835_sdhost_request, + .set_ios = bcm2835_sdhost_set_ios, -+ .hw_reset = bcm2835_sdhost_reset, ++// todo:fix .hw_reset = bcm2835_sdhost_reset, +}; + +static void bcm2835_sdhost_cmd_wait_work(struct work_struct *work) @@ -90187,13 +141968,16 @@ + mmc_hostname(host->mmc)); + } + -+ mmc_request_done(host->mmc, mrq); ++ if (!mmc_hsq_finalize_request(host->mmc, mrq)) ++ mmc_request_done(host->mmc, mrq); + log_event("TSK>", mrq, 0); +} + -+int bcm2835_sdhost_add_host(struct bcm2835_host *host) ++int bcm2835_sdhost_add_host(struct platform_device *pdev) +{ ++ struct bcm2835_host *host = platform_get_drvdata(pdev); + struct mmc_host *mmc; ++ struct mmc_hsq *hsq; + struct dma_slave_config cfg; + char pio_limit_string20; + int ret; @@ -90226,7 +142010,6 @@ + } 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 */ + @@ -90289,6 +142072,16 @@ + goto untasklet; + } + ++ hsq = devm_kzalloc(&pdev->dev, sizeof(*hsq), GFP_KERNEL); ++ if (!hsq) { ++ ret = -ENOMEM; ++ goto free_irq; ++ } ++ ++ ret = mmc_hsq_init(hsq, host->mmc); ++ if (ret) ++ goto free_irq; ++ + mmc_add_host(mmc); + + pio_limit_string0 = '\0'; @@ -90301,6 +142094,9 @@ + + return 0; + ++free_irq: ++ free_irq(host->irq, host); ++ +untasklet: + tasklet_kill(&host->finish_tasklet); + @@ -90315,9 +142111,7 @@ + struct resource *iomem; + struct bcm2835_host *host; + struct mmc_host *mmc; -+ const __be32 *addr; + u32 msg3; -+ int na; + int ret; + + pr_debug("bcm2835_sdhost_probe\n"); @@ -90334,24 +142128,13 @@ + host->allow_dma = 1; + spin_lock_init(&host->lock); + -+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ host->ioaddr = devm_ioremap_resource(dev, iomem); ++ host->ioaddr = devm_platform_get_and_ioremap_resource(pdev, 0, &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); ++ host->bus_addr = iomem->start; + + if (node) { + /* Read any custom properties */ @@ -90427,7 +142210,7 @@ + (unsigned long)host->max_clk, + (int)host->irq); + -+ log_init(dev, iomem->start - host->bus_addr); ++ log_init(dev); + + if (node) + mmc_of_parse(mmc); @@ -90444,12 +142227,12 @@ + + host->firmware_sets_cdiv = (msg1 != ~0); + -+ ret = bcm2835_sdhost_add_host(host); ++ platform_set_drvdata(pdev, host); ++ ++ ret = bcm2835_sdhost_add_host(pdev); + if (ret) + goto err; + -+ platform_set_drvdata(pdev, host); -+ + pr_debug("bcm2835_sdhost_probe -> OK\n"); + + return 0; @@ -90511,11 +142294,505 @@ +MODULE_DESCRIPTION("BCM2835 SDHost driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Phil Elwell"); +diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c +index 35d8fdea668b..746a60fac0f0 100644 +--- a/drivers/mmc/host/bcm2835.c ++++ b/drivers/mmc/host/bcm2835.c +@@ -38,7 +38,6 @@ + #include <linux/io.h> + #include <linux/iopoll.h> + #include <linux/module.h> +-#include <linux/of_address.h> + #include <linux/of_irq.h> + #include <linux/platform_device.h> + #include <linux/scatterlist.h> +@@ -1347,8 +1346,8 @@ static int bcm2835_probe(struct platform_device *pdev) + struct device *dev = &pdev->dev; + struct clk *clk; + struct bcm2835_host *host; ++ struct resource *iomem; + struct mmc_host *mmc; +- const __be32 *regaddr_p; + int ret; + + dev_dbg(dev, "%s\n", __func__); +@@ -1361,23 +1360,13 @@ static int bcm2835_probe(struct platform_device *pdev) + host->pdev = pdev; + spin_lock_init(&host->lock); + +- host->ioaddr = devm_platform_ioremap_resource(pdev, 0); ++ host->ioaddr = devm_platform_get_and_ioremap_resource(pdev, 0, &iomem); + if (IS_ERR(host->ioaddr)) { + ret = PTR_ERR(host->ioaddr); + goto err; + } + +- /* Parse OF address directly to get the physical address for +- * DMA to our registers. +- */ +- regaddr_p = of_get_address(pdev->dev.of_node, 0, NULL, NULL); +- if (!regaddr_p) { +- dev_err(dev, "Can't get phys address\n"); +- ret = -EINVAL; +- goto err; +- } +- +- host->phys_addr = be32_to_cpup(regaddr_p); ++ host->phys_addr = iomem->start; + + host->dma_chan = NULL; + host->dma_desc = NULL; +diff --git a/drivers/mmc/host/cqhci-core.c b/drivers/mmc/host/cqhci-core.c +index 41e94cd14109..5da5bf8ad038 100644 +--- a/drivers/mmc/host/cqhci-core.c ++++ b/drivers/mmc/host/cqhci-core.c +@@ -383,9 +383,11 @@ static void cqhci_off(struct mmc_host *mmc) + + err = readx_poll_timeout(cqhci_read_ctl, cq_host, reg, + reg & CQHCI_HALT, 0, CQHCI_OFF_TIMEOUT); +- if (err < 0) ++ if (err < 0) { + pr_err("%s: cqhci: CQE stuck on\n", mmc_hostname(mmc)); +- else ++ /* eMMC v5.1 B.2.8 recommends writing 0 to CQHCI_CTL if stuck */ ++ cqhci_writel(cq_host, 0, CQHCI_CTL); ++ } else + pr_debug("%s: cqhci: CQE off\n", mmc_hostname(mmc)); + + if (cq_host->ops->post_disable) +@@ -612,7 +614,7 @@ static int cqhci_request(struct mmc_host *mmc, struct mmc_request *mrq) + cqhci_writel(cq_host, 0, CQHCI_CTL); + mmc->cqe_on = true; + pr_debug("%s: cqhci: CQE on\n", mmc_hostname(mmc)); +- if (cqhci_readl(cq_host, CQHCI_CTL) && CQHCI_HALT) { ++ if (cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT) { + pr_err("%s: cqhci: CQE failed to exit halt state\n", + mmc_hostname(mmc)); + } +@@ -975,8 +977,11 @@ static bool cqhci_halt(struct mmc_host *mmc, unsigned int timeout) + + ret = cqhci_halted(cq_host); + +- if (!ret) ++ if (!ret) { + pr_warn("%s: cqhci: Failed to halt\n", mmc_hostname(mmc)); ++ /* eMMC v5.1 B.2.8 recommends writing 0 to CQHCI_CTL if stuck */ ++ cqhci_writel(cq_host, 0, CQHCI_CTL); ++ } + + return ret; + } +diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c +index c23251bb95f3..61cea31cc891 100644 +--- a/drivers/mmc/host/sdhci-brcmstb.c ++++ b/drivers/mmc/host/sdhci-brcmstb.c +@@ -11,6 +11,8 @@ + #include <linux/of.h> + #include <linux/bitops.h> + #include <linux/delay.h> ++#include <linux/pinctrl/consumer.h> ++#include <linux/regulator/consumer.h> + + #include "sdhci-cqhci.h" + #include "sdhci-pltfm.h" +@@ -26,18 +28,43 @@ + + #define BRCMSTB_PRIV_FLAGS_HAS_CQE BIT(0) + #define BRCMSTB_PRIV_FLAGS_GATE_CLOCK BIT(1) ++#define BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS BIT(2) + + #define SDHCI_ARASAN_CQE_BASE_ADDR 0x200 + ++#define SDIO_CFG_CTRL 0x0 ++#define SDIO_CFG_CTRL_SDCD_N_TEST_EN BIT(31) ++#define SDIO_CFG_CTRL_SDCD_N_TEST_LEV BIT(30) ++ ++#define SDIO_CFG_SD_PIN_SEL 0x44 ++#define SDIO_CFG_SD_PIN_SEL_MASK 0x3 ++#define SDIO_CFG_SD_PIN_SEL_SD BIT(1) ++#define SDIO_CFG_SD_PIN_SEL_MMC BIT(0) ++ ++#define SDIO_CFG_CQ_CAPABILITY 0x4c ++#define SDIO_CFG_CQ_CAPABILITY_FMUL_SHIFT 12 ++ ++#define SDIO_CFG_MAX_50MHZ_MODE 0x1ac ++#define SDIO_CFG_MAX_50MHZ_MODE_STRAP_OVERRIDE BIT(31) ++#define SDIO_CFG_MAX_50MHZ_MODE_ENABLE BIT(0) ++ + struct sdhci_brcmstb_priv { + void __iomem *cfg_regs; + unsigned int flags; + struct clk *base_clk; + u32 base_freq_hz; ++ struct regulator *sde_1v8; ++ struct device_node *sde_pcie; ++ void *__iomem sde_ioaddr; ++ void *__iomem sde_ioaddr2; ++ struct pinctrl *pinctrl; ++ struct pinctrl_state *pins_default; ++ struct pinctrl_state *pins_sdex; + }; + + struct brcmstb_match_priv { + void (*hs400es)(struct mmc_host *mmc, struct mmc_ios *ios); ++ void (*cfginit)(struct sdhci_host *host); + struct sdhci_ops *ops; + const unsigned int flags; + }; +@@ -79,6 +106,42 @@ static void sdhci_brcmstb_hs400es(struct mmc_host *mmc, struct mmc_ios *ios) + writel(reg, host->ioaddr + SDHCI_VENDOR); + } + ++static void sdhci_bcm2712_set_clock(struct sdhci_host *host, unsigned int clock) ++{ ++ u16 clk; ++ u32 reg; ++ bool is_emmc_rate = false; ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host); ++ ++ host->mmc->actual_clock = 0; ++ ++ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); ++ ++ switch (host->mmc->ios.timing) { ++ case MMC_TIMING_MMC_HS400: ++ case MMC_TIMING_MMC_HS200: ++ case MMC_TIMING_MMC_DDR52: ++ case MMC_TIMING_MMC_HS: ++ is_emmc_rate = true; ++ break; ++ } ++ ++ reg = readl(brcmstb_priv->cfg_regs + SDIO_CFG_SD_PIN_SEL); ++ reg &= ~SDIO_CFG_SD_PIN_SEL_MASK; ++ if (is_emmc_rate) ++ reg |= SDIO_CFG_SD_PIN_SEL_MMC; ++ else ++ reg |= SDIO_CFG_SD_PIN_SEL_SD; ++ writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_SD_PIN_SEL); ++ ++ if (clock == 0) ++ return; ++ ++ clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); ++ sdhci_enable_clk(host, clk); ++} ++ + static void sdhci_brcmstb_set_clock(struct sdhci_host *host, unsigned int clock) + { + u16 clk; +@@ -94,6 +157,17 @@ static void sdhci_brcmstb_set_clock(struct sdhci_host *host, unsigned int clock) + sdhci_enable_clk(host, clk); + } + ++static void sdhci_brcmstb_set_power(struct sdhci_host *host, unsigned char mode, ++ unsigned short vdd) ++{ ++ if (!IS_ERR(host->mmc->supply.vmmc)) { ++ struct mmc_host *mmc = host->mmc; ++ ++ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); ++ } ++ sdhci_set_power_noreg(host, mode, vdd); ++} ++ + static void sdhci_brcmstb_set_uhs_signaling(struct sdhci_host *host, + unsigned int timing) + { +@@ -123,6 +197,139 @@ static void sdhci_brcmstb_set_uhs_signaling(struct sdhci_host *host, + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); + } + ++static void sdhci_brcmstb_cfginit_2712(struct sdhci_host *host) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host); ++ u32 uhs_mask = (MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104); ++ u32 hsemmc_mask = (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS200_1_2V_SDR | ++ MMC_CAP2_HS400_1_8V | MMC_CAP2_HS400_1_2V); ++ u32 reg, base_clk_mhz; ++ ++ /* ++ * If we support a speed that requires tuning, ++ * then select the delay line PHY as the clock source. ++ */ ++ if ((host->mmc->caps & uhs_mask) || (host->mmc->caps2 & hsemmc_mask)) { ++ reg = readl(brcmstb_priv->cfg_regs + SDIO_CFG_MAX_50MHZ_MODE); ++ reg &= ~SDIO_CFG_MAX_50MHZ_MODE_ENABLE; ++ reg |= SDIO_CFG_MAX_50MHZ_MODE_STRAP_OVERRIDE; ++ writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_MAX_50MHZ_MODE); ++ } ++ ++ if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) || ++ (host->mmc->caps & MMC_CAP_NEEDS_POLL)) { ++ /* Force presence */ ++ reg = readl(brcmstb_priv->cfg_regs + SDIO_CFG_CTRL); ++ reg &= ~SDIO_CFG_CTRL_SDCD_N_TEST_LEV; ++ reg |= SDIO_CFG_CTRL_SDCD_N_TEST_EN; ++ writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_CTRL); ++ } ++ ++ /* Guesstimate the timer frequency (controller base clock) */ ++ base_clk_mhz = max_t(u32, clk_get_rate(pltfm_host->clk) / (1000 * 1000), 1); ++ reg = (3 << SDIO_CFG_CQ_CAPABILITY_FMUL_SHIFT) | base_clk_mhz; ++ writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_CQ_CAPABILITY); ++} ++ ++static int bcm2712_init_sd_express(struct sdhci_host *host, struct mmc_ios *ios) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host); ++ struct device *dev = host->mmc->parent; ++ u32 ctrl_val; ++ u32 present_state; ++ int ret; ++ ++ if (!brcmstb_priv->sde_ioaddr || !brcmstb_priv->sde_ioaddr2) ++ return -EINVAL; ++ ++ if (!brcmstb_priv->pinctrl) ++ return -EINVAL; ++ ++ /* Turn off the SD clock first */ ++ sdhci_set_clock(host, 0); ++ ++ /* Disable SD DAT0-3 pulls */ ++ pinctrl_select_state(brcmstb_priv->pinctrl, brcmstb_priv->pins_sdex); ++ ++ ctrl_val = readl(brcmstb_priv->sde_ioaddr); ++ dev_dbg(dev, "ctrl_val 1 %08x\n", ctrl_val); ++ ++ /* Tri-state the SD pins */ ++ ctrl_val |= 0x1ff8; ++ writel(ctrl_val, brcmstb_priv->sde_ioaddr); ++ dev_dbg(dev, "ctrl_val 1->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr)); ++ /* Let voltages settle */ ++ udelay(100); ++ ++ /* Enable the PCIe sideband pins */ ++ ctrl_val &= ~0x6000; ++ writel(ctrl_val, brcmstb_priv->sde_ioaddr); ++ dev_dbg(dev, "ctrl_val 1->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr)); ++ /* Let voltages settle */ ++ udelay(100); ++ ++ /* Turn on the 1v8 VDD2 regulator */ ++ ret = regulator_enable(brcmstb_priv->sde_1v8); ++ if (ret) ++ return ret; ++ ++ /* Wait for Tpvcrl */ ++ msleep(1); ++ ++ /* Sample DAT2 (CLKREQ#) - if low, card is in PCIe mode */ ++ present_state = sdhci_readl(host, SDHCI_PRESENT_STATE); ++ present_state = (present_state & SDHCI_DATA_LVL_MASK) >> SDHCI_DATA_LVL_SHIFT; ++ dev_dbg(dev, "state = 0x%08x\n", present_state); ++ ++ if (present_state & BIT(2)) { ++ dev_err(dev, "DAT2 still high, abandoning SDex switch\n"); ++ return -ENODEV; ++ } ++ ++ /* Turn on the LCPLL PTEST mux */ ++ ctrl_val = readl(brcmstb_priv->sde_ioaddr2 + 20); // misc5 ++ ctrl_val &= ~(0x7 << 7); ++ ctrl_val |= 3 << 7; ++ writel(ctrl_val, brcmstb_priv->sde_ioaddr2 + 20); ++ dev_dbg(dev, "misc 5->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr2 + 20)); ++ ++ /* PTEST diff driver enable */ ++ ctrl_val = readl(brcmstb_priv->sde_ioaddr2); ++ ctrl_val |= BIT(21); ++ writel(ctrl_val, brcmstb_priv->sde_ioaddr2); ++ ++ dev_dbg(dev, "misc 0->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr2)); ++ ++ /* Wait for more than the minimum Tpvpgl time */ ++ msleep(100); ++ ++ if (brcmstb_priv->sde_pcie) { ++ struct of_changeset changeset; ++ static struct property okay_property = { ++ .name = "status", ++ .value = "okay", ++ .length = 5, ++ }; ++ ++ /* Enable the pcie controller */ ++ of_changeset_init(&changeset); ++ ret = of_changeset_update_property(&changeset, ++ brcmstb_priv->sde_pcie, ++ &okay_property); ++ if (ret) { ++ dev_err(dev, "%s: failed to update property - %d\n", __func__, ++ ret); ++ return -ENODEV; ++ } ++ ret = of_changeset_apply(&changeset); ++ } ++ ++ dev_dbg(dev, "%s -> %d\n", __func__, ret); ++ return ret; ++} ++ + static void sdhci_brcmstb_dumpregs(struct mmc_host *mmc) + { + sdhci_dumpregs(mmc_priv(mmc)); +@@ -131,6 +338,7 @@ static void sdhci_brcmstb_dumpregs(struct mmc_host *mmc) + static void sdhci_brcmstb_cqe_enable(struct mmc_host *mmc) + { + struct sdhci_host *host = mmc_priv(mmc); ++ struct cqhci_host *cq_host = mmc->cqe_private; + u32 reg; + + reg = sdhci_readl(host, SDHCI_PRESENT_STATE); +@@ -140,6 +348,9 @@ static void sdhci_brcmstb_cqe_enable(struct mmc_host *mmc) + } + + sdhci_cqe_enable(mmc); ++ ++ /* Reset CMD13 polling timer back to eMMC specification default */ ++ cqhci_writel(cq_host, 0x00011000, CQHCI_SSC1); + } + + static const struct cqhci_host_ops sdhci_brcmstb_cqhci_ops = { +@@ -155,6 +366,15 @@ static struct sdhci_ops sdhci_brcmstb_ops = { + .set_uhs_signaling = sdhci_set_uhs_signaling, + }; + ++static struct sdhci_ops sdhci_brcmstb_ops_2712 = { ++ .set_clock = sdhci_bcm2712_set_clock, ++ .set_power = sdhci_brcmstb_set_power, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, ++ .init_sd_express = bcm2712_init_sd_express, ++}; ++ + static struct sdhci_ops sdhci_brcmstb_ops_7216 = { + .set_clock = sdhci_brcmstb_set_clock, + .set_bus_width = sdhci_set_bus_width, +@@ -179,10 +399,18 @@ static const struct brcmstb_match_priv match_priv_7216 = { + .ops = &sdhci_brcmstb_ops_7216, + }; + ++static const struct brcmstb_match_priv match_priv_2712 = { ++ .flags = BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE, ++ .hs400es = sdhci_brcmstb_hs400es, ++ .cfginit = sdhci_brcmstb_cfginit_2712, ++ .ops = &sdhci_brcmstb_ops_2712, ++}; ++ + static const struct of_device_id __maybe_unused sdhci_brcm_of_match = { + { .compatible = "brcm,bcm7425-sdhci", .data = &match_priv_7425 }, + { .compatible = "brcm,bcm7445-sdhci", .data = &match_priv_7445 }, + { .compatible = "brcm,bcm7216-sdhci", .data = &match_priv_7216 }, ++ { .compatible = "brcm,bcm2712-sdhci", .data = &match_priv_2712 }, + {}, + }; + +@@ -255,6 +483,8 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) + struct sdhci_brcmstb_priv *priv; + u32 actual_clock_mhz; + struct sdhci_host *host; ++ struct resource *iomem; ++ bool no_pinctrl = false; + struct clk *clk; + struct clk *base_clk = NULL; + int res; +@@ -277,12 +507,19 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) + return PTR_ERR(host); + + pltfm_host = sdhci_priv(host); ++ pltfm_host->clk = clk; ++ + priv = sdhci_pltfm_priv(pltfm_host); + if (device_property_read_bool(&pdev->dev, "supports-cqe")) { + priv->flags |= BRCMSTB_PRIV_FLAGS_HAS_CQE; + match_priv->ops->irq = sdhci_brcmstb_cqhci_irq; + } + ++ priv->sde_pcie = of_parse_phandle(pdev->dev.of_node, ++ "sde-pcie", 0); ++ if (priv->sde_pcie) ++ priv->flags |= BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS; ++ + /* Map in the non-standard CFG registers */ + priv->cfg_regs = devm_platform_get_and_ioremap_resource(pdev, 1, NULL); + if (IS_ERR(priv->cfg_regs)) { +@@ -295,6 +532,43 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) + if (res) + goto err; + ++ priv->sde_1v8 = devm_regulator_get_optional(&pdev->dev, "sde-1v8"); ++ if (IS_ERR(priv->sde_1v8)) ++ priv->flags &= ~BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS; ++ ++ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 2); ++ if (iomem) { ++ priv->sde_ioaddr = devm_ioremap_resource(&pdev->dev, iomem); ++ if (IS_ERR(priv->sde_ioaddr)) ++ priv->sde_ioaddr = NULL; ++ } ++ ++ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 3); ++ if (iomem) { ++ priv->sde_ioaddr2 = devm_ioremap_resource(&pdev->dev, iomem); ++ if (IS_ERR(priv->sde_ioaddr2)) ++ priv->sde_ioaddr = NULL; ++ } ++ ++ priv->pinctrl = devm_pinctrl_get(&pdev->dev); ++ if (IS_ERR(priv->pinctrl)) { ++ no_pinctrl = true; ++ } ++ priv->pins_default = pinctrl_lookup_state(priv->pinctrl, "default"); ++ if (IS_ERR(priv->pins_default)) { ++ dev_dbg(&pdev->dev, "No pinctrl default state\n"); ++ no_pinctrl = true; ++ } ++ priv->pins_sdex = pinctrl_lookup_state(priv->pinctrl, "sd-express"); ++ if (IS_ERR(priv->pins_sdex)) { ++ dev_dbg(&pdev->dev, "No pinctrl sd-express state\n"); ++ no_pinctrl = true; ++ } ++ if (no_pinctrl || !priv->sde_ioaddr || !priv->sde_ioaddr2) { ++ priv->pinctrl = NULL; ++ priv->flags &= ~BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS; ++ } ++ + /* + * Automatic clock gating does not work for SD cards that may + * voltage switch so only enable it for non-removable devices. +@@ -311,6 +585,13 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) + (host->mmc->caps2 & MMC_CAP2_HS400_ES)) + host->mmc_host_ops.hs400_enhanced_strobe = match_priv->hs400es; + ++ if (host->ops->init_sd_express && ++ (priv->flags & BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS)) ++ host->mmc->caps2 |= MMC_CAP2_SD_EXP; ++ ++ if(match_priv->cfginit) ++ match_priv->cfginit(host); ++ + /* + * Supply the existing CAPS, but clear the UHS modes. This + * will allow these modes to be specified by device tree +@@ -358,7 +639,6 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) + if (res) + goto err; + +- pltfm_host->clk = clk; + return res; + + err: diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c -index b9eb2ec61a83..404870e6b759 100644 +index 10235fdff246..f014437cb911 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c -@@ -207,6 +207,7 @@ static const struct sdhci_ops sdhci_iproc_32only_ops = { +@@ -198,6 +198,7 @@ static const struct sdhci_ops sdhci_iproc_32only_ops = { .write_b = sdhci_iproc_writeb, .set_clock = sdhci_set_clock, .get_max_clock = sdhci_iproc_get_max_clock, @@ -90523,11 +142800,185 @@ .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, +diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c +index 3a3bae6948a8..e9a3b29b409d 100644 +--- a/drivers/mmc/host/sdhci-of-dwcmshc.c ++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c +@@ -90,6 +90,7 @@ struct rk35xx_priv { + + struct dwcmshc_priv { + struct clk *bus_clk; ++ struct clk *sdio_clk; + int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */ + void *priv; /* pointer to SoC private stuff */ + }; +@@ -117,6 +118,17 @@ static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc, + sdhci_adma_write_desc(host, desc, addr, len, cmd); + } + ++static void dwcmshc_set_clock(struct sdhci_host *host, unsigned int clock) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); ++ ++ if (priv->sdio_clk) ++ clk_set_rate(priv->sdio_clk, clock); ++ ++ sdhci_set_clock(host, clock); ++} ++ + static unsigned int dwcmshc_get_max_clock(struct sdhci_host *host) + { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +@@ -339,10 +351,11 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask) + } + + static const struct sdhci_ops sdhci_dwcmshc_ops = { +- .set_clock = sdhci_set_clock, ++ .set_clock = dwcmshc_set_clock, + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = dwcmshc_set_uhs_signaling, + .get_max_clock = dwcmshc_get_max_clock, ++ .get_timeout_clock = sdhci_pltfm_clk_get_timeout_clock, + .reset = sdhci_reset, + .adma_write_desc = dwcmshc_adma_write_desc, + }; +@@ -358,8 +371,10 @@ static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = { + + static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { + .ops = &sdhci_dwcmshc_ops, +- .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, +- .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, ++ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | ++ SDHCI_QUIRK_BROKEN_CARD_DETECTION, ++ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | ++ SDHCI_QUIRK2_BROKEN_HS200, + }; + + #ifdef CONFIG_ACPI +@@ -371,12 +386,24 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_bf3_pdata = { + }; + #endif + ++static const struct sdhci_pltfm_data sdhci_dwcmshc_rp1_pdata = { ++ .ops = &sdhci_dwcmshc_ops, ++ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | ++ SDHCI_QUIRK_BROKEN_CARD_DETECTION, ++ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | ++ SDHCI_QUIRK2_BROKEN_HS200 | ++ SDHCI_QUIRK2_SPURIOUS_INT_RESP, ++}; ++ + static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = { + .ops = &sdhci_dwcmshc_rk35xx_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | + SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | +- SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, ++ SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | ++ SDHCI_QUIRK2_NO_SDR50 | ++ SDHCI_QUIRK2_NO_SDR104 | ++ SDHCI_QUIRK2_NO_SDR25, + }; + + static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) +@@ -435,6 +462,10 @@ static void dwcmshc_rk35xx_postinit(struct sdhci_host *host, struct dwcmshc_priv + } + + static const struct of_device_id sdhci_dwcmshc_dt_ids = { ++ { ++ .compatible = "raspberrypi,rp1-dwcmshc", ++ .data = &sdhci_dwcmshc_rp1_pdata, ++ }, + { + .compatible = "rockchip,rk3588-dwcmshc", + .data = &sdhci_dwcmshc_rk35xx_pdata, +@@ -509,13 +540,32 @@ static int dwcmshc_probe(struct platform_device *pdev) + priv->bus_clk = devm_clk_get(dev, "bus"); + if (!IS_ERR(priv->bus_clk)) + clk_prepare_enable(priv->bus_clk); ++ ++ pltfm_host->timeout_clk = devm_clk_get(dev, "timeout"); ++ if (!IS_ERR(pltfm_host->timeout_clk)) ++ err = clk_prepare_enable(pltfm_host->timeout_clk); ++ if (err) ++ goto free_pltfm; ++ ++ priv->sdio_clk = devm_clk_get_optional(&pdev->dev, "sdio"); + } + ++ pltfm_host->timeout_clk = devm_clk_get(&pdev->dev, "timeout"); ++ if (IS_ERR(pltfm_host->timeout_clk)) { ++ err = PTR_ERR(pltfm_host->timeout_clk); ++ dev_err(&pdev->dev, "failed to get timeout clk: %d\n", err); ++ goto free_pltfm; ++ } ++ err = clk_prepare_enable(pltfm_host->timeout_clk); ++ if (err) ++ goto free_pltfm; ++ + err = mmc_of_parse(host->mmc); + if (err) + goto err_clk; + + sdhci_get_of_property(pdev); ++ sdhci_enable_v4_mode(host); + + priv->vendor_specific_area1 = + sdhci_readl(host, DWCMSHC_P_VENDOR_AREA1) & DWCMSHC_AREA1_MASK; +@@ -575,6 +625,7 @@ static int dwcmshc_probe(struct platform_device *pdev) + pm_runtime_put_noidle(dev); + err_clk: + clk_disable_unprepare(pltfm_host->clk); ++ clk_disable_unprepare(pltfm_host->timeout_clk); + clk_disable_unprepare(priv->bus_clk); + if (rk_priv) + clk_bulk_disable_unprepare(RK35xx_MAX_CLKS, +diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c +index a72e123a585d..58e5c46edb06 100644 +--- a/drivers/mmc/host/sdhci-pltfm.c ++++ b/drivers/mmc/host/sdhci-pltfm.c +@@ -33,6 +33,14 @@ unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host) + } + EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_max_clock); + ++unsigned int sdhci_pltfm_clk_get_timeout_clock(struct sdhci_host *host) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ ++ return clk_get_rate(pltfm_host->timeout_clk); ++} ++EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_timeout_clock); ++ + static const struct sdhci_ops sdhci_pltfm_ops = { + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, +diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h +index b81d5b0fd616..4eb77191c421 100644 +--- a/drivers/mmc/host/sdhci-pltfm.h ++++ b/drivers/mmc/host/sdhci-pltfm.h +@@ -20,6 +20,7 @@ struct sdhci_pltfm_data { + + struct sdhci_pltfm_host { + struct clk *clk; ++ struct clk *timeout_clk; + + /* migrate from sdhci_of_host */ + unsigned int clock; +@@ -106,6 +107,8 @@ extern void sdhci_pltfm_remove(struct platform_device *pdev); + + extern unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host); + ++extern unsigned int sdhci_pltfm_clk_get_timeout_clock(struct sdhci_host *host); ++ + static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host) + { + return host->private; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c -index d42e86cdff12..0533339d7979 100644 +index ff41aa56564e..7e9ec325b87c 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c -@@ -41,7 +41,7 @@ +@@ -40,7 +40,7 @@ pr_debug("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x) #define SDHCI_DUMP(f, x...) \ @@ -90536,39 +142987,134 @@ #define MAX_TUNING_LOOP 40 -@@ -3145,7 +3145,7 @@ static void sdhci_timeout_timer(struct timer_list *t) +@@ -1713,6 +1713,12 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) + if (host->use_external_dma) + sdhci_external_dma_pre_transfer(host, cmd); + ++ if (host->quirks2 & SDHCI_QUIRK2_SPURIOUS_INT_RESP) { ++ host->ier |= SDHCI_INT_RESPONSE; ++ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); ++ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); ++ } ++ + sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); + + return true; +@@ -3047,6 +3053,15 @@ static void sdhci_card_event(struct mmc_host *mmc) + spin_unlock_irqrestore(&host->lock, flags); + } + ++static int sdhci_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios) ++{ ++ struct sdhci_host *host = mmc_priv(mmc); ++ ++ if (!host->ops->init_sd_express) ++ return -EOPNOTSUPP; ++ return host->ops->init_sd_express(host, ios); ++} ++ + static const struct mmc_host_ops sdhci_ops = { + .request = sdhci_request, + .post_req = sdhci_post_req, +@@ -3062,6 +3077,7 @@ static const struct mmc_host_ops sdhci_ops = { + .execute_tuning = sdhci_execute_tuning, + .card_event = sdhci_card_event, + .card_busy = sdhci_card_busy, ++ .init_sd_express = sdhci_init_sd_express, + }; + + /*****************************************************************************\ +@@ -3209,7 +3225,7 @@ static void sdhci_timeout_timer(struct timer_list *t) 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_err_stats_inc(host, REQ_TIMEOUT); sdhci_dumpregs(host); - -@@ -3167,7 +3167,7 @@ static void sdhci_timeout_data_timer(struct timer_list *t) +@@ -3232,7 +3248,7 @@ static void sdhci_timeout_data_timer(struct timer_list *t) 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_err_stats_inc(host, REQ_TIMEOUT); sdhci_dumpregs(host); +@@ -3296,6 +3312,11 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p) + if (intmask & SDHCI_INT_TIMEOUT) { + host->cmd->error = -ETIMEDOUT; + sdhci_err_stats_inc(host, CMD_TIMEOUT); ++ if (host->quirks2 & SDHCI_QUIRK2_SPURIOUS_INT_RESP) { ++ host->ier &= ~SDHCI_INT_RESPONSE; ++ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); ++ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); ++ } + } else { + host->cmd->error = -EILSEQ; + if (!mmc_op_tuning(host->cmd->opcode)) +@@ -4574,6 +4595,15 @@ int sdhci_setup_host(struct sdhci_host *host) + !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50)) + mmc->caps |= MMC_CAP_UHS_DDR50; + ++ if (host->quirks2 & SDHCI_QUIRK2_NO_SDR25) ++ mmc->caps &= ~MMC_CAP_UHS_SDR25; ++ ++ if (host->quirks2 & SDHCI_QUIRK2_NO_SDR50) ++ mmc->caps &= ~MMC_CAP_UHS_SDR50; ++ ++ if (host->quirks2 & SDHCI_QUIRK2_NO_SDR104) ++ mmc->caps &= ~MMC_CAP_UHS_SDR104; ++ + /* Does the host need tuning for SDR50? */ + if (host->caps1 & SDHCI_USE_SDR50_TUNING) + host->flags |= SDHCI_SDR50_NEEDS_TUNING; +diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h +index f219bdea8f28..112402286f73 100644 +--- a/drivers/mmc/host/sdhci.h ++++ b/drivers/mmc/host/sdhci.h +@@ -486,6 +486,14 @@ struct sdhci_host { + /* Issue CMD and DATA reset together */ + #define SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER (1<<19) + ++/* Quirks to ignore a speed if a that speed is unreliable */ ++#define SDHCI_QUIRK2_NO_SDR25 (1<<19) ++#define SDHCI_QUIRK2_NO_SDR50 (1<<20) ++#define SDHCI_QUIRK2_NO_SDR104 (1<<21) ++ ++/* Command timeouts may generate a trailing INT_RESPONSE later */ ++#define SDHCI_QUIRK2_SPURIOUS_INT_RESP (1<<31) ++ + int irq; /* Device IRQ */ + void __iomem *ioaddr; /* Mapped address */ + phys_addr_t mapbase; /* physical address base */ +@@ -668,6 +676,7 @@ struct sdhci_ops { + void (*request_done)(struct sdhci_host *host, + struct mmc_request *mrq); + void (*dump_vendor_regs)(struct sdhci_host *host); ++ int (*init_sd_express)(struct sdhci_host *host, struct mmc_ios *ios); + }; + #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c -index 8c221666c972..f63ac74227b3 100644 +index 89c8ddc6565a..0ca1dcc04002 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c -@@ -67,6 +67,9 @@ +@@ -67,6 +67,12 @@ /* 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 bool eee = true; ++module_param(eee, bool, 0444); ++MODULE_PARM_DESC(eee, "Enable EEE (default Y)"); static inline void bcmgenet_writel(u32 value, void __iomem *offset) { -@@ -2430,6 +2433,11 @@ static void reset_umac(struct bcmgenet_priv *priv) +@@ -2491,6 +2497,11 @@ static void reset_umac(struct bcmgenet_priv *priv) bcmgenet_rbuf_ctrl_set(priv, 0); udelay(10); @@ -90580,7 +143126,7 @@ /* issue soft reset and disable MAC while updating its registers */ bcmgenet_umac_writel(priv, CMD_SW_RESET, UMAC_CMD); udelay(2); -@@ -2599,7 +2607,7 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, +@@ -2660,7 +2671,7 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX); bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX); @@ -90589,7 +143135,7 @@ /* Disable rate control for now */ bcmgenet_tdma_ring_writel(priv, index, flow_period_val, TDMA_FLOW_PERIOD); -@@ -3240,7 +3248,7 @@ static void bcmgenet_get_hw_addr(struct bcmgenet_priv *priv, +@@ -3299,7 +3310,7 @@ static void bcmgenet_get_hw_addr(struct bcmgenet_priv *priv, } /* Returns a reusable dma control register value */ @@ -90598,7 +143144,7 @@ { unsigned int i; u32 reg; -@@ -3265,6 +3273,14 @@ static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv) +@@ -3324,6 +3335,14 @@ static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv) udelay(10); bcmgenet_umac_writel(priv, 0, UMAC_TX_FLUSH); @@ -90613,7 +143159,7 @@ return dma_ctrl; } -@@ -3328,8 +3344,8 @@ static int bcmgenet_open(struct net_device *dev) +@@ -3387,8 +3406,8 @@ static int bcmgenet_open(struct net_device *dev) bcmgenet_set_hw_addr(priv, dev->dev_addr); @@ -90624,7 +143170,25 @@ /* Reinitialize TDMA and RDMA and SW housekeeping */ ret = bcmgenet_init_dma(priv); -@@ -4064,9 +4080,12 @@ static int bcmgenet_probe(struct platform_device *pdev) +@@ -3425,6 +3444,17 @@ static int bcmgenet_open(struct net_device *dev) + + bcmgenet_phy_pause_set(dev, priv->rx_pause, priv->tx_pause); + ++ if (!eee) { ++ struct ethtool_eee eee_data; ++ ++ ret = bcmgenet_get_eee(dev, &eee_data); ++ if (ret == 0) { ++ eee_data.eee_enabled = 0; ++ bcmgenet_set_eee(dev, &eee_data); ++ netdev_warn(dev, "EEE disabled\n"); ++ } ++ } ++ + bcmgenet_netif_start(dev); + + netif_tx_start_all_queues(dev); +@@ -4141,9 +4171,12 @@ static int bcmgenet_probe(struct platform_device *pdev) netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1); /* Set default coalescing parameters */ @@ -90638,7 +143202,7 @@ /* libphy will determine the link state */ netif_carrier_off(dev); -@@ -4182,7 +4201,7 @@ static int bcmgenet_resume(struct device *d) +@@ -4259,7 +4292,7 @@ static int bcmgenet_resume(struct device *d) bcmgenet_hfb_create_rxnfc_filter(priv, rule); /* Disable RX/TX DMA and flush TX queues */ @@ -90648,10 +143212,10 @@ /* Reinitialize TDMA and RDMA and SW housekeeping */ ret = bcmgenet_init_dma(priv); diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h -index f6ca01da141d..45ea07829b8c 100644 +index 1985c0ec4da2..4a73c1572398 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h -@@ -29,7 +29,7 @@ +@@ -31,7 +31,7 @@ #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) @@ -90661,23 +143225,692 @@ /* misc. configuration */ #define MAX_NUM_OF_FS_RULES 16 diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c -index f9e91304d232..7abd5ddebd8e 100644 +index 97ea76d443ab..7f856f5a26d6 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c -@@ -293,6 +293,8 @@ int bcmgenet_mii_probe(struct net_device *dev) +@@ -299,14 +299,14 @@ int bcmgenet_mii_probe(struct net_device *dev) + struct device_node *dn = kdev->of_node; + phy_interface_t phy_iface = priv->phy_interface; + struct phy_device *phydev; +- u32 phy_flags = PHY_BRCM_AUTO_PWRDWN_ENABLE | +- PHY_BRCM_DIS_TXCRXC_NOENRGY | +- PHY_BRCM_IDDQ_SUSPEND; ++ u32 phy_flags = 0; + int ret; + /* 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; + /* This is an ugly quirk but we have not been correctly interpreting + * the phy_interface values and we have done that across different +diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h +index 78c972bb1d96..2e259d91b936 100644 +--- a/drivers/net/ethernet/cadence/macb.h ++++ b/drivers/net/ethernet/cadence/macb.h +@@ -85,6 +85,8 @@ + #define GEM_PBUFRXCUT 0x0044 /* RX Partial Store and Forward */ + #define GEM_JML 0x0048 /* Jumbo Max Length */ + #define GEM_HS_MAC_CONFIG 0x0050 /* GEM high speed config */ ++#define GEM_AMP 0x0054 /* AXI Max Pipeline */ ++#define GEM_INTMOD 0x005c /* Interrupt moderation */ + #define GEM_HRB 0x0080 /* Hash Bottom */ + #define GEM_HRT 0x0084 /* Hash Top */ + #define GEM_SA1B 0x0088 /* Specific1 Bottom */ +@@ -347,6 +349,21 @@ + #define GEM_ADDR64_OFFSET 30 /* Address bus width - 64b or 32b */ + #define GEM_ADDR64_SIZE 1 + ++/* Bitfields in AMP */ ++#define GEM_AR2R_MAX_PIPE_OFFSET 0 /* Maximum number of outstanding AXI read requests */ ++#define GEM_AR2R_MAX_PIPE_SIZE 8 ++#define GEM_AW2W_MAX_PIPE_OFFSET 8 /* Maximum number of outstanding AXI write requests */ ++#define GEM_AW2W_MAX_PIPE_SIZE 8 ++#define GEM_AW2B_FILL_OFFSET 16 /* Select wether the max AW2W transactions operates between: */ ++#define GEM_AW2B_FILL_AW2W 0 /* 0: the AW to W AXI channel */ ++#define GEM_AW2B_FILL_AW2B 1 /* 1: AW to B channel */ ++#define GEM_AW2B_FILL_SIZE 1 ++ ++/* Bitfields in INTMOD */ ++#define GEM_RX_MODERATION_OFFSET 0 /* RX interrupt moderation */ ++#define GEM_RX_MODERATION_SIZE 8 ++#define GEM_TX_MODERATION_OFFSET 16 /* TX interrupt moderation */ ++#define GEM_TX_MODERATION_SIZE 8 + + /* Bitfields in PBUFRXCUT */ + #define GEM_ENCUTTHRU_OFFSET 31 /* Enable RX partial store and forward */ +@@ -807,6 +824,7 @@ + }) + + #define MACB_READ_NSR(bp) macb_readl(bp, NSR) ++#define MACB_READ_TSR(bp) macb_readl(bp, TSR) + + /* struct macb_dma_desc - Hardware DMA descriptor + * @addr: DMA address of data buffer +@@ -1222,6 +1240,7 @@ struct macb_queue { + dma_addr_t tx_ring_dma; + struct work_struct tx_error_task; + bool txubr_pending; ++ bool tx_pending; + struct napi_struct napi_tx; + + dma_addr_t rx_ring_dma; +@@ -1285,9 +1304,15 @@ struct macb { + + u32 caps; + unsigned int dma_burst_length; ++ u8 aw2w_max_pipe; ++ u8 ar2r_max_pipe; ++ bool use_aw2b_fill; + + phy_interface_t phy_interface; + ++ struct gpio_desc *phy_reset_gpio; ++ int phy_reset_ms; ++ + /* AT91RM9200 transmit queue (1 on wire + 1 queued) */ + struct macb_tx_skb rm9200_txq2; + unsigned int max_tx_length; +diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c +index b940dcd3ace6..79fab300a534 100644 +--- a/drivers/net/ethernet/cadence/macb_main.c ++++ b/drivers/net/ethernet/cadence/macb_main.c +@@ -40,6 +40,9 @@ + #include <linux/firmware/xlnx-zynqmp.h> + #include "macb.h" + ++static unsigned int txdelay = 35; ++module_param(txdelay, uint, 0644); ++ + /* This structure is only used for MACB on SiFive FU540 devices */ + struct sifive_fu540_macb_mgmt { + void __iomem *reg; +@@ -334,7 +337,7 @@ static int macb_mdio_wait_for_idle(struct macb *bp) + u32 val; + + return readx_poll_timeout(MACB_READ_NSR, bp, val, val & MACB_BIT(IDLE), +- 1, MACB_MDIO_TIMEOUT); ++ 100, MACB_MDIO_TIMEOUT); + } + + static int macb_mdio_read_c22(struct mii_bus *bus, int mii_id, int regnum) +@@ -493,6 +496,19 @@ static int macb_mdio_write_c45(struct mii_bus *bus, int mii_id, + return status; + } + ++static int macb_mdio_reset(struct mii_bus *bus) ++{ ++ struct macb *bp = bus->priv; ++ ++ if (bp->phy_reset_gpio) { ++ gpiod_set_value_cansleep(bp->phy_reset_gpio, 1); ++ msleep(bp->phy_reset_ms); ++ gpiod_set_value_cansleep(bp->phy_reset_gpio, 0); ++ } ++ ++ return 0; ++} ++ + static void macb_init_buffers(struct macb *bp) + { + struct macb_queue *queue; +@@ -969,6 +985,7 @@ static int macb_mii_init(struct macb *bp) + bp->mii_bus->write = &macb_mdio_write_c22; + bp->mii_bus->read_c45 = &macb_mdio_read_c45; + bp->mii_bus->write_c45 = &macb_mdio_write_c45; ++ bp->mii_bus->reset = &macb_mdio_reset; + snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", + bp->pdev->name, bp->pdev->id); + bp->mii_bus->priv = bp; +@@ -1640,6 +1657,11 @@ static int macb_rx(struct macb_queue *queue, struct napi_struct *napi, + + macb_init_rx_ring(queue); + queue_writel(queue, RBQP, queue->rx_ring_dma); ++#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT ++ if (bp->hw_dma_cap & HW_DMA_CAP_64B) ++ macb_writel(bp, RBQPH, ++ upper_32_bits(queue->rx_ring_dma)); ++#endif + + macb_writel(bp, NCR, ctrl | MACB_BIT(RE)); + +@@ -1940,8 +1962,9 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) + queue_writel(queue, ISR, MACB_BIT(TCOMP) | + MACB_BIT(TXUBR)); + +- if (status & MACB_BIT(TXUBR)) { ++ if (status & MACB_BIT(TXUBR) || queue->tx_pending) { + queue->txubr_pending = true; ++ queue->tx_pending = 0; + wmb(); // ensure softirq can see update + } + +@@ -2394,6 +2417,11 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev) + skb_tx_timestamp(skb); + + spin_lock_irq(&bp->lock); ++ ++ /* TSTART write might get dropped, so make the IRQ retrigger a buffer read */ ++ if (macb_readl(bp, TSR) & MACB_BIT(TGO)) ++ queue->tx_pending = 1; ++ + macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); + spin_unlock_irq(&bp->lock); + +@@ -2768,6 +2796,37 @@ static void macb_configure_dma(struct macb *bp) + } + } + ++static void gem_init_axi(struct macb *bp) ++{ ++ u32 amp; ++ ++ /* AXI pipeline setup - don't touch values unless specified in device ++ * tree. Some hardware could have reset values > 1. ++ */ ++ amp = gem_readl(bp, AMP); ++ ++ if (bp->use_aw2b_fill) ++ amp = GEM_BFINS(AW2B_FILL, bp->use_aw2b_fill, amp); ++ if (bp->aw2w_max_pipe) ++ amp = GEM_BFINS(AW2W_MAX_PIPE, bp->aw2w_max_pipe, amp); ++ if (bp->ar2r_max_pipe) ++ amp = GEM_BFINS(AR2R_MAX_PIPE, bp->ar2r_max_pipe, amp); ++ ++ gem_writel(bp, AMP, amp); ++} ++ ++static void gem_init_intmod(struct macb *bp) ++{ ++ unsigned int throttle; ++ u32 intmod = 0; ++ ++ /* Use sensible interrupt moderation thresholds (50us rx and tx) */ ++ throttle = (1000 * 50) / 800; ++ intmod = GEM_BFINS(TX_MODERATION, throttle, intmod); ++ intmod = GEM_BFINS(RX_MODERATION, throttle, intmod); ++ gem_writel(bp, INTMOD, intmod); ++} ++ + static void macb_init_hw(struct macb *bp) + { + u32 config; +@@ -2796,6 +2855,11 @@ static void macb_init_hw(struct macb *bp) + if (bp->caps & MACB_CAPS_JUMBO) + bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK; + ++ if (macb_is_gem(bp)) { ++ gem_init_axi(bp); ++ gem_init_intmod(bp); ++ } ++ + macb_configure_dma(bp); + + /* Enable RX partial store and forward and set watermark */ +@@ -3157,6 +3221,52 @@ static void gem_get_ethtool_strings(struct net_device *dev, u32 sset, u8 *p) + } + } + ++static int gem_set_coalesce(struct net_device *dev, ++ struct ethtool_coalesce *ec, ++ struct kernel_ethtool_coalesce *kernel_coal, ++ struct netlink_ext_ack *extack) ++{ ++ struct macb *bp = netdev_priv(dev); ++ unsigned int tx_throttle; ++ unsigned int rx_throttle; ++ u32 intmod = 0; ++ ++ /* GEM has simple IRQ throttling support. RX and TX interrupts ++ * are separately moderated on 800ns quantums, with no support ++ * for frame coalescing. ++ */ ++ ++ /* Max is 255 * 0.8us = 204us. Zero implies no moderation. */ ++ if (ec->rx_coalesce_usecs > 204 || ec->tx_coalesce_usecs > 204) ++ return -EINVAL; ++ ++ tx_throttle = (1000 * ec->tx_coalesce_usecs) / 800; ++ rx_throttle = (1000 * ec->rx_coalesce_usecs) / 800; ++ ++ intmod = GEM_BFINS(TX_MODERATION, tx_throttle, intmod); ++ intmod = GEM_BFINS(RX_MODERATION, rx_throttle, intmod); ++ ++ gem_writel(bp, INTMOD, intmod); ++ ++ return 0; ++} ++ ++static int gem_get_coalesce(struct net_device *dev, ++ struct ethtool_coalesce *ec, ++ struct kernel_ethtool_coalesce *kernel_coal, ++ struct netlink_ext_ack *extack) ++{ ++ struct macb *bp = netdev_priv(dev); ++ u32 intmod; ++ ++ intmod = gem_readl(bp, INTMOD); ++ ++ ec->tx_coalesce_usecs = (GEM_BFEXT(TX_MODERATION, intmod) * 800) / 1000; ++ ec->rx_coalesce_usecs = (GEM_BFEXT(RX_MODERATION, intmod) * 800) / 1000; ++ ++ return 0; ++} ++ + static struct net_device_stats *macb_get_stats(struct net_device *dev) + { + struct macb *bp = netdev_priv(dev); +@@ -3749,6 +3859,8 @@ static const struct ethtool_ops macb_ethtool_ops = { + }; + + static const struct ethtool_ops gem_ethtool_ops = { ++ .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS | ++ ETHTOOL_COALESCE_TX_USECS, + .get_regs_len = macb_get_regs_len, + .get_regs = macb_get_regs, + .get_wol = macb_get_wol, +@@ -3758,6 +3870,8 @@ static const struct ethtool_ops gem_ethtool_ops = { + .get_ethtool_stats = gem_get_ethtool_stats, + .get_strings = gem_get_ethtool_strings, + .get_sset_count = gem_get_sset_count, ++ .get_coalesce = gem_get_coalesce, ++ .set_coalesce = gem_set_coalesce, + .get_link_ksettings = macb_get_link_ksettings, + .set_link_ksettings = macb_set_link_ksettings, + .get_ringparam = macb_get_ringparam, +@@ -5054,6 +5168,11 @@ static int macb_probe(struct platform_device *pdev) + } + } + } ++ ++ device_property_read_u8(&pdev->dev, "cdns,aw2w-max-pipe", &bp->aw2w_max_pipe); ++ device_property_read_u8(&pdev->dev, "cdns,ar2r-max-pipe", &bp->ar2r_max_pipe); ++ bp->use_aw2b_fill = device_property_read_bool(&pdev->dev, "cdns,use-aw2b-fill"); ++ + spin_lock_init(&bp->lock); + + /* setup capabilities */ +@@ -5109,6 +5228,21 @@ static int macb_probe(struct platform_device *pdev) + else + bp->phy_interface = interface; + ++ /* optional PHY reset-related properties */ ++ bp->phy_reset_gpio = devm_gpiod_get_optional(&pdev->dev, "phy-reset", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(bp->phy_reset_gpio)) { ++ dev_err(&pdev->dev, "Failed to obtain phy-reset gpio\n"); ++ err = PTR_ERR(bp->phy_reset_gpio); ++ goto err_out_free_netdev; ++ } ++ ++ bp->phy_reset_ms = 10; ++ of_property_read_u32(np, "phy-reset-duration", &bp->phy_reset_ms); ++ /* A sane reset duration should not be longer than 1s */ ++ if (bp->phy_reset_ms > 1000) ++ bp->phy_reset_ms = 1000; ++ + /* IP specific init */ + err = init(pdev); + if (err) +@@ -5185,6 +5319,19 @@ static int macb_remove(struct platform_device *pdev) + return 0; + } + ++static void macb_shutdown(struct platform_device *pdev) ++{ ++ struct net_device *dev; ++ ++ dev = platform_get_drvdata(pdev); ++ ++ rtnl_lock(); ++ netif_device_detach(dev); ++ if (netif_running(dev)) ++ dev_close(dev); ++ rtnl_unlock(); ++} ++ + static int __maybe_unused macb_suspend(struct device *dev) + { + struct net_device *netdev = dev_get_drvdata(dev); +@@ -5399,6 +5546,7 @@ static const struct dev_pm_ops macb_pm_ops = { + static struct platform_driver macb_driver = { + .probe = macb_probe, + .remove = macb_remove, ++ .shutdown = macb_shutdown, + .driver = { + .name = "macb", + .of_match_table = of_match_ptr(macb_dt_ids), +diff --git a/drivers/net/ethernet/realtek/Makefile b/drivers/net/ethernet/realtek/Makefile +index 2e1d78b106b0..adff9ebfbf2c 100644 +--- a/drivers/net/ethernet/realtek/Makefile ++++ b/drivers/net/ethernet/realtek/Makefile +@@ -7,4 +7,7 @@ obj-$(CONFIG_8139CP) += 8139cp.o + obj-$(CONFIG_8139TOO) += 8139too.o + obj-$(CONFIG_ATP) += atp.o + r8169-objs += r8169_main.o r8169_firmware.o r8169_phy_config.o ++ifdef CONFIG_LEDS_TRIGGER_NETDEV ++r8169-objs += r8169_leds.o ++endif + obj-$(CONFIG_R8169) += r8169.o +diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h +index 55ef8251feb5..81567fcf3957 100644 +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -8,6 +8,7 @@ + * See MAINTAINERS file for support contact information. + */ + ++#include <linux/netdevice.h> + #include <linux/types.h> + #include <linux/phy.h> + +@@ -77,3 +78,9 @@ u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp); + u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr); + void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, + enum mac_version ver); ++ ++void r8169_get_led_name(struct rtl8169_private *tp, int idx, ++ char *buf, int buf_len); ++int rtl8168_get_led_mode(struct rtl8169_private *tp); ++int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val); ++void rtl8168_init_leds(struct net_device *ndev); +diff --git a/drivers/net/ethernet/realtek/r8169_leds.c b/drivers/net/ethernet/realtek/r8169_leds.c +new file mode 100644 +index 000000000000..007d077edcad +--- /dev/null ++++ b/drivers/net/ethernet/realtek/r8169_leds.c +@@ -0,0 +1,157 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* r8169_leds.c: Realtek 8169/8168/8101/8125 ethernet driver. ++ * ++ * Copyright (c) 2023 Heiner Kallweit <hkallweit1@gmail.com> ++ * ++ * See MAINTAINERS file for support contact information. ++ */ ++ ++#include <linux/leds.h> ++#include <linux/netdevice.h> ++#include <uapi/linux/uleds.h> ++ ++#include "r8169.h" ++ ++#define RTL8168_LED_CTRL_OPTION2 BIT(15) ++#define RTL8168_LED_CTRL_ACT BIT(3) ++#define RTL8168_LED_CTRL_LINK_1000 BIT(2) ++#define RTL8168_LED_CTRL_LINK_100 BIT(1) ++#define RTL8168_LED_CTRL_LINK_10 BIT(0) ++ ++#define RTL8168_NUM_LEDS 3 ++ ++#define RTL8168_SUPPORTED_MODES \ ++ (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK_100) | \ ++ BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_RX) | \ ++ BIT(TRIGGER_NETDEV_TX)) ++ ++struct r8169_led_classdev { ++ struct led_classdev led; ++ struct net_device *ndev; ++ int index; ++}; ++ ++#define lcdev_to_r8169_ldev(lcdev) container_of(lcdev, struct r8169_led_classdev, led) ++ ++static int rtl8168_led_hw_control_is_supported(struct led_classdev *led_cdev, ++ unsigned long flags) ++{ ++ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); ++ struct rtl8169_private *tp = netdev_priv(ldev->ndev); ++ int shift = ldev->index * 4; ++ bool rx, tx; ++ ++ if (flags & ~RTL8168_SUPPORTED_MODES) ++ goto nosupp; ++ ++ rx = flags & BIT(TRIGGER_NETDEV_RX); ++ tx = flags & BIT(TRIGGER_NETDEV_TX); ++ if (rx != tx) ++ goto nosupp; ++ ++ return 0; ++ ++nosupp: ++ /* Switch LED off to indicate that mode isn't supported */ ++ rtl8168_led_mod_ctrl(tp, 0x000f << shift, 0); ++ return -EOPNOTSUPP; ++} ++ ++static int rtl8168_led_hw_control_set(struct led_classdev *led_cdev, ++ unsigned long flags) ++{ ++ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); ++ struct rtl8169_private *tp = netdev_priv(ldev->ndev); ++ int shift = ldev->index * 4; ++ u16 mode = 0; ++ ++ if (flags & BIT(TRIGGER_NETDEV_LINK_10)) ++ mode |= RTL8168_LED_CTRL_LINK_10; ++ if (flags & BIT(TRIGGER_NETDEV_LINK_100)) ++ mode |= RTL8168_LED_CTRL_LINK_100; ++ if (flags & BIT(TRIGGER_NETDEV_LINK_1000)) ++ mode |= RTL8168_LED_CTRL_LINK_1000; ++ if (flags & BIT(TRIGGER_NETDEV_TX)) ++ mode |= RTL8168_LED_CTRL_ACT; ++ ++ return rtl8168_led_mod_ctrl(tp, 0x000f << shift, mode << shift); ++} ++ ++static int rtl8168_led_hw_control_get(struct led_classdev *led_cdev, ++ unsigned long *flags) ++{ ++ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); ++ struct rtl8169_private *tp = netdev_priv(ldev->ndev); ++ int shift = ldev->index * 4; ++ int mode; ++ ++ mode = rtl8168_get_led_mode(tp); ++ if (mode < 0) ++ return mode; ++ ++ if (mode & RTL8168_LED_CTRL_OPTION2) { ++ rtl8168_led_mod_ctrl(tp, RTL8168_LED_CTRL_OPTION2, 0); ++ netdev_notice(ldev->ndev, "Deactivating unsupported Option2 LED mode\n"); ++ } ++ ++ mode = (mode >> shift) & 0x000f; ++ ++ if (mode & RTL8168_LED_CTRL_ACT) ++ *flags |= BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX); ++ ++ if (mode & RTL8168_LED_CTRL_LINK_10) ++ *flags |= BIT(TRIGGER_NETDEV_LINK_10); ++ if (mode & RTL8168_LED_CTRL_LINK_100) ++ *flags |= BIT(TRIGGER_NETDEV_LINK_100); ++ if (mode & RTL8168_LED_CTRL_LINK_1000) ++ *flags |= BIT(TRIGGER_NETDEV_LINK_1000); ++ ++ return 0; ++} ++ ++static struct device * ++ r8169_led_hw_control_get_device(struct led_classdev *led_cdev) ++{ ++ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); ++ ++ return &ldev->ndev->dev; ++} ++ ++static void rtl8168_setup_ldev(struct r8169_led_classdev *ldev, ++ struct net_device *ndev, int index) ++{ ++ struct rtl8169_private *tp = netdev_priv(ndev); ++ struct led_classdev *led_cdev = &ldev->led; ++ char led_nameLED_MAX_NAME_SIZE; ++ ++ ldev->ndev = ndev; ++ ldev->index = index; ++ ++ r8169_get_led_name(tp, index, led_name, LED_MAX_NAME_SIZE); ++ led_cdev->name = led_name; ++ led_cdev->default_trigger = "netdev"; ++ led_cdev->hw_control_trigger = "netdev"; ++ led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN; ++ led_cdev->hw_control_is_supported = rtl8168_led_hw_control_is_supported; ++ led_cdev->hw_control_set = rtl8168_led_hw_control_set; ++ led_cdev->hw_control_get = rtl8168_led_hw_control_get; ++ led_cdev->hw_control_get_device = r8169_led_hw_control_get_device; ++ ++ /* ignore errors */ ++ devm_led_classdev_register(&ndev->dev, led_cdev); ++} ++ ++void rtl8168_init_leds(struct net_device *ndev) ++{ ++ /* bind resource mgmt to netdev */ ++ struct device *dev = &ndev->dev; ++ struct r8169_led_classdev *leds; ++ int i; ++ ++ leds = devm_kcalloc(dev, RTL8168_NUM_LEDS, sizeof(*leds), GFP_KERNEL); ++ if (!leds) ++ return; ++ ++ for (i = 0; i < RTL8168_NUM_LEDS; i++) ++ rtl8168_setup_ldev(leds + i, ndev, i); ++} +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 81fd31f6fac4..47d2f4f13220 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -289,6 +289,7 @@ enum rtl8168_8101_registers { + }; + + enum rtl8168_registers { ++ LED_CTRL = 0x18, + LED_FREQ = 0x1a, + EEE_LED = 0x1b, + ERIDR = 0x70, +@@ -620,6 +621,7 @@ struct rtl8169_private { + + raw_spinlock_t config25_lock; + raw_spinlock_t mac_ocp_lock; ++ struct mutex led_lock; /* serialize LED ctrl RMW access */ + + raw_spinlock_t cfg9346_usage_lock; + int cfg9346_usage_count; +@@ -792,6 +794,62 @@ static const struct rtl_cond name = { \ + \ + static bool name ## _check(struct rtl8169_private *tp) + ++int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val) ++{ ++ struct device *dev = tp_to_dev(tp); ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret < 0) ++ return ret; ++ ++ mutex_lock(&tp->led_lock); ++ RTL_W16(tp, LED_CTRL, (RTL_R16(tp, LED_CTRL) & ~mask) | val); ++ mutex_unlock(&tp->led_lock); ++ ++ pm_runtime_put_sync(dev); ++ ++ return 0; ++} ++ ++int rtl8168_get_led_mode(struct rtl8169_private *tp) ++{ ++ struct device *dev = tp_to_dev(tp); ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret < 0) ++ return ret; ++ ++ ret = RTL_R16(tp, LED_CTRL); ++ ++ pm_runtime_put_sync(dev); ++ ++ return ret; ++} ++ ++void r8169_get_led_name(struct rtl8169_private *tp, int idx, ++ char *buf, int buf_len) ++{ ++ struct pci_dev *pdev = tp->pci_dev; ++ char pdom8, pfun8; ++ int domain; ++ ++ domain = pci_domain_nr(pdev->bus); ++ if (domain) ++ snprintf(pdom, sizeof(pdom), "P%d", domain); ++ else ++ pdom0 = '\0'; ++ ++ if (pdev->multifunction) ++ snprintf(pfun, sizeof(pfun), "f%d", PCI_FUNC(pdev->devfn)); ++ else ++ pfun0 = '\0'; ++ ++ snprintf(buf, buf_len, "en%sp%ds%d%s-%d::lan", pdom, pdev->bus->number, ++ PCI_SLOT(pdev->devfn), pfun, idx); ++} ++ + static void r8168fp_adjust_ocp_cmd(struct rtl8169_private *tp, u32 *cmd, int type) + { + /* based on RTL8168FP_OOBMAC_BASE in vendor driver */ +@@ -5227,6 +5285,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + raw_spin_lock_init(&tp->cfg9346_usage_lock); + raw_spin_lock_init(&tp->config25_lock); + raw_spin_lock_init(&tp->mac_ocp_lock); ++ mutex_init(&tp->led_lock); + + dev->tstats = devm_netdev_alloc_pcpu_stats(&pdev->dev, + struct pcpu_sw_netstats); +@@ -5383,6 +5442,12 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + if (rc) + return rc; + ++#if IS_REACHABLE(CONFIG_LEDS_CLASS) && IS_ENABLED(CONFIG_LEDS_TRIGGER_NETDEV) ++ if (tp->mac_version > RTL_GIGA_MAC_VER_06 && ++ tp->mac_version < RTL_GIGA_MAC_VER_61) ++ rtl8168_init_leds(dev); ++#endif ++ + netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n", + rtl_chip_infoschipset.name, dev->dev_addr, xid, tp->irq); + +diff --git a/drivers/net/phy/bcm-phy-ptp.c b/drivers/net/phy/bcm-phy-ptp.c +index ef00d6163061..30ee23e73a4b 100644 +--- a/drivers/net/phy/bcm-phy-ptp.c ++++ b/drivers/net/phy/bcm-phy-ptp.c +@@ -916,6 +916,18 @@ struct bcm_ptp_private *bcm_ptp_probe(struct phy_device *phydev) + switch (BRCM_PHY_MODEL(phydev)) { + case PHY_ID_BCM54210E: + break; ++#ifdef PHY_ID_BCM54213PE ++ case PHY_ID_BCM54213PE: ++ switch (phydev->mdio.addr) { ++ case 0: // CM4 - this is a BCM54210PE which supports PTP ++ break; ++ case 1: // 4B - this is a BCM54213PE which doesn't ++ return NULL; ++ default: // Unknown - assume it's BCM54210PE ++ break; ++ } ++ break; ++#endif + default: + return NULL; + } diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c -index 644861366d54..992459dcaf39 100644 +index 04b2e6eeb195..aec68af033e4 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c -@@ -82,6 +82,11 @@ static int bcm54210e_config_init(struct phy_device *phydev) +@@ -101,6 +101,11 @@ static int bcm54210e_config_init(struct phy_device *phydev) return 0; } @@ -90689,9 +143922,9 @@ static int bcm54612e_config_init(struct phy_device *phydev) { int reg; -@@ -252,7 +257,8 @@ static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev) - BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 && +@@ -272,7 +277,8 @@ static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev) BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M && + BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54210E && BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54810 && - BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) + BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811 && @@ -90699,7 +143932,7 @@ return; val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3); -@@ -313,6 +319,9 @@ static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev) +@@ -350,6 +356,9 @@ static void bcm54xx_ptp_config_init(struct phy_device *phydev) static int bcm54xx_config_init(struct phy_device *phydev) { int reg, err, val; @@ -90709,7 +143942,17 @@ reg = phy_read(phydev, MII_BCM54XX_ECR); if (reg < 0) -@@ -350,6 +359,9 @@ static int bcm54xx_config_init(struct phy_device *phydev) +@@ -374,6 +383,9 @@ static int bcm54xx_config_init(struct phy_device *phydev) + (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE)) + bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0); + ++ if (of_property_read_bool(np, "brcm,powerdown-enable")) ++ phydev->dev_flags |= PHY_BRCM_AUTO_PWRDWN_ENABLE; ++ + bcm54xx_adjust_rxrefclk(phydev); + + switch (BRCM_PHY_MODEL(phydev)) { +@@ -387,6 +399,9 @@ static int bcm54xx_config_init(struct phy_device *phydev) case PHY_ID_BCM54612E: err = bcm54612e_config_init(phydev); break; @@ -90719,51 +143962,67 @@ case PHY_ID_BCM54616S: err = bcm54616s_config_init(phydev); break; -@@ -368,17 +380,15 @@ static int bcm54xx_config_init(struct phy_device *phydev) +@@ -405,10 +420,10 @@ static int bcm54xx_config_init(struct phy_device *phydev) 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_modes0) | -+ BCM5482_SHD_LEDS1_LED3(led_modes1); - bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val); + /* For non-SFP setups, 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. + * Don't do this for devices on an SFP module, since some of these + * use the LED outputs to control the SFP LOS signal, and changing + * these settings will cause LOS to malfunction. +@@ -417,10 +432,15 @@ static int bcm54xx_config_init(struct phy_device *phydev) + val = BCM54XX_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) | + BCM54XX_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1); + bcm_phy_write_shadow(phydev, BCM54XX_SHD_LEDS1, val); ++ /* BCM54210PE controls two extra LEDs with the next register. ++ * Make them shadow the first pair of LEDs - useful on CM4 which ++ * uses LED3 for ETH_LEDY instead of LED1. ++ */ ++ bcm_phy_write_shadow(phydev, BCM54XX_SHD_LEDS1 + 1, val); + + val = BCM_LED_MULTICOLOR_IN_PHASE | +- BCM54XX_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) | +- BCM54XX_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT); ++ BCM54XX_SHD_LEDS1_LED1(led_modes0) | ++ BCM54XX_SHD_LEDS1_LED3(led_modes1); + bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val); + } - return 0; -@@ -762,12 +772,20 @@ static struct phy_driver broadcom_drivers = { - .config_intr = bcm_phy_config_intr, +@@ -1015,7 +1035,7 @@ static struct phy_driver broadcom_drivers = { + .link_change_notify = bcm54xx_link_change_notify, }, { .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, + .flags = PHY_ALWAYS_CALL_SUSPEND, +@@ -1032,6 +1052,19 @@ static struct phy_driver broadcom_drivers = { + .get_wol = bcm54xx_phy_get_wol, + .set_wol = bcm54xx_phy_set_wol, + .led_brightness_set = bcm_phy_led_brightness_set, +}, { + .phy_id = PHY_ID_BCM54213PE, + .phy_id_mask = 0xffffffff, + .name = "Broadcom BCM54213PE", + /* PHY_GBIT_FEATURES */ ++ .get_sset_count = bcm_phy_get_sset_count, ++ .get_strings = bcm_phy_get_strings, ++ .get_stats = bcm54xx_get_stats, ++ .probe = bcm54xx_phy_probe, + .config_init = bcm54xx_config_init, -+ .ack_interrupt = bcm_phy_ack_intr, + .config_intr = bcm_phy_config_intr, ++ .suspend = bcm54xx_suspend, ++ .resume = bcm54xx_resume, }, { .phy_id = PHY_ID_BCM5461, .phy_id_mask = 0xfffffff0, -@@ -924,7 +942,8 @@ module_phy_driver(broadcom_drivers); +@@ -1283,7 +1316,8 @@ module_phy_driver(broadcom_drivers); static struct mdio_device_id __maybe_unused broadcom_tbl = { { PHY_ID_BCM5411, 0xfffffff0 }, { PHY_ID_BCM5421, 0xfffffff0 }, @@ -90774,10 +144033,10 @@ { PHY_ID_BCM54612E, 0xfffffff0 }, { PHY_ID_BCM54616S, 0xfffffff0 }, diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c -index a644e8e5071c..15e0a7383f68 100644 +index 0b88635f4fbc..ae266a69822a 100644 --- a/drivers/net/phy/microchip.c +++ b/drivers/net/phy/microchip.c -@@ -217,6 +217,7 @@ static int lan88xx_probe(struct phy_device *phydev) +@@ -233,6 +233,7 @@ static int lan88xx_probe(struct phy_device *phydev) struct device *dev = &phydev->mdio.dev; struct lan88xx_priv *priv; u32 led_modes4; @@ -90785,7 +144044,7 @@ int len; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -@@ -246,6 +247,32 @@ static int lan88xx_probe(struct phy_device *phydev) +@@ -262,6 +263,32 @@ static int lan88xx_probe(struct phy_device *phydev) return -EINVAL; } @@ -90818,71 +144077,26 @@ /* 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 --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c -index caf7291ffaf8..65ccc94a9282 100644 ---- a/drivers/net/phy/smsc.c -+++ b/drivers/net/phy/smsc.c -@@ -185,6 +185,8 @@ static int lan87xx_read_status(struct phy_device *phydev) - int err = genphy_read_status(phydev); - - if (!phydev->link && priv->energy_enable) { -+ int energy_detected; -+ - /* Disable EDPD to wake up PHY */ - int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); - if (rc < 0) -@@ -195,12 +197,12 @@ static int lan87xx_read_status(struct phy_device *phydev) - if (rc < 0) - return rc; - -- /* Wait max 640 ms to detect energy and the timeout is not -+ /* Wait max 1500 ms to detect energy and the timeout is not - * an actual error. - */ - read_poll_timeout(phy_read, rc, - rc & MII_LAN83C185_ENERGYON || rc < 0, -- 10000, 640000, true, phydev, -+ 150000, 1500000, true, phydev, - MII_LAN83C185_CTRL_STATUS); - if (rc < 0) - return rc; -@@ -210,10 +212,16 @@ static int lan87xx_read_status(struct phy_device *phydev) - if (rc < 0) - return rc; - -+ energy_detected = !!(rc & MII_LAN83C185_ENERGYON); -+ - rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS, - rc | MII_LAN83C185_EDPWRDOWN); - if (rc < 0) - return rc; -+ -+ /* Save CPU and power by deferring the next poll */ -+ if (!energy_detected) -+ msleep(2000); - } +diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c +index d837c1887416..5a1bf42ce156 100644 +--- a/drivers/net/usb/ax88179_178a.c ++++ b/drivers/net/usb/ax88179_178a.c +@@ -1315,6 +1315,8 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf) + + netif_set_tso_max_size(dev->net, 16384); + ++ ax88179_reset(dev); ++ + return 0; + } - return err; -diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile -index 99fd12be2111..99381e6bea78 100644 ---- a/drivers/net/usb/Makefile -+++ b/drivers/net/usb/Makefile -@@ -13,7 +13,7 @@ obj-$(CONFIG_USB_LAN78XX) += lan78xx.o - 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 --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c -index 6f7b70522d92..54b3eb586b7e 100644 +index 921ae046f860..a7f24d6c0cae 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c -@@ -427,6 +427,20 @@ static int msg_level = -1; - module_param(msg_level, int, 0); - MODULE_PARM_DESC(msg_level, "Override default message level"); +@@ -609,6 +609,20 @@ static int lan78xx_alloc_tx_resources(struct lan78xx_net *dev) + dev->n_tx_urbs, dev->tx_urb_size, dev); + } +/* TSO seems to be having some issue with Selective Acknowledge (SACK) that + * results in lost data never being retransmitted. @@ -90900,10 +144114,10 @@ + static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data) { - u32 *buf = kmalloc(sizeof(u32), GFP_KERNEL); -@@ -1169,6 +1183,9 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) + u32 *buf; +@@ -1426,6 +1440,9 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) if (unlikely(ret < 0)) - return -EIO; + return ret; + /* Acknowledge any pending PHY interrupt, lest it be the last */ + phy_read(phydev, LAN88XX_INT_STS); @@ -90911,7 +144125,7 @@ mutex_lock(&phydev->lock); phy_read_status(phydev); link = phydev->link; -@@ -1668,6 +1685,7 @@ static const struct ethtool_ops lan78xx_ethtool_ops = { +@@ -1938,6 +1955,7 @@ static const struct ethtool_ops lan78xx_ethtool_ops = { .set_link_ksettings = lan78xx_set_link_ksettings, .get_regs_len = lan78xx_get_regs_len, .get_regs = lan78xx_get_regs, @@ -90919,7 +144133,7 @@ }; static void lan78xx_init_mac_address(struct lan78xx_net *dev) -@@ -2168,6 +2186,22 @@ static int lan78xx_phy_init(struct lan78xx_net *dev) +@@ -2410,6 +2428,22 @@ static int lan78xx_phy_init(struct lan78xx_net *dev) mii_adv_to_linkmode_adv_t(fc, mii_adv); linkmode_or(phydev->advertising, fc, phydev->advertising); @@ -90942,9 +144156,9 @@ if (phydev->mdio.dev.of_node) { u32 reg; int len; -@@ -2463,6 +2497,11 @@ static int lan78xx_reset(struct lan78xx_net *dev) - int ret = 0; - unsigned long timeout; +@@ -2883,6 +2917,11 @@ static int lan78xx_reset(struct lan78xx_net *dev) + int ret; + u32 buf; u8 sig; + bool has_eeprom; + bool has_otp; @@ -90953,18 +144167,19 @@ + has_otp = !lan78xx_read_otp(dev, 0, 0, NULL); ret = lan78xx_read_reg(dev, HW_CFG, &buf); - buf |= HW_CFG_LRST_; -@@ -2516,6 +2555,9 @@ static int lan78xx_reset(struct lan78xx_net *dev) + if (ret < 0) +@@ -2947,6 +2986,10 @@ static int lan78xx_reset(struct lan78xx_net *dev) - 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); -@@ -2571,6 +2613,9 @@ static int lan78xx_reset(struct lan78xx_net *dev) + if (ret < 0) + return ret; +@@ -3046,6 +3089,9 @@ static int lan78xx_reset(struct lan78xx_net *dev) buf |= MAC_CR_AUTO_DUPLEX_ | MAC_CR_AUTO_SPEED_; } } @@ -90972,9 +144187,9 @@ + 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); -@@ -2900,8 +2945,14 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf) + if (ret < 0) + return ret; +@@ -3443,8 +3489,14 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf) if (DEFAULT_RX_CSUM_ENABLE) dev->net->features |= NETIF_F_RXCSUM; @@ -90991,18 +144206,9 @@ if (DEFAULT_VLAN_RX_OFFLOAD) dev->net->features |= NETIF_F_HW_VLAN_CTAG_RX; -@@ -3124,7 +3175,7 @@ static int rx_submit(struct lan78xx_net *dev, struct urb *urb, gfp_t flags) - 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; -@@ -3728,7 +3779,13 @@ static int lan78xx_probe(struct usb_interface *intf, - netdev->max_mtu = MAX_SINGLE_PACKET_SIZE; - netif_set_gso_max_size(netdev, MAX_SINGLE_PACKET_SIZE - MAX_HEADER); +@@ -4412,7 +4464,13 @@ static int lan78xx_probe(struct usb_interface *intf, + if (ret < 0) + goto out4; - period = ep_intr->desc.bInterval; + if (int_urb_interval_ms <= 0) @@ -91012,5363 +144218,14 @@ + + netif_notice(dev, probe, netdev, "int urb period %d\n", period); + - maxp = usb_maxpacket(dev->udev, dev->pipe_intr, 0); + maxp = usb_maxpacket(dev->udev, dev->pipe_intr); buf = kmalloc(maxp, GFP_KERNEL); - if (buf) { -diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c -index 842f16815395..257dc21e2bc7 100644 ---- a/drivers/net/usb/r8152.c -+++ b/drivers/net/usb/r8152.c -@@ -26,9 +26,10 @@ - #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" -@@ -42,10 +43,14 @@ - - #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 -@@ -62,6 +67,8 @@ - #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 -@@ -71,6 +78,8 @@ - #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 -@@ -81,6 +90,7 @@ - #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 -@@ -97,6 +107,7 @@ - #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 -@@ -111,6 +122,7 @@ - #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 -@@ -121,7 +133,12 @@ - #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 -@@ -135,16 +152,20 @@ - #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 -@@ -187,6 +208,9 @@ - #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 -@@ -198,6 +222,7 @@ - /* 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 -@@ -209,11 +234,19 @@ - #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 -@@ -248,6 +281,9 @@ - - /* 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) -@@ -281,6 +317,7 @@ - #define MCU_BORW_EN 0x4000 - - /* PLA_CPCR */ -+#define FLOW_CTRL_EN BIT(0) - #define CPCR_RX_VLAN 0x0040 - - /* PLA_CFG_WOL */ -@@ -306,6 +343,10 @@ - /* 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 -@@ -329,6 +370,7 @@ - /* 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) -@@ -341,6 +383,7 @@ - #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 -@@ -381,6 +424,13 @@ - #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 -@@ -429,6 +479,9 @@ - #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) -@@ -436,27 +489,52 @@ - /* 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 -@@ -492,8 +570,12 @@ - #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) -@@ -501,6 +583,7 @@ - #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) -@@ -521,6 +604,8 @@ enum spd_duplex { - FORCE_10M_FULL, - FORCE_100M_HALF, - FORCE_100M_FULL, -+ FORCE_1000M_FULL, -+ NWAY_2500M_FULL, - }; - - /* OCP_ALDPS_CONFIG */ -@@ -585,6 +670,9 @@ enum spd_duplex { - #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 -@@ -604,7 +692,8 @@ enum spd_duplex { - #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) -@@ -635,6 +724,11 @@ enum spd_duplex { - #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, -@@ -642,6 +736,9 @@ enum rtl_register_content { - 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 -@@ -653,27 +750,12 @@ enum rtl_register_content { - - #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 { -@@ -689,21 +771,9 @@ enum rtl8152_flags { - 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; -@@ -815,9 +885,11 @@ struct r8152 { - 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; -@@ -859,7 +931,9 @@ struct r8152 { - 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; -@@ -894,10 +968,71 @@ struct fw_header { - 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_set2; -+ struct fw_phy_set bp8; -+ 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. -@@ -911,6 +1046,7 @@ struct fw_header { - * @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 -@@ -936,8 +1072,10 @@ struct fw_mac { - /** - * 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; -@@ -950,6 +1088,7 @@ struct fw_phy_patch_key { - * 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. -@@ -958,8 +1097,9 @@ struct fw_phy_patch_key { - * @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. -@@ -992,6 +1132,15 @@ enum rtl_fw_type { - 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 { -@@ -1005,6 +1154,15 @@ enum rtl_version { - 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 - }; - -@@ -1020,6 +1178,7 @@ enum tx_csum_stat { - #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. -@@ -1027,8 +1186,7 @@ enum tx_csum_stat { - 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) -@@ -1388,6 +1546,10 @@ void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val) - 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); -@@ -2410,11 +2572,9 @@ static void tx_bottom(struct r8152 *tp) - } 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; -@@ -2612,7 +2772,7 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, - - 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; -@@ -2623,45 +2783,78 @@ static void r8152b_reset_packet_filter(struct r8152 *tp) - - 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) -@@ -2759,6 +2952,29 @@ static int rtl_stop_rx(struct r8152 *tp) - 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, -@@ -2778,6 +2994,7 @@ static int rtl_enable(struct r8152 *tp) - switch (tp->version) { - case RTL_VER_08: - case RTL_VER_09: -+ case RTL_VER_14: - r8153b_rx_agg_chg_indicate(tp); - break; - default: -@@ -2815,6 +3032,7 @@ static void r8153_set_rx_early_timeout(struct r8152 *tp) - - 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. - */ -@@ -2824,6 +3042,18 @@ static void r8153_set_rx_early_timeout(struct r8152 *tp) - 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; - } -@@ -2843,8 +3073,19 @@ static void r8153_set_rx_early_size(struct r8152 *tp) - 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); -@@ -2854,6 +3095,8 @@ static void r8153_set_rx_early_size(struct r8152 *tp) - - static int rtl8153_enable(struct r8152 *tp) - { -+ u32 ocp_data; -+ - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return -ENODEV; - -@@ -2862,15 +3105,20 @@ static int rtl8153_enable(struct r8152 *tp) - 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); -@@ -2935,12 +3183,40 @@ static void rtl_rx_vlan_en(struct r8152 *tp, bool enable) - { - 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, -@@ -3033,6 +3309,40 @@ static void __rtl_set_wol(struct r8152 *tp, u32 wolopts) - 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 u1u28; -@@ -3092,6 +3402,9 @@ static void r8153b_ups_flags(struct r8152 *tp) - 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; - -@@ -3142,10 +3455,104 @@ static void r8153b_ups_flags(struct r8152 *tp) - 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 */ -@@ -3156,11 +3563,7 @@ static void r8153b_green_en(struct r8152 *tp, bool enable) - 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) -@@ -3197,61 +3600,137 @@ static void r8153b_ups_en(struct r8152 *tp, bool enable) - 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, 0xcfff); -- ocp_data &= ~BIT(0); -- ocp_write_byte(tp, MCU_TYPE_USB, 0xcfff, ocp_data); -- -- 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); -- -- data = r8153_phy_status(tp, 0); -+ 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 (data) { -- case PHY_STAT_PWRDN: -- case PHY_STAT_EXT_INIT: -- r8153b_green_en(tp, -- test_bit(GREEN_ETHERNET, &tp->flags)); -+ if (ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0) & PCUT_STATUS) { -+ int i; - -- data = r8152_mdio_read(tp, MII_BMCR); -- data &= ~BMCR_PDOWN; -- data |= BMCR_RESET; -- r8152_mdio_write(tp, MII_BMCR, data); -+ for (i = 0; i < 500; i++) { -+ if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) & -+ AUTOLOAD_DONE) -+ break; -+ msleep(20); -+ } - -- data = r8153_phy_status(tp, PHY_STAT_LAN_ON); -- fallthrough; -+ tp->rtl_ops.hw_phy_cfg(tp); - -- default: -- if (data != PHY_STAT_LAN_ON) -- netif_warn(tp, link, tp->netdev, -- "PHY not ready"); -- break; -+ rtl8152_set_speed(tp, tp->autoneg, tp->speed, -+ tp->duplex, tp->advertising); - } - } - } - --static void r8153_power_cut_en(struct r8152 *tp, bool enable) -+static void r8153c_ups_en(struct r8152 *tp, bool enable) - { -- u32 ocp_data; -+ u32 ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_POWER_CUT); - -- ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT); -- if (enable) -- ocp_data |= PWR_EN | PHASE2_EN; -- else -- ocp_data &= ~(PWR_EN | PHASE2_EN); -- ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data); -+ if (enable) { -+ r8153b_ups_flags(tp); - -- ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0); -- ocp_data &= ~PCUT_STATUS; -+ 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, 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); -+ } -+ -+ 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); -+ } -+} -+ -+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: -+ 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); -+ } -+ } -+} -+ -+static void r8153_power_cut_en(struct r8152 *tp, bool enable) -+{ -+ u32 ocp_data; -+ -+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT); -+ if (enable) -+ ocp_data |= PWR_EN | PHASE2_EN; -+ else -+ ocp_data &= ~(PWR_EN | PHASE2_EN); -+ ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data); -+ -+ 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); - } - -@@ -3363,7 +3842,39 @@ static void rtl8153b_runtime_enable(struct r8152 *tp, bool enable) - 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); - } - } -@@ -3388,14 +3899,19 @@ static void r8153_teredo_off(struct r8152 *tp) - - 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); -@@ -3430,6 +3946,12 @@ static void rtl_clear_bp(struct r8152 *tp, u16 type) - 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_word(tp, MCU_TYPE_USB, USB_BP2_EN, 0); -@@ -3462,65 +3984,238 @@ static void rtl_clear_bp(struct r8152 *tp, u16 type) - 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; -@@ -3622,6 +4317,11 @@ static bool rtl8152_is_fw_mac_ok(struct r8152 *tp, struct fw_mac *mac) - 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; -@@ -3645,6 +4345,11 @@ static bool rtl8152_is_fw_mac_ok(struct r8152 *tp, struct fw_mac *mac) - 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; -@@ -3772,10 +4477,7 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) - { - 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; - -@@ -3804,50 +4506,56 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) - 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; -@@ -3858,53 +4566,336 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) - "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; - } -- -- break; -- default: -- dev_warn(&tp->intf->dev, "Unknown type %u is found\n", -- type); -+ __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; -+ } - -- /* next block */ -- i += ALIGN(__le32_to_cpu(block->length), 8); -- } -+ if (test_bit(FW_FLAGS_NC, &fw_flags)) { -+ dev_err(&tp->intf->dev, "multiple PHY_UNION_NC encountered\n"); -+ goto fail; -+ } - --fw_end: -- if ((phy_nc || start) && !stop) { -- dev_err(&tp->intf->dev, "without PHY_STOP\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; -+ } - -- return 0; --fail: -- return ret; --} -+ if (test_bit(FW_FLAGS_NC1, &fw_flags)) { -+ dev_err(&tp->intf->dev, "multiple PHY NC1 encountered\n"); -+ goto fail; -+ } - --static void rtl8152_fw_phy_nc_apply(struct r8152 *tp, struct fw_phy_nc *phy) --{ -+ 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", -+ type); -+ break; -+ } -+ -+ /* next block */ -+ i += ALIGN(__le32_to_cpu(block->length), 8); -+ } -+ -+fw_end: -+ 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; -+ } -+ -+ return 0; -+fail: -+ 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_seti.addr), -+ __le16_to_cpu(phy->pre_seti.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(datai)); -+ -+ num = phy->bp_num; -+ for (i = 0; i < num; i++) -+ sram_write(tp, __le16_to_cpu(phy->bpi.addr), __le16_to_cpu(phy->bpi.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; - u32 length, i, num; - __le16 *data; -@@ -3956,6 +4947,12 @@ static void rtl8152_fw_mac_apply(struct r8152 *tp, struct fw_mac *mac) - 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 -@@ -3991,7 +4988,6 @@ static void rtl8152_fw_mac_apply(struct r8152 *tp, struct fw_mac *mac) - 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); -@@ -3999,14 +4995,14 @@ static void rtl8152_fw_mac_apply(struct r8152 *tp, struct fw_mac *mac) - 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; -@@ -4028,18 +5024,40 @@ static void rtl8152_apply_firmware(struct r8152 *tp) - 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; - } -@@ -4186,6 +5204,22 @@ static void r8153_eee_en(struct r8152 *tp, bool enable) - 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) { -@@ -4207,6 +5241,7 @@ static void rtl_eee_enable(struct r8152 *tp, bool enable) - 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); -@@ -4215,6 +5250,19 @@ static void rtl_eee_enable(struct r8152 *tp, bool enable) - 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; - } -@@ -4240,7 +5288,7 @@ static void rtl8152_disable(struct r8152 *tp) - - 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); -@@ -4261,6 +5309,20 @@ static void wait_oob_link_list_ready(struct r8152 *tp) - } - } - -+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; -@@ -4311,7 +5373,7 @@ static void r8152b_exit_oob(struct r8152 *tp) - } - - /* 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); -@@ -4488,6 +5550,36 @@ static int r8153b_post_firmware_1(struct r8152 *tp) - 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; -@@ -4522,7 +5614,7 @@ static void r8153_hw_phy_cfg(struct r8152 *tp) - /* 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); -@@ -4590,13 +5682,37 @@ static void r8153b_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); -+ } -+ - /* 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)); - -@@ -4637,7 +5753,7 @@ static void r8153b_hw_phy_cfg(struct r8152 *tp) - 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); -@@ -4654,7 +5770,7 @@ static void r8153b_hw_phy_cfg(struct r8152 *tp) - 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) -@@ -4666,6 +5782,19 @@ static void r8153b_hw_phy_cfg(struct r8152 *tp) - 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; -@@ -4698,9 +5827,7 @@ static void r8153_first_init(struct r8152 *tp) - - 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; -@@ -4735,8 +5862,7 @@ static void r8153_enter_oob(struct r8152 *tp) - - 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: -@@ -4750,6 +5876,7 @@ static void r8153_enter_oob(struct r8152 *tp) - - case RTL_VER_08: - case RTL_VER_09: -+ case RTL_VER_14: - /* Clear teredo wake event. bit15:8 is the teredo wakeup - * type. Set it to zero. bits7:0 are the W1C bits about - * the events. Set them to all 1 to clear them. -@@ -4786,27 +5913,117 @@ static void rtl8153_disable(struct r8152 *tp) - r8153_aldps_en(tp, true); - } - --static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex, -- u32 advertising) -+static int rtl8156_enable(struct r8152 *tp) - { -- u16 bmcr; -- int ret = 0; -+ u32 ocp_data; -+ u16 speed; - -- if (autoneg == AUTONEG_DISABLE) { -- if (duplex != DUPLEX_HALF && duplex != DUPLEX_FULL) -- return -EINVAL; -+ if (test_bit(RTL8152_UNPLUG, &tp->flags)) -+ return -ENODEV; - -- switch (speed) { -- case SPEED_10: -- bmcr = BMCR_SPEED10; -- if (duplex == DUPLEX_FULL) { -- bmcr |= BMCR_FULLDPLX; -- tp->ups_info.speed_duplex = FORCE_10M_FULL; -- } else { -- tp->ups_info.speed_duplex = FORCE_10M_HALF; -- } -- break; -- case SPEED_100: -+ 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 0xb45e3: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) -+{ -+ u16 bmcr; -+ int ret = 0; -+ -+ if (autoneg == AUTONEG_DISABLE) { -+ if (duplex != DUPLEX_HALF && duplex != DUPLEX_FULL) -+ return -EINVAL; -+ -+ switch (speed) { -+ case SPEED_10: -+ bmcr = BMCR_SPEED10; -+ if (duplex == DUPLEX_FULL) { -+ bmcr |= BMCR_FULLDPLX; -+ tp->ups_info.speed_duplex = FORCE_10M_FULL; -+ } else { -+ tp->ups_info.speed_duplex = FORCE_10M_HALF; -+ } -+ break; -+ case SPEED_100: - bmcr = BMCR_SPEED100; - if (duplex == DUPLEX_FULL) { - bmcr |= BMCR_FULLDPLX; -@@ -4834,58 +6051,73 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex, - - 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; -@@ -5016,7 +6248,7 @@ static void rtl8153b_up(struct r8152 *tp) - - r8153_aldps_en(tp, true); - -- if (tp->udev->speed != USB_SPEED_HIGH) -+ if (tp->udev->speed >= USB_SPEED_SUPER) - r8153b_u1u2en(tp, true); - } - -@@ -5041,239 +6273,486 @@ static void rtl8153b_down(struct r8152 *tp) - r8153_aldps_en(tp, true); - } - --static bool rtl8152_in_nway(struct r8152 *tp) -+static void rtl8153c_change_mtu(struct r8152 *tp) - { -- u16 nway_state; -- -- ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, 0x2000); -- tp->ocp_base = 0x2000; -- ocp_write_byte(tp, MCU_TYPE_PLA, 0xb014, 0x4c); /* phy state */ -- nway_state = ocp_read_word(tp, MCU_TYPE_PLA, 0xb01a); -- -- /* bit 15: TXDIS_STATE, bit 14: ABD_STATE */ -- if (nway_state & 0xc000) -- return false; -- else -- return true; --} -+ 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); - --static bool rtl8153_in_nway(struct r8152 *tp) --{ -- u16 phy_state = ocp_reg_read(tp, OCP_PHY_STATE) & 0xff; -+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, 512 / 64); - -- if (phy_state == TXDIS_STATE || phy_state == ABD_STATE) -- return false; -+ /* 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 -- return true; -+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_FULL, 900 / 8); - } - --static void set_carrier(struct r8152 *tp) -+static void rtl8153c_up(struct r8152 *tp) - { -- struct net_device *netdev = tp->netdev; -- struct napi_struct *napi = &tp->napi; -- u8 speed; -+ u32 ocp_data; - -- speed = rtl8152_get_speed(tp); -+ if (test_bit(RTL8152_UNPLUG, &tp->flags)) -+ return; - -- if (speed & LINK_STATUS) { -- if (!netif_carrier_ok(netdev)) { -- tp->rtl_ops.enable(tp); -- netif_stop_queue(netdev); -- napi_disable(napi); -- netif_carrier_on(netdev); -- rtl_start_rx(tp); -- clear_bit(RTL8152_SET_RX_MODE, &tp->flags); -- _rtl8152_set_rx_mode(netdev); -- napi_enable(&tp->napi); -- netif_wake_queue(netdev); -- netif_info(tp, link, netdev, "carrier on\n"); -- } else if (netif_queue_stopped(netdev) && -- skb_queue_len(&tp->tx_queue) < tp->tx_qlen) { -- netif_wake_queue(netdev); -- } -- } else { -- if (netif_carrier_ok(netdev)) { -- netif_carrier_off(netdev); -- tasklet_disable(&tp->tx_tl); -- napi_disable(napi); -- tp->rtl_ops.disable(tp); -- napi_enable(napi); -- tasklet_enable(&tp->tx_tl); -- netif_info(tp, link, netdev, "carrier off\n"); -- } -- } --} -+ r8153b_u1u2en(tp, false); -+ r8153_u2p3en(tp, false); -+ r8153_aldps_en(tp, false); - --static void rtl_work_func_t(struct work_struct *work) --{ -- struct r8152 *tp = container_of(work, struct r8152, schedule.work); -+ rxdy_gated_en(tp, true); -+ r8153_teredo_off(tp); - -- /* If the device is unplugged or !netif_running(), the workqueue -- * doesn't need to wake the device, and could return directly. -- */ -- if (test_bit(RTL8152_UNPLUG, &tp->flags) || !netif_running(tp->netdev)) -- return; -+ 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); - -- if (usb_autopm_get_interface(tp->intf) < 0) -- return; -+ rtl8152_nic_reset(tp); -+ rtl_reset_bmu(tp); - -- if (!test_bit(WORK_ENABLE, &tp->flags)) -- goto out1; -+ 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); - -- if (!mutex_trylock(&tp->control)) { -- schedule_delayed_work(&tp->schedule, 0); -- goto out1; -- } -+ 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); - -- if (test_and_clear_bit(RTL8152_LINK_CHG, &tp->flags)) -- set_carrier(tp); -+ wait_oob_link_list_ready(tp); - -- if (test_and_clear_bit(RTL8152_SET_RX_MODE, &tp->flags)) -- _rtl8152_set_rx_mode(tp->netdev); -+ 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); - -- /* don't schedule tasket before linking */ -- if (test_and_clear_bit(SCHEDULE_TASKLET, &tp->flags) && -- netif_carrier_ok(tp->netdev)) -- tasklet_schedule(&tp->tx_tl); -+ wait_oob_link_list_ready(tp); - -- mutex_unlock(&tp->control); -+ rtl_rx_vlan_en(tp, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX); - --out1: -- usb_autopm_put_interface(tp->intf); --} -+ rtl8153c_change_mtu(tp); - --static void rtl_hw_phy_work_func_t(struct work_struct *work) --{ -- struct r8152 *tp = container_of(work, struct r8152, hw_phy_work.work); -+ rtl8152_nic_reset(tp); - -- if (test_bit(RTL8152_UNPLUG, &tp->flags)) -- return; -+ /* 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); - -- if (usb_autopm_get_interface(tp->intf) < 0) -- return; -+ ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_B); - -- mutex_lock(&tp->control); -+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG); - -- if (rtl8152_request_firmware(tp) == -ENODEV && tp->rtl_fw.retry) { -- tp->rtl_fw.retry = false; -- tp->rtl_fw.fw = NULL; -+ 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); - -- /* Delay execution in case request_firmware() is not ready yet. -- */ -- queue_delayed_work(system_long_wq, &tp->hw_phy_work, HZ * 10); -- goto ignore_once; -- } -+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); - -- tp->rtl_ops.hw_phy_cfg(tp); -+ 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); - -- rtl8152_set_speed(tp, tp->autoneg, tp->speed, tp->duplex, -- tp->advertising); -+ r8153_aldps_en(tp, true); -+ r8153b_u1u2en(tp, true); -+} - --ignore_once: -- mutex_unlock(&tp->control); -+static inline u32 fc_pause_on_auto(struct r8152 *tp) -+{ -+ return (ALIGN(mtu_to_size(tp->netdev->mtu), 1024) + 6 * 1024); -+} - -- usb_autopm_put_interface(tp->intf); -+static inline u32 fc_pause_off_auto(struct r8152 *tp) -+{ -+ return (ALIGN(mtu_to_size(tp->netdev->mtu), 1024) + 14 * 1024); - } - --#ifdef CONFIG_PM_SLEEP --static int rtl_notifier(struct notifier_block *nb, unsigned long action, -- void *data) -+static void r8156_fc_parameter(struct r8152 *tp) - { -- struct r8152 *tp = container_of(nb, struct r8152, pm_notifier); -+ 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 (action) { -- case PM_HIBERNATION_PREPARE: -- case PM_SUSPEND_PREPARE: -- usb_autopm_get_interface(tp->intf); -+ 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 PM_POST_HIBERNATION: -- case PM_POST_SUSPEND: -- usb_autopm_put_interface(tp->intf); -+ 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; -- -- case PM_POST_RESTORE: -- case PM_RESTORE_PREPARE: - default: - break; - } -- -- return NOTIFY_DONE; - } --#endif - --static int rtl8152_open(struct net_device *netdev) -+static void rtl8156_change_mtu(struct r8152 *tp) - { -- struct r8152 *tp = netdev_priv(netdev); -- int res = 0; -- -- if (work_busy(&tp->hw_phy_work.work) & WORK_BUSY_PENDING) { -- cancel_delayed_work_sync(&tp->hw_phy_work); -- rtl_hw_phy_work_func_t(&tp->hw_phy_work.work); -- } -+ u32 rx_max_size = mtu_to_size(tp->netdev->mtu); - -- res = alloc_all_mem(tp); -- if (res) -- goto out; -+ 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); - -- res = usb_autopm_get_interface(tp->intf); -- if (res < 0) -- goto out_free; -+ /* 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); -+} - -- mutex_lock(&tp->control); -+static void rtl8156_up(struct r8152 *tp) -+{ -+ u32 ocp_data; - -- tp->rtl_ops.up(tp); -+ if (test_bit(RTL8152_UNPLUG, &tp->flags)) -+ return; - -- netif_carrier_off(netdev); -- netif_start_queue(netdev); -- set_bit(WORK_ENABLE, &tp->flags); -+ r8153b_u1u2en(tp, false); -+ r8153_u2p3en(tp, false); -+ r8153_aldps_en(tp, false); - -- res = usb_submit_urb(tp->intr_urb, GFP_KERNEL); -- if (res) { -- if (res == -ENODEV) -- netif_device_detach(tp->netdev); -- netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n", -- res); -- goto out_unlock; -+ 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; - } -- napi_enable(&tp->napi); -- tasklet_enable(&tp->tx_tl); -+ -+ /* 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. bit15:8 is the teredo wakeup -+ * type. Set it to zero. bits7: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; -+ -+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, 0x2000); -+ tp->ocp_base = 0x2000; -+ ocp_write_byte(tp, MCU_TYPE_PLA, 0xb014, 0x4c); /* phy state */ -+ nway_state = ocp_read_word(tp, MCU_TYPE_PLA, 0xb01a); -+ -+ /* bit 15: TXDIS_STATE, bit 14: ABD_STATE */ -+ if (nway_state & 0xc000) -+ return false; -+ else -+ return true; -+} -+ -+static bool rtl8153_in_nway(struct r8152 *tp) -+{ -+ u16 phy_state = ocp_reg_read(tp, OCP_PHY_STATE) & 0xff; -+ -+ if (phy_state == TXDIS_STATE || phy_state == ABD_STATE) -+ return false; -+ else -+ return true; -+} -+ -+static void set_carrier(struct r8152 *tp) -+{ -+ struct net_device *netdev = tp->netdev; -+ struct napi_struct *napi = &tp->napi; -+ u16 speed; -+ -+ speed = rtl8152_get_speed(tp); -+ -+ if (speed & LINK_STATUS) { -+ if (!netif_carrier_ok(netdev)) { -+ tp->rtl_ops.enable(tp); -+ netif_stop_queue(netdev); -+ napi_disable(napi); -+ netif_carrier_on(netdev); -+ rtl_start_rx(tp); -+ clear_bit(RTL8152_SET_RX_MODE, &tp->flags); -+ _rtl8152_set_rx_mode(netdev); -+ napi_enable(napi); -+ netif_wake_queue(netdev); -+ netif_info(tp, link, netdev, "carrier on\n"); -+ } else if (netif_queue_stopped(netdev) && -+ skb_queue_len(&tp->tx_queue) < tp->tx_qlen) { -+ netif_wake_queue(netdev); -+ } -+ } else { -+ if (netif_carrier_ok(netdev)) { -+ netif_carrier_off(netdev); -+ tasklet_disable(&tp->tx_tl); -+ napi_disable(napi); -+ tp->rtl_ops.disable(tp); -+ napi_enable(napi); -+ tasklet_enable(&tp->tx_tl); -+ netif_info(tp, link, netdev, "carrier off\n"); -+ } -+ } -+} -+ -+static void rtl_work_func_t(struct work_struct *work) -+{ -+ struct r8152 *tp = container_of(work, struct r8152, schedule.work); -+ -+ /* If the device is unplugged or !netif_running(), the workqueue -+ * doesn't need to wake the device, and could return directly. -+ */ -+ if (test_bit(RTL8152_UNPLUG, &tp->flags) || !netif_running(tp->netdev)) -+ return; -+ -+ if (usb_autopm_get_interface(tp->intf) < 0) -+ return; -+ -+ if (!test_bit(WORK_ENABLE, &tp->flags)) -+ goto out1; -+ -+ if (!mutex_trylock(&tp->control)) { -+ schedule_delayed_work(&tp->schedule, 0); -+ goto out1; -+ } -+ -+ if (test_and_clear_bit(RTL8152_LINK_CHG, &tp->flags)) -+ set_carrier(tp); -+ -+ if (test_and_clear_bit(RTL8152_SET_RX_MODE, &tp->flags)) -+ _rtl8152_set_rx_mode(tp->netdev); -+ -+ /* don't schedule tasket before linking */ -+ if (test_and_clear_bit(SCHEDULE_TASKLET, &tp->flags) && -+ netif_carrier_ok(tp->netdev)) -+ tasklet_schedule(&tp->tx_tl); - - mutex_unlock(&tp->control); - -+out1: - usb_autopm_put_interface(tp->intf); --#ifdef CONFIG_PM_SLEEP -- tp->pm_notifier.notifier_call = rtl_notifier; -- register_pm_notifier(&tp->pm_notifier); --#endif -- return 0; -+} - --out_unlock: -+static void rtl_hw_phy_work_func_t(struct work_struct *work) -+{ -+ struct r8152 *tp = container_of(work, struct r8152, hw_phy_work.work); -+ -+ if (test_bit(RTL8152_UNPLUG, &tp->flags)) -+ return; -+ -+ if (usb_autopm_get_interface(tp->intf) < 0) -+ return; -+ -+ mutex_lock(&tp->control); -+ -+ if (rtl8152_request_firmware(tp) == -ENODEV && tp->rtl_fw.retry) { -+ tp->rtl_fw.retry = false; -+ tp->rtl_fw.fw = NULL; -+ -+ /* Delay execution in case request_firmware() is not ready yet. -+ */ -+ queue_delayed_work(system_long_wq, &tp->hw_phy_work, HZ * 10); -+ goto ignore_once; -+ } -+ -+ tp->rtl_ops.hw_phy_cfg(tp); -+ -+ rtl8152_set_speed(tp, tp->autoneg, tp->speed, tp->duplex, -+ tp->advertising); -+ -+ignore_once: - mutex_unlock(&tp->control); -+ - usb_autopm_put_interface(tp->intf); --out_free: -- free_all_mem(tp); --out: -- return res; - } - --static int rtl8152_close(struct net_device *netdev) -+#ifdef CONFIG_PM_SLEEP -+static int rtl_notifier(struct notifier_block *nb, unsigned long action, -+ void *data) - { -- struct r8152 *tp = netdev_priv(netdev); -- int res = 0; -+ struct r8152 *tp = container_of(nb, struct r8152, pm_notifier); - --#ifdef CONFIG_PM_SLEEP -- unregister_pm_notifier(&tp->pm_notifier); --#endif -- tasklet_disable(&tp->tx_tl); -- clear_bit(WORK_ENABLE, &tp->flags); -- usb_kill_urb(tp->intr_urb); -- cancel_delayed_work_sync(&tp->schedule); -- napi_disable(&tp->napi); -- netif_stop_queue(netdev); -+ switch (action) { -+ case PM_HIBERNATION_PREPARE: -+ case PM_SUSPEND_PREPARE: -+ usb_autopm_get_interface(tp->intf); -+ break; - -- res = usb_autopm_get_interface(tp->intf); -- if (res < 0 || test_bit(RTL8152_UNPLUG, &tp->flags)) { -+ case PM_POST_HIBERNATION: -+ case PM_POST_SUSPEND: -+ usb_autopm_put_interface(tp->intf); -+ break; -+ -+ case PM_POST_RESTORE: -+ case PM_RESTORE_PREPARE: -+ default: -+ break; -+ } -+ -+ return NOTIFY_DONE; -+} -+#endif -+ -+static int rtl8152_open(struct net_device *netdev) -+{ -+ struct r8152 *tp = netdev_priv(netdev); -+ int res = 0; -+ -+ if (work_busy(&tp->hw_phy_work.work) & WORK_BUSY_PENDING) { -+ cancel_delayed_work_sync(&tp->hw_phy_work); -+ rtl_hw_phy_work_func_t(&tp->hw_phy_work.work); -+ } -+ -+ res = alloc_all_mem(tp); -+ if (res) -+ goto out; -+ -+ res = usb_autopm_get_interface(tp->intf); -+ if (res < 0) -+ goto out_free; -+ -+ mutex_lock(&tp->control); -+ -+ tp->rtl_ops.up(tp); -+ -+ netif_carrier_off(netdev); -+ netif_start_queue(netdev); -+ set_bit(WORK_ENABLE, &tp->flags); -+ -+ res = usb_submit_urb(tp->intr_urb, GFP_KERNEL); -+ if (res) { -+ if (res == -ENODEV) -+ netif_device_detach(tp->netdev); -+ netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n", -+ res); -+ goto out_unlock; -+ } -+ napi_enable(&tp->napi); -+ tasklet_enable(&tp->tx_tl); -+ -+ mutex_unlock(&tp->control); -+ -+ usb_autopm_put_interface(tp->intf); -+#ifdef CONFIG_PM_SLEEP -+ tp->pm_notifier.notifier_call = rtl_notifier; -+ register_pm_notifier(&tp->pm_notifier); -+#endif -+ return 0; -+ -+out_unlock: -+ mutex_unlock(&tp->control); -+ usb_autopm_put_interface(tp->intf); -+out_free: -+ free_all_mem(tp); -+out: -+ return res; -+} -+ -+static int rtl8152_close(struct net_device *netdev) -+{ -+ struct r8152 *tp = netdev_priv(netdev); -+ int res = 0; -+ -+#ifdef CONFIG_PM_SLEEP -+ unregister_pm_notifier(&tp->pm_notifier); -+#endif -+ tasklet_disable(&tp->tx_tl); -+ clear_bit(WORK_ENABLE, &tp->flags); -+ usb_kill_urb(tp->intr_urb); -+ cancel_delayed_work_sync(&tp->schedule); -+ napi_disable(&tp->napi); -+ netif_stop_queue(netdev); -+ -+ res = usb_autopm_get_interface(tp->intf); -+ if (res < 0 || test_bit(RTL8152_UNPLUG, &tp->flags)) { - rtl_drop_queued_tx(tp); - rtl_stop_rx(tp); - } else { -@@ -5281,95 +6760,775 @@ static int rtl8152_close(struct net_device *netdev) - - tp->rtl_ops.down(tp); - -- mutex_unlock(&tp->control); -+ mutex_unlock(&tp->control); -+ } -+ -+ if (!res) -+ usb_autopm_put_interface(tp->intf); -+ -+ free_all_mem(tp); -+ -+ return res; -+} -+ -+static void rtl_tally_reset(struct r8152 *tp) -+{ -+ u32 ocp_data; -+ -+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY); -+ ocp_data |= TALLY_RESET; -+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data); -+} -+ -+static void r8152b_init(struct r8152 *tp) -+{ -+ u32 ocp_data; -+ u16 data; -+ -+ if (test_bit(RTL8152_UNPLUG, &tp->flags)) -+ return; -+ -+ data = r8152_mdio_read(tp, MII_BMCR); -+ if (data & BMCR_PDOWN) { -+ data &= ~BMCR_PDOWN; -+ r8152_mdio_write(tp, MII_BMCR, data); -+ } -+ -+ r8152_aldps_en(tp, false); -+ -+ if (tp->version == RTL_VER_01) { -+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE); -+ ocp_data &= ~LED_MODE_MASK; -+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data); -+ } -+ -+ r8152_power_cut_en(tp, false); -+ -+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); -+ ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH; -+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data); -+ ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL); -+ ocp_data &= ~MCU_CLK_RATIO_MASK; -+ ocp_data |= MCU_CLK_RATIO | D3_CLK_GATED_EN; -+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ocp_data); -+ ocp_data = GPHY_STS_MSK | SPEED_DOWN_MSK | -+ SPDWN_RXDV_MSK | SPDWN_LINKCHG_MSK; -+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_GPHY_INTR_IMR, ocp_data); -+ -+ rtl_tally_reset(tp); -+ -+ /* enable 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); -+} -+ -+static void r8153_init(struct r8152 *tp) -+{ -+ u32 ocp_data; -+ u16 data; -+ int i; -+ -+ if (test_bit(RTL8152_UNPLUG, &tp->flags)) -+ return; -+ -+ r8153_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)) -+ break; -+ } -+ -+ data = r8153_phy_status(tp, 0); -+ -+ if (tp->version == RTL_VER_03 || tp->version == RTL_VER_04 || -+ tp->version == RTL_VER_05) -+ ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L); -+ -+ 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); -+ -+ if (tp->version == RTL_VER_04) { -+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_SSPHYLINK2); -+ ocp_data &= ~pwd_dn_scale_mask; -+ ocp_data |= pwd_dn_scale(96); -+ ocp_write_word(tp, MCU_TYPE_USB, USB_SSPHYLINK2, ocp_data); -+ -+ ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY); -+ ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND; -+ ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data); -+ } else if (tp->version == RTL_VER_05) { -+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0); -+ ocp_data &= ~ECM_ALDPS; -+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0, ocp_data); -+ -+ ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1); -+ if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0) -+ ocp_data &= ~DYNAMIC_BURST; -+ else -+ ocp_data |= DYNAMIC_BURST; -+ ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1, ocp_data); -+ } else if (tp->version == RTL_VER_06) { -+ ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1); -+ if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0) -+ ocp_data &= ~DYNAMIC_BURST; -+ else -+ ocp_data |= DYNAMIC_BURST; -+ ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1, ocp_data); -+ -+ r8153_queue_wake(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); -+ } -+ -+ ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY2); -+ ocp_data |= EP4_FULL_FC; -+ ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY2, ocp_data); -+ -+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL); -+ ocp_data &= ~TIMER11_EN; -+ ocp_write_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL, ocp_data); -+ -+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE); -+ ocp_data &= ~LED_MODE_MASK; -+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data); -+ -+ ocp_data = FIFO_EMPTY_1FB | ROK_EXIT_LPM; -+ if (tp->version == RTL_VER_04 && tp->udev->speed < USB_SPEED_SUPER) -+ ocp_data |= LPM_TIMER_500MS; -+ else -+ ocp_data |= LPM_TIMER_500US; -+ ocp_write_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL, ocp_data); -+ -+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2); -+ ocp_data &= ~SEN_VAL_MASK; -+ ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE; -+ ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data); -+ -+ ocp_write_word(tp, MCU_TYPE_USB, USB_CONNECT_TIMER, 0x0001); -+ -+ 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); -+ -+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6); -+ ocp_data |= LANWAKE_CLR_EN; -+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6, ocp_data); -+ -+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_LWAKE_CTRL_REG); -+ ocp_data &= ~LANWAKE_PIN; -+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_LWAKE_CTRL_REG, ocp_data); -+ -+ /* rx aggregation */ -+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); -+ ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); -+ if (test_bit(DELL_TB_RX_AGG_BUG, &tp->flags)) -+ ocp_data |= RX_AGG_DISABLE; -+ -+ ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); -+ -+ rtl_tally_reset(tp); -+ -+ switch (tp->udev->speed) { -+ case USB_SPEED_SUPER: -+ case USB_SPEED_SUPER_PLUS: -+ tp->coalesce = COALESCE_SUPER; -+ break; -+ case USB_SPEED_HIGH: -+ tp->coalesce = COALESCE_HIGH; -+ break; -+ default: -+ tp->coalesce = COALESCE_SLOW; -+ break; -+ } -+} -+ -+static void r8153b_init(struct r8152 *tp) -+{ -+ u32 ocp_data; -+ u16 data; -+ int i; -+ -+ if (test_bit(RTL8152_UNPLUG, &tp->flags)) -+ return; -+ -+ 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)) -+ break; -+ } -+ -+ 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); -+ r8153b_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); -+ -+ if (tp->udev->speed >= USB_SPEED_SUPER) -+ r8153b_u1u2en(tp, true); -+ -+ usb_enable_lpm(tp->udev); -+ -+ /* MAC clock speed down */ -+ 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; -+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data); -+ -+ if (tp->version == RTL_VER_09) { -+ /* Disable Test IO for 32QFN */ -+ if (ocp_read_byte(tp, MCU_TYPE_PLA, 0xdc00) & BIT(5)) { -+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); -+ ocp_data |= TEST_IO_OFF; -+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data); -+ } - } - -- if (!res) -- usb_autopm_put_interface(tp->intf); -- -- free_all_mem(tp); -+ set_bit(GREEN_ETHERNET, &tp->flags); - -- return res; --} -+ /* 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); - --static void rtl_tally_reset(struct r8152 *tp) --{ -- u32 ocp_data; -+ rtl_tally_reset(tp); - -- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY); -- ocp_data |= TALLY_RESET; -- ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data); -+ tp->coalesce = 15000; /* 15 us */ - } - --static void r8152b_init(struct r8152 *tp) -+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); - } - -- r8152_aldps_en(tp, false); -+ data = r8153_phy_status(tp, PHY_STAT_LAN_ON); - -- if (tp->version == RTL_VER_01) { -- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE); -- ocp_data &= ~LED_MODE_MASK; -- ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data); -- } -+ r8153_u2p3en(tp, false); - -- r8152_power_cut_en(tp, false); -+ /* MSC timer = 0xfff * 8ms = 32760 ms */ -+ ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff); - -- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); -- ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH; -- ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data); -- ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL); -- ocp_data &= ~MCU_CLK_RATIO_MASK; -- ocp_data |= MCU_CLK_RATIO | D3_CLK_GATED_EN; -- ocp_write_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ocp_data); -- ocp_data = GPHY_STS_MSK | SPEED_DOWN_MSK | -- SPDWN_RXDV_MSK | SPDWN_LINKCHG_MSK; -- ocp_write_word(tp, MCU_TYPE_PLA, PLA_GPHY_INTR_IMR, ocp_data); -+ r8153b_power_cut_en(tp, false); -+ r8153c_ups_en(tp, false); -+ r8153_queue_wake(tp, false); -+ rtl_runtime_suspend_enable(tp, false); - -- rtl_tally_reset(tp); -+ 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; - -- /* enable rx aggregation */ -+ 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 r8153_init(struct r8152 *tp) -+static void r8156_hw_phy_cfg(struct r8152 *tp) - { - u32 ocp_data; - u16 data; -- int i; - -- if (test_bit(RTL8152_UNPLUG, &tp->flags)) -- return; -+ 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); -+ } - -- r8153_u1u2en(tp, false); -+ data = r8153_phy_status(tp, 0); -+ switch (data) { -+ case PHY_STAT_EXT_INIT: -+ rtl8152_apply_firmware(tp, true); - -- for (i = 0; i < 500; i++) { -- if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) & -- AUTOLOAD_DONE) -- break; -+ 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; -+ } - -- msleep(20); -- if (test_bit(RTL8152_UNPLUG, &tp->flags)) -- 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); - -- if (tp->version == RTL_VER_03 || tp->version == RTL_VER_04 || -- tp->version == RTL_VER_05) -- ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L); -+ 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) { -@@ -5377,119 +7536,450 @@ static void r8153_init(struct r8152 *tp) - 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); - -- r8153_u2p3en(tp, false); -+ 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); - -- if (tp->version == RTL_VER_04) { -- ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_SSPHYLINK2); -- ocp_data &= ~pwd_dn_scale_mask; -- ocp_data |= pwd_dn_scale(96); -- ocp_write_word(tp, MCU_TYPE_USB, USB_SSPHYLINK2, 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); - -- ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY); -- ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND; -- ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data); -- } else if (tp->version == RTL_VER_05) { -- ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0); -- ocp_data &= ~ECM_ALDPS; -- ocp_write_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0, ocp_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; -+ } - -- ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1); -- if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0) -- ocp_data &= ~DYNAMIC_BURST; -- else -- ocp_data |= DYNAMIC_BURST; -- ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1, ocp_data); -- } else if (tp->version == RTL_VER_06) { -- ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1); -- if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0) -- ocp_data &= ~DYNAMIC_BURST; -- else -- ocp_data |= DYNAMIC_BURST; -- ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1, ocp_data); -+ 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; - -- r8153_queue_wake(tp, false); -+ msleep(20); -+ if (test_bit(RTL8152_UNPLUG, &tp->flags)) -+ return; -+ } - -- 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); -+ 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); - } - -- ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY2); -- ocp_data |= EP4_FULL_FC; -- ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY2, ocp_data); -+ data = r8152_mdio_read(tp, MII_BMCR); -+ if (data & BMCR_PDOWN) { -+ data &= ~BMCR_PDOWN; -+ r8152_mdio_write(tp, MII_BMCR, data); -+ } - -- ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL); -- ocp_data &= ~TIMER11_EN; -- ocp_write_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL, ocp_data); -+ 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_LED_FEATURE); -- ocp_data &= ~LED_MODE_MASK; -- ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data); -+ r8153_u2p3en(tp, false); - -- ocp_data = FIFO_EMPTY_1FB | ROK_EXIT_LPM; -- if (tp->version == RTL_VER_04 && tp->udev->speed < USB_SPEED_SUPER) -- ocp_data |= LPM_TIMER_500MS; -- else -- ocp_data |= LPM_TIMER_500US; -- ocp_write_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL, ocp_data); -+ /* MSC timer = 0xfff * 8ms = 32760 ms */ -+ ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff); - -- ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2); -- ocp_data &= ~SEN_VAL_MASK; -- ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE; -- ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data); -+ /* U1/U2/L1 idle timer. 500 us */ -+ ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500); - -- ocp_write_word(tp, MCU_TYPE_USB, USB_CONNECT_TIMER, 0x0001); -+ r8153b_power_cut_en(tp, false); -+ r8156_ups_en(tp, false); -+ r8153_queue_wake(tp, false); -+ rtl_runtime_suspend_enable(tp, false); - -- /* 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); -+ if (tp->udev->speed >= USB_SPEED_SUPER) -+ r8153b_u1u2en(tp, true); - -- r8153_power_cut_en(tp, false); -- rtl_runtime_suspend_enable(tp, false); -- r8153_u1u2en(tp, true); - usb_enable_lpm(tp->udev); - -- ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6); -- ocp_data |= LANWAKE_CLR_EN; -- ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6, ocp_data); -+ r8156_mac_clk_spd(tp, true); - -- ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_LWAKE_CTRL_REG); -- ocp_data &= ~LANWAKE_PIN; -- ocp_write_byte(tp, MCU_TYPE_PLA, PLA_LWAKE_CTRL_REG, 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_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); -- if (test_bit(DELL_TB_RX_AGG_BUG, &tp->flags)) -- ocp_data |= RX_AGG_DISABLE; -- - 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); - -- switch (tp->udev->speed) { -- case USB_SPEED_SUPER: -- case USB_SPEED_SUPER_PLUS: -- tp->coalesce = COALESCE_SUPER; -- break; -- case USB_SPEED_HIGH: -- tp->coalesce = COALESCE_HIGH; -- break; -- default: -- tp->coalesce = COALESCE_SLOW; -- break; -- } -+ tp->coalesce = 15000; /* 15 us */ - } - --static void r8153b_init(struct r8152 *tp) -+static void r8156b_init(struct r8152 *tp) - { - u32 ocp_data; - u16 data; -@@ -5498,8 +7988,31 @@ static void r8153b_init(struct r8152 *tp) - 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) -@@ -5507,10 +8020,19 @@ static void r8153b_init(struct r8152 *tp) - - msleep(20); - if (test_bit(RTL8152_UNPLUG, &tp->flags)) -- break; -+ 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) { -@@ -5529,39 +8051,50 @@ static void r8153b_init(struct r8152 *tp) - ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500); - - r8153b_power_cut_en(tp, false); -- r8153b_ups_en(tp, false); -+ r8156_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); -- -- 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); -+ 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); - -- if (tp->version == RTL_VER_09) { -- /* Disable Test IO for 32QFN */ -- if (ocp_read_byte(tp, MCU_TYPE_PLA, 0xdc00) & BIT(5)) { -- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); -- ocp_data |= TEST_IO_OFF; -- ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, 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); - -@@ -5575,6 +8108,39 @@ static void r8153b_init(struct r8152 *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_cache0->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); -@@ -5725,6 +8291,9 @@ static int rtl8152_runtime_suspend(struct r8152 *tp) - 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(); - -@@ -5935,6 +8504,22 @@ int rtl8152_get_link_ksettings(struct net_device *netdev, - - 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); -@@ -5978,6 +8563,10 @@ static int rtl8152_set_link_ksettings(struct net_device *dev, - 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, -@@ -6124,6 +8713,11 @@ rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *edata) - 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; -@@ -6146,6 +8740,11 @@ rtl_ethtool_set_eee(struct net_device *net, struct ethtool_eee *edata) - 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; -@@ -6434,12 +9033,21 @@ static int rtl8152_change_mtu(struct net_device *dev, int new_mtu) - 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); -@@ -6528,6 +9136,7 @@ static int rtl_ops_init(struct r8152 *tp) - 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 -@@ -6549,6 +9158,68 @@ static int rtl_ops_init(struct r8152 *tp) - 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; -@@ -6556,7 +9227,7 @@ static int rtl_ops_init(struct r8152 *tp) - - default: - ret = -ENODEV; -- netif_err(tp, probe, tp->netdev, "Unknown Device\n"); -+ dev_err(&tp->intf->dev, "Unknown Device\n"); - break; - } - -@@ -6567,11 +9238,17 @@ static int rtl_ops_init(struct r8152 *tp) - #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) - { -@@ -6597,6 +9274,19 @@ static int rtl_fw_init(struct r8152 *tp) - 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; - } -@@ -6604,7 +9294,7 @@ static int rtl_fw_init(struct r8152 *tp) - 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; -@@ -6652,6 +9342,27 @@ static u8 rtl_get_version(struct usb_interface *intf) - 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); -@@ -6662,12 +9373,13 @@ static u8 rtl_get_version(struct usb_interface *intf) - - 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; -@@ -6675,10 +9387,8 @@ static int rtl8152_probe(struct usb_interface *intf, - 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; -@@ -6719,7 +9429,7 @@ static int rtl8152_probe(struct usb_interface *intf, - 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; -@@ -6763,12 +9473,29 @@ static int rtl8152_probe(struct usb_interface *intf, - /* 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; - } - -@@ -6784,7 +9511,13 @@ static int rtl8152_probe(struct usb_interface *intf, - 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; -@@ -6808,11 +9541,15 @@ static int rtl8152_probe(struct usb_interface *intf, - 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; - } - -@@ -6844,7 +9581,8 @@ static void rtl8152_disconnect(struct usb_interface *intf) - 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); - } -@@ -6864,13 +9602,28 @@ static void rtl8152_disconnect(struct usb_interface *intf) - .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 --git a/drivers/net/usb/r8153_ecm.c b/drivers/net/usb/r8153_ecm.c -new file mode 100644 -index 000000000000..2c3fabd38b16 ---- /dev/null -+++ b/drivers/net/usb/r8153_ecm.c -@@ -0,0 +1,162 @@ -+// 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"); + if (!buf) { diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c -index 465e11dcdf12..2c7c91b4d418 100644 +index a530f20ee257..340a877eaf69 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c -@@ -50,6 +50,7 @@ - #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; -@@ -67,6 +68,18 @@ static bool turbo_mode = true; +@@ -79,6 +79,18 @@ static bool turbo_mode = true; module_param(turbo_mode, bool, 0644); MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); @@ -96384,75 +144241,47 @@ +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) + static int __must_check smsc95xx_read_reg(struct usbnet *dev, u32 index, + u32 *data) { -@@ -753,6 +766,53 @@ static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) +@@ -801,6 +813,21 @@ static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) 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) ++static int smsc95xx_macaddr_param(struct usbnet *dev, struct net_device *nd) +{ -+ int i, j, got_num, num; -+ u8 mtblMAC_ADDR_LEN; -+ -+ if (macaddr0 == ':') -+ return 0; ++ u8 mtblETH_ALEN; + -+ i = 0; -+ j = 0; -+ num = 0; -+ got_num = 0; -+ while (j < MAC_ADDR_LEN) { -+ if (macaddri && macaddri != ':') { -+ got_num++; -+ if ('0' <= macaddri && macaddri <= '9') -+ num = num * 16 + macaddri - '0'; -+ else if ('A' <= macaddri && macaddri <= 'F') -+ num = num * 16 + 10 + macaddri - 'A'; -+ else if ('a' <= macaddri && macaddri <= 'f') -+ num = num * 16 + 10 + macaddri - 'a'; -+ else -+ break; -+ i++; -+ } else if (got_num == 2) { -+ mtblj++ = (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", mtbl0, mtbl1, mtbl2, -+ mtbl3, mtbl4, mtbl5); -+ for (i = 0; i < MAC_ADDR_LEN; i++) -+ dev_maci = mtbli; -+ return 1; -+ } else { -+ return 0; -+ } ++ if (mac_pton(macaddr, mtbl)) { ++ netif_dbg(dev, ifup, dev->net, ++ "Overriding MAC address with: %pM\n", mtbl); ++ dev_addr_mod(nd, 0, mtbl, ETH_ALEN); ++ return 0; ++ } else { ++ return -EINVAL; ++ } +} + static void smsc95xx_init_mac_address(struct usbnet *dev) { - /* maybe the boot loader passed the MAC address in devicetree */ -@@ -775,6 +835,10 @@ static void smsc95xx_init_mac_address(struct usbnet *dev) + u8 addrETH_ALEN; +@@ -824,6 +851,14 @@ static void smsc95xx_init_mac_address(struct usbnet *dev) } } + /* Check module parameters */ -+ if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr)) -+ return; ++ if (smsc95xx_macaddr_param(dev, dev->net) == 0) { ++ if (is_valid_ether_addr(dev->net->dev_addr)) { ++ netif_dbg(dev, ifup, dev->net, "MAC address read from module parameter\n"); ++ return; ++ } ++ } + /* no useful static MAC address found. generate a random one */ eth_hw_addr_random(dev->net); netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n"); -@@ -901,13 +965,13 @@ static int smsc95xx_reset(struct usbnet *dev) +@@ -932,13 +967,13 @@ static int smsc95xx_reset(struct usbnet *dev) if (!turbo_mode) { burst_cap = 0; @@ -96471,7 +144300,7 @@ } netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld\n", -@@ -1830,7 +1894,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +@@ -1870,7 +1905,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) if (dev->net->features & NETIF_F_RXCSUM) smsc95xx_rx_csum_offload(skb); skb_trim(skb, skb->len - 4); /* remove fcs */ @@ -96481,7 +144310,7 @@ return 1; } -@@ -1848,7 +1913,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +@@ -1888,7 +1924,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) if (dev->net->features & NETIF_F_RXCSUM) smsc95xx_rx_csum_offload(ax_skb); skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ @@ -96492,36 +144321,20 @@ usbnet_skb_return(dev, ax_skb); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h -index 3f5da3bb6aa5..ba3c58caac9f 100644 +index fe31051a9e11..8c3613ff23f5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h -@@ -78,7 +78,7 @@ struct brcmf_bus_ops { - 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); - }; -@@ -223,7 +223,14 @@ static inline - 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); - } +@@ -298,7 +298,7 @@ void brcmf_rx_event(struct device *dev, struct sk_buff *rxp); - static inline + int brcmf_alloc(struct device *dev, struct brcmf_mp_device *settings); + /* Indication from bus module regarding presence/insertion of dongle. */ +-int brcmf_attach(struct device *dev); ++int brcmf_attach(struct device *dev, bool start_bus); + /* Indication from bus module regarding removal/absence of dongle */ + void brcmf_detach(struct device *dev); + void brcmf_free(struct device *dev); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c -index c2b6e5c966d0..e51b42b547be 100644 +index 6049f9a761d9..07f07373fbb7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -9,6 +9,7 @@ @@ -96532,7 +144345,134 @@ #include <net/cfg80211.h> #include <net/netlink.h> #include <uapi/linux/if_arp.h> -@@ -2940,7 +2941,7 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, +@@ -88,6 +89,9 @@ + + #define BRCMF_PS_MAX_TIMEOUT_MS 2000 + ++#define MGMT_AUTH_FRAME_DWELL_TIME 4000 ++#define MGMT_AUTH_FRAME_WAIT_TIME (MGMT_AUTH_FRAME_DWELL_TIME + 100) ++ + /* Dump obss definitions */ + #define ACS_MSRMNT_DELAY 80 + #define CHAN_NOISE_DUMMY (-80) +@@ -1957,14 +1961,18 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev, + s32 val = 0; + s32 err = 0; + +- if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) ++ if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) { + val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; +- else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) +- val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; +- else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_3) ++ } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) { ++ if (sme->crypto.akm_suites0 == WLAN_AKM_SUITE_SAE) ++ val = WPA3_AUTH_SAE_PSK; ++ else ++ val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; ++ } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_3) { + val = WPA3_AUTH_SAE_PSK; +- else ++ } else { + val = WPA_AUTH_DISABLED; ++ } + brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val); + err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", val); + if (err) { +@@ -2229,7 +2237,7 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) + brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp); + + skip_mfp_config: +- brcmf_dbg(CONN, "setting wpa_auth to %d\n", val); ++ brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val); + err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val); + if (err) { + bphy_err(drvr, "could not set wpa_auth (%d)\n", err); +@@ -2474,44 +2482,52 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, + goto done; + } + +- if (sme->crypto.psk && +- profile->use_fwsup != BRCMF_PROFILE_FWSUP_SAE) { +- if (WARN_ON(profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE)) { +- err = -EINVAL; +- goto done; ++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP)) { ++ if (sme->crypto.psk) { ++ if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_SAE) { ++ if (WARN_ON(profile->use_fwsup != ++ BRCMF_PROFILE_FWSUP_NONE)) { ++ err = -EINVAL; ++ goto done; ++ } ++ brcmf_dbg(INFO, "using PSK offload\n"); ++ profile->use_fwsup = BRCMF_PROFILE_FWSUP_PSK; ++ } ++ } else if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_1X) { ++ profile->use_fwsup = BRCMF_PROFILE_FWSUP_NONE; + } +- brcmf_dbg(INFO, "using PSK offload\n"); +- profile->use_fwsup = BRCMF_PROFILE_FWSUP_PSK; +- } + +- if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE) { +- /* enable firmware supplicant for this interface */ +- err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1); +- if (err < 0) { +- bphy_err(drvr, "failed to enable fw supplicant\n"); +- goto done; ++ if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE) { ++ /* enable firmware supplicant for this interface */ ++ err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1); ++ if (err < 0) { ++ bphy_err(drvr, "failed to enable fw supplicant\n"); ++ goto done; ++ } ++ } else { ++ err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 0); + } +- } + +- if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) +- err = brcmf_set_pmk(ifp, sme->crypto.psk, +- BRCMF_WSEC_MAX_PSK_LEN); +- else if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_SAE) { +- /* clean up user-space RSNE */ +- err = brcmf_fil_iovar_data_set(ifp, "wpaie", NULL, 0); +- if (err) { +- bphy_err(drvr, "failed to clean up user-space RSNE\n"); +- goto done; +- } +- err = brcmf_set_sae_password(ifp, sme->crypto.sae_pwd, +- sme->crypto.sae_pwd_len); +- if (!err && sme->crypto.psk) ++ if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) { + err = brcmf_set_pmk(ifp, sme->crypto.psk, + BRCMF_WSEC_MAX_PSK_LEN); +- } +- if (err) +- goto done; ++ } else if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_SAE) { ++ /* clean up user-space RSNE */ ++ err = brcmf_fil_iovar_data_set(ifp, "wpaie", NULL, 0); ++ if (err) { ++ bphy_err(drvr, "failed to clean up user-space RSNE\n"); ++ goto done; ++ } + ++ err = brcmf_set_sae_password(ifp, sme->crypto.sae_pwd, ++ sme->crypto.sae_pwd_len); ++ if (!err && sme->crypto.psk) ++ err = brcmf_set_pmk(ifp, sme->crypto.psk, ++ BRCMF_WSEC_MAX_PSK_LEN); ++ } ++ if (err) ++ goto done; ++ } + /* Join with specific BSSID and cached SSID + * If SSID is zero join based on BSSID only + */ +@@ -3312,7 +3328,7 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, brcmf_dbg(INFO, "Do not enable power save for P2P clients\n"); pm = PM_OFF; } @@ -96541,7 +144481,7 @@ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm); if (err) { -@@ -2950,6 +2951,7 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, +@@ -3322,6 +3338,7 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, bphy_err(drvr, "error (%d)\n", err); } @@ -96549,46 +144489,308 @@ err = brcmf_fil_iovar_int_set(ifp, "pm2_sleep_ret", min_t(u32, timeout, BRCMF_PS_MAX_TIMEOUT_MS)); if (err) -@@ -7356,12 +7358,18 @@ static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha22, - struct brcmfmac_pd_cc *country_codes; - struct brcmfmac_pd_cc_entry *cc; - s32 found_index; -+ char ccodeBRCMF_COUNTRY_BUF_SZ; -+ int rev; - int i; +@@ -5519,9 +5536,12 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + s32 ie_len; + struct brcmf_fil_action_frame_le *action_frame; + struct brcmf_fil_af_params_le *af_params; +- bool ack; ++ bool ack = false; + s32 chan_nr; + u32 freq; ++ struct brcmf_mf_params_le *mf_params; ++ u32 mf_params_len; ++ s32 timeout; + + brcmf_dbg(TRACE, "Enter\n"); -+ memcpy(ccode, alpha2, sizeof(ccode)); -+ rev = -1; +@@ -5602,6 +5622,71 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack, + GFP_KERNEL); + kfree(af_params); ++ } else if (ieee80211_is_auth(mgmt->frame_control)) { ++ reinit_completion(&vif->mgmt_tx); ++ clear_bit(BRCMF_MGMT_TX_ACK, &vif->mgmt_tx_status); ++ clear_bit(BRCMF_MGMT_TX_NOACK, &vif->mgmt_tx_status); ++ clear_bit(BRCMF_MGMT_TX_OFF_CHAN_COMPLETED, ++ &vif->mgmt_tx_status); ++ ++ mf_params_len = offsetof(struct brcmf_mf_params_le, data) + ++ (len - DOT11_MGMT_HDR_LEN); ++ mf_params = kzalloc(mf_params_len, GFP_KERNEL); ++ if (!mf_params) { ++ err = -ENOMEM; ++ goto exit; ++ } + - 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; - } ++ mf_params->dwell_time = cpu_to_le32(MGMT_AUTH_FRAME_DWELL_TIME); ++ mf_params->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN); ++ mf_params->frame_control = mgmt->frame_control; ++ ++ if (chan) ++ freq = chan->center_freq; ++ else ++ brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL, ++ &freq); ++ chan_nr = ieee80211_frequency_to_channel(freq); ++ mf_params->channel = cpu_to_le32(chan_nr); ++ memcpy(&mf_params->da0, &mgmt->da0, ETH_ALEN); ++ memcpy(&mf_params->bssid0, &mgmt->bssid0, ETH_ALEN); ++ mf_params->packet_id = cpu_to_le32(*cookie); ++ memcpy(mf_params->data, &bufDOT11_MGMT_HDR_LEN, ++ le16_to_cpu(mf_params->len)); ++ ++ brcmf_dbg(TRACE, "Auth frame, cookie=%d, fc=%04x, len=%d, channel=%d\n", ++ le32_to_cpu(mf_params->packet_id), ++ le16_to_cpu(mf_params->frame_control), ++ le16_to_cpu(mf_params->len), ++ le32_to_cpu(mf_params->channel)); ++ ++ vif->mgmt_tx_id = le32_to_cpu(mf_params->packet_id); ++ set_bit(BRCMF_MGMT_TX_SEND_FRAME, &vif->mgmt_tx_status); ++ ++ err = brcmf_fil_bsscfg_data_set(vif->ifp, "mgmt_frame", ++ mf_params, mf_params_len); ++ if (err) { ++ bphy_err(drvr, "Failed to send Auth frame: err=%d\n", ++ err); ++ goto tx_status; ++ } ++ ++ timeout = ++ wait_for_completion_timeout(&vif->mgmt_tx, ++ MGMT_AUTH_FRAME_WAIT_TIME); ++ if (test_bit(BRCMF_MGMT_TX_ACK, &vif->mgmt_tx_status)) { ++ brcmf_dbg(TRACE, "TX Auth frame operation is success\n"); ++ ack = true; ++ } else { ++ bphy_err(drvr, "TX Auth frame operation is failed: status=%ld)\n", ++ vif->mgmt_tx_status); ++ } ++ ++tx_status: ++ cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack, ++ GFP_KERNEL); ++ kfree(mf_params); ++ + } else { + brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control); + brcmf_dbg_hex_dump(true, buf, len, "payload, len=%zu\n", len); +@@ -5925,6 +6010,40 @@ static int brcmf_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev, + return brcmf_set_pmk(ifp, NULL, 0); + } - if ((alpha20 == ccreq->country_abbrev0) && -@@ -7385,10 +7393,14 @@ static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha22, - brcmf_dbg(TRACE, "No country code match found\n"); - return -EINVAL; ++static int ++brcmf_cfg80211_external_auth(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_external_auth_params *params) ++{ ++ struct brcmf_if *ifp; ++ struct brcmf_pub *drvr; ++ struct brcmf_auth_req_status_le auth_status; ++ int ret = 0; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ ifp = netdev_priv(dev); ++ drvr = ifp->drvr; ++ if (params->status == WLAN_STATUS_SUCCESS) { ++ auth_status.flags = cpu_to_le16(BRCMF_EXTAUTH_SUCCESS); ++ } else { ++ bphy_err(drvr, "External authentication failed: status=%d\n", ++ params->status); ++ auth_status.flags = cpu_to_le16(BRCMF_EXTAUTH_FAIL); ++ } ++ ++ memcpy(auth_status.peer_mac, params->bssid, ETH_ALEN); ++ auth_status.ssid_len = cpu_to_le32(min_t(u8, params->ssid.ssid_len, ++ IEEE80211_MAX_SSID_LEN)); ++ memcpy(auth_status.ssid, params->ssid.ssid, auth_status.ssid_len); ++ ++ ret = brcmf_fil_iovar_data_set(ifp, "auth_status", &auth_status, ++ sizeof(auth_status)); ++ if (ret < 0) ++ bphy_err(drvr, "auth_status iovar failed: ret=%d\n", ret); ++ ++ return ret; ++} ++ + static struct cfg80211_ops brcmf_cfg80211_ops = { + .add_virtual_intf = brcmf_cfg80211_add_iface, + .del_virtual_intf = brcmf_cfg80211_del_iface, +@@ -5972,6 +6091,7 @@ static struct cfg80211_ops brcmf_cfg80211_ops = { + .update_connect_params = brcmf_cfg80211_update_conn_params, + .set_pmk = brcmf_cfg80211_set_pmk, + .del_pmk = brcmf_cfg80211_del_pmk, ++ .external_auth = brcmf_cfg80211_external_auth, + }; + + struct cfg80211_ops *brcmf_cfg80211_get_ops(struct brcmf_mp_device *settings) +@@ -6018,6 +6138,7 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, + vif->mbss = mbss; } -- memset(ccreq, 0, sizeof(*ccreq)); -- ccreq->rev = cpu_to_le32(country_codes->tablefound_index.rev); -- memcpy(ccreq->ccode, country_codes->tablefound_index.cc, -+ rev = country_codes->tablefound_index.rev; -+ memcpy(ccode, country_codes->tablefound_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_abbrev0 = alpha20; - ccreq->country_abbrev1 = alpha21; - ccreq->country_abbrev2 = 0; -@@ -7403,31 +7415,45 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, + ++ init_completion(&vif->mgmt_tx); + list_add_tail(&vif->list, &cfg->vif_list); + return vif; + } +@@ -6709,6 +6830,122 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp, + return -EINVAL; + } + ++static s32 ++brcmf_notify_ext_auth_request(struct brcmf_if *ifp, ++ const struct brcmf_event_msg *e, void *data) ++{ ++ struct brcmf_pub *drvr = ifp->drvr; ++ struct cfg80211_external_auth_params params; ++ struct brcmf_auth_req_status_le *auth_req = ++ (struct brcmf_auth_req_status_le *)data; ++ s32 err = 0; ++ ++ brcmf_dbg(INFO, "Enter: event %s (%d) received\n", ++ brcmf_fweh_event_name(e->event_code), e->event_code); ++ ++ if (e->datalen < sizeof(*auth_req)) { ++ bphy_err(drvr, "Event %s (%d) data too small. Ignore\n", ++ brcmf_fweh_event_name(e->event_code), e->event_code); ++ return -EINVAL; ++ } ++ ++ memset(¶ms, 0, sizeof(params)); ++ params.action = NL80211_EXTERNAL_AUTH_START; ++ params.key_mgmt_suite = ntohl(WLAN_AKM_SUITE_SAE); ++ params.status = WLAN_STATUS_SUCCESS; ++ params.ssid.ssid_len = min_t(u32, 32, le32_to_cpu(auth_req->ssid_len)); ++ memcpy(params.ssid.ssid, auth_req->ssid, params.ssid.ssid_len); ++ memcpy(params.bssid, auth_req->peer_mac, ETH_ALEN); ++ ++ err = cfg80211_external_auth_request(ifp->ndev, ¶ms, GFP_ATOMIC); ++ if (err) ++ bphy_err(drvr, "Ext Auth request to supplicant failed (%d)\n", ++ err); ++ ++ return err; ++} ++ ++static s32 ++brcmf_notify_auth_frame_rx(struct brcmf_if *ifp, ++ const struct brcmf_event_msg *e, void *data) ++{ ++ struct brcmf_pub *drvr = ifp->drvr; ++ struct brcmf_cfg80211_info *cfg = drvr->config; ++ struct wireless_dev *wdev; ++ u32 mgmt_frame_len = e->datalen - sizeof(struct brcmf_rx_mgmt_data); ++ struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data; ++ u8 *frame = (u8 *)(rxframe + 1); ++ struct brcmu_chan ch; ++ struct ieee80211_mgmt *mgmt_frame; ++ s32 freq; ++ ++ brcmf_dbg(INFO, "Enter: event %s (%d) received\n", ++ brcmf_fweh_event_name(e->event_code), e->event_code); ++ ++ if (e->datalen < sizeof(*rxframe)) { ++ bphy_err(drvr, "Event %s (%d) data too small. Ignore\n", ++ brcmf_fweh_event_name(e->event_code), e->event_code); ++ return -EINVAL; ++ } ++ ++ wdev = &ifp->vif->wdev; ++ WARN_ON(!wdev); ++ ++ ch.chspec = be16_to_cpu(rxframe->chanspec); ++ cfg->d11inf.decchspec(&ch); ++ ++ mgmt_frame = kzalloc(mgmt_frame_len, GFP_KERNEL); ++ if (!mgmt_frame) ++ return -ENOMEM; ++ ++ mgmt_frame->frame_control = cpu_to_le16(IEEE80211_STYPE_AUTH); ++ memcpy(mgmt_frame->da, ifp->mac_addr, ETH_ALEN); ++ memcpy(mgmt_frame->sa, e->addr, ETH_ALEN); ++ brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mgmt_frame->bssid, ++ ETH_ALEN); ++ frame += offsetof(struct ieee80211_mgmt, u); ++ memcpy(&mgmt_frame->u, frame, ++ mgmt_frame_len - offsetof(struct ieee80211_mgmt, u)); ++ ++ freq = ieee80211_channel_to_frequency(ch.control_ch_num, ++ ch.band == BRCMU_CHAN_BAND_2G ? ++ NL80211_BAND_2GHZ : ++ NL80211_BAND_5GHZ); ++ ++ cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, ++ NL80211_RXMGMT_FLAG_EXTERNAL_AUTH); ++ kfree(mgmt_frame); ++ return 0; ++} ++ ++static s32 ++brcmf_notify_mgmt_tx_status(struct brcmf_if *ifp, ++ const struct brcmf_event_msg *e, void *data) ++{ ++ struct brcmf_cfg80211_vif *vif = ifp->vif; ++ u32 *packet_id = (u32 *)data; ++ ++ brcmf_dbg(INFO, "Enter: event %s (%d), status=%d\n", ++ brcmf_fweh_event_name(e->event_code), e->event_code, ++ e->status); ++ ++ if (!test_bit(BRCMF_MGMT_TX_SEND_FRAME, &vif->mgmt_tx_status) || ++ (*packet_id != vif->mgmt_tx_id)) ++ return 0; ++ ++ if (e->event_code == BRCMF_E_MGMT_FRAME_TXSTATUS) { ++ if (e->status == BRCMF_E_STATUS_SUCCESS) ++ set_bit(BRCMF_MGMT_TX_ACK, &vif->mgmt_tx_status); ++ else ++ set_bit(BRCMF_MGMT_TX_NOACK, &vif->mgmt_tx_status); ++ } else { ++ set_bit(BRCMF_MGMT_TX_OFF_CHAN_COMPLETED, &vif->mgmt_tx_status); ++ } ++ ++ complete(&vif->mgmt_tx); ++ return 0; ++} ++ + static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) + { + conf->frag_threshold = (u32)-1; +@@ -6753,7 +6990,16 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg) + brcmf_p2p_notify_action_tx_complete); + brcmf_fweh_register(cfg->pub, BRCMF_E_PSK_SUP, + brcmf_notify_connect_status); +- brcmf_fweh_register(cfg->pub, BRCMF_E_RSSI, brcmf_notify_rssi); ++ brcmf_fweh_register(cfg->pub, BRCMF_E_RSSI, ++ brcmf_notify_rssi); ++ brcmf_fweh_register(cfg->pub, BRCMF_E_EXT_AUTH_REQ, ++ brcmf_notify_ext_auth_request); ++ brcmf_fweh_register(cfg->pub, BRCMF_E_EXT_AUTH_FRAME_RX, ++ brcmf_notify_auth_frame_rx); ++ brcmf_fweh_register(cfg->pub, BRCMF_E_MGMT_FRAME_TXSTATUS, ++ brcmf_notify_mgmt_tx_status); ++ brcmf_fweh_register(cfg->pub, BRCMF_E_MGMT_FRAME_OFF_CHAN_COMPLETE, ++ brcmf_notify_mgmt_tx_status); + } + + static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) +@@ -7341,6 +7587,7 @@ brcmf_txrx_stypesNUM_NL80211_IFTYPES = { + NL80211_IFTYPE_STATION = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + NL80211_IFTYPE_P2P_CLIENT = { +@@ -7646,6 +7893,8 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_SAE_OFFLOAD_AP); + } ++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SAE_EXT)) ++ wiphy->features |= NL80211_FEATURE_SAE; + wiphy->mgmt_stypes = brcmf_txrx_stypes; + wiphy->max_remain_on_channel_duration = 5000; + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) { +@@ -8187,31 +8436,45 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); struct brcmf_pub *drvr = cfg->pub; struct brcmf_fil_country_le ccreq; @@ -96646,41 +144848,150 @@ if (err) return; +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +index 0e1fa3f0dea2..ae1c8a416336 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +@@ -178,6 +178,21 @@ enum brcmf_vif_status { + BRCMF_VIF_STATUS_ASSOC_SUCCESS, + }; + ++/** ++ * enum brcmf_mgmt_tx_status - mgmt frame tx status ++ * ++ * @BRCMF_MGMT_TX_ACK: mgmt frame acked ++ * @BRCMF_MGMT_TX_NOACK: mgmt frame not acked ++ * @BRCMF_MGMT_TX_OFF_CHAN_COMPLETED: off-channel complete ++ * @BRCMF_MGMT_TX_SEND_FRAME: mgmt frame tx is in progres ++ */ ++enum brcmf_mgmt_tx_status { ++ BRCMF_MGMT_TX_ACK, ++ BRCMF_MGMT_TX_NOACK, ++ BRCMF_MGMT_TX_OFF_CHAN_COMPLETED, ++ BRCMF_MGMT_TX_SEND_FRAME ++}; ++ + /** + * struct vif_saved_ie - holds saved IEs for a virtual interface. + * +@@ -224,6 +239,9 @@ struct brcmf_cfg80211_vif { + unsigned long sme_state; + struct vif_saved_ie saved_ie; + struct list_head list; ++ struct completion mgmt_tx; ++ unsigned long mgmt_tx_status; ++ u32 mgmt_tx_id; + u16 mgmt_rx_reg; + bool mbss; + int is_11d; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c -index e3758bd86acf..9047a0813ebf 100644 +index a194b0e68eb5..935c858f422d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c -@@ -134,13 +134,23 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp) - brcmf_dbg(TRACE, "Enter\n"); +@@ -20,6 +20,8 @@ + #include "of.h" + #include "firmware.h" + #include "chip.h" ++#include "fweh.h" ++#include <brcm_hw_ids.h> + + MODULE_AUTHOR("Broadcom Corporation"); + MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); +@@ -274,6 +276,8 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) + char *clmver; + char *ptr; + s32 err; ++ struct eventmsgs_ext *eventmask_msg = NULL; ++ u8 msglen; - 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; + if (is_valid_ether_addr(ifp->mac_addr)) { + /* set mac address */ +@@ -427,6 +431,41 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) + goto done; } -- err = firmware_request_nowarn(&clm, clm_name, bus->dev); -+ if (clm_name0) -+ err = firmware_request_nowarn(&clm, clm_name, bus->dev); -+ if (err || !clm_name0) { -+ 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; ++ /* Enable event_msg_ext specific to 43012 chip */ ++ if (bus->chip == CY_CC_43012_CHIP_ID) { ++ /* Program event_msg_ext to support event larger than 128 */ ++ msglen = (roundup(BRCMF_E_LAST, NBBY) / NBBY) + ++ EVENTMSGS_EXT_STRUCT_SIZE; ++ /* Allocate buffer for eventmask_msg */ ++ eventmask_msg = kzalloc(msglen, GFP_KERNEL); ++ if (!eventmask_msg) { ++ err = -ENOMEM; ++ goto done; + } + -+ err = firmware_request_nowarn(&clm, clm_name, bus->dev); ++ /* Read the current programmed event_msgs_ext */ ++ eventmask_msg->ver = EVENTMSGS_VER; ++ eventmask_msg->len = roundup(BRCMF_E_LAST, NBBY) / NBBY; ++ err = brcmf_fil_iovar_data_get(ifp, "event_msgs_ext", ++ eventmask_msg, ++ msglen); ++ ++ /* Enable ULP event */ ++ brcmf_dbg(EVENT, "enable event ULP\n"); ++ setbit(eventmask_msg->mask, BRCMF_E_ULP); ++ ++ /* Write updated Event mask */ ++ eventmask_msg->ver = EVENTMSGS_VER; ++ eventmask_msg->command = EVENTMSGS_SET_MASK; ++ eventmask_msg->len = (roundup(BRCMF_E_LAST, NBBY) / NBBY); ++ ++ err = brcmf_fil_iovar_data_set(ifp, "event_msgs_ext", ++ eventmask_msg, msglen); ++ if (err) { ++ brcmf_err("Set event_msgs_ext error (%d)\n", err); ++ goto done; ++ } + } - if (err) { - brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n", - err); + /* Setup default scan channel time */ + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME, + BRCMF_DEFAULT_SCAN_CHANNEL_TIME); +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +index f599d5f896e8..c188e7ca72a3 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -1318,7 +1318,7 @@ int brcmf_alloc(struct device *dev, struct brcmf_mp_device *settings) + return 0; + } + +-int brcmf_attach(struct device *dev) ++int brcmf_attach(struct device *dev, bool start_bus) + { + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_pub *drvr = bus_if->drvr; +@@ -1355,10 +1355,13 @@ int brcmf_attach(struct device *dev) + /* attach firmware event handler */ + brcmf_fweh_attach(drvr); + +- ret = brcmf_bus_started(drvr, drvr->ops); +- if (ret != 0) { +- bphy_err(drvr, "dongle is not responding: err=%d\n", ret); +- goto fail; ++ if (start_bus) { ++ ret = brcmf_bus_started(drvr, drvr->ops); ++ if (ret != 0) { ++ bphy_err(drvr, "dongle is not responding: err=%d\n", ++ ret); ++ goto fail; ++ } + } + + return 0; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h -index 4146faeed344..d7d0f84f3693 100644 +index 9bb5f709d41a..f3804d6f8768 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h -@@ -63,7 +63,12 @@ void __brcmf_err(struct brcmf_bus *bus, const char *func, const char *fmt, ...); +@@ -29,6 +29,7 @@ + #define BRCMF_MSGBUF_VAL 0x00040000 + #define BRCMF_PCIE_VAL 0x00080000 + #define BRCMF_FWCON_VAL 0x00100000 ++#define BRCMF_ULP_VAL 0x00200000 + + /* set default print format */ + #undef pr_fmt +@@ -67,7 +68,12 @@ void __brcmf_err(struct brcmf_bus *bus, const char *func, const char *fmt, ...); #if defined(DEBUG) || defined(CONFIG_BRCM_TRACING) /* For debug/tracing purposes treat info messages as errors */ @@ -96694,8 +145005,40 @@ __printf(3, 4) void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...); +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +index 6d10c9efbe93..2bdf95179609 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +@@ -43,6 +43,7 @@ static const struct brcmf_feat_fwcap brcmf_fwcap_map = { + { BRCMF_FEAT_DOT11H, "802.11h" }, + { BRCMF_FEAT_SAE, "sae" }, + { BRCMF_FEAT_FWAUTH, "idauth" }, ++ { BRCMF_FEAT_SAE_EXT, "sae_ext " }, + }; + + #ifdef DEBUG +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +index 7f4f0b3e4a7b..e2fc7c9dffdb 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +@@ -30,6 +30,7 @@ + * SAE: simultaneous authentication of equals + * FWAUTH: Firmware authenticator + * DUMP_OBSS: Firmware has capable to dump obss info to support ACS ++ * SAE_EXT: SAE be handled by userspace supplicant + * SCAN_V2: Version 2 scan params + */ + #define BRCMF_FEAT_LIST \ +@@ -55,6 +56,7 @@ + BRCMF_FEAT_DEF(SAE) \ + BRCMF_FEAT_DEF(FWAUTH) \ + BRCMF_FEAT_DEF(DUMP_OBSS) \ ++ BRCMF_FEAT_DEF(SAE_EXT) \ + BRCMF_FEAT_DEF(SCAN_V2) \ + BRCMF_FEAT_DEF(PMKID_V2) \ + BRCMF_FEAT_DEF(PMKID_V3) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c -index d821a4758f8c..b14963be17f1 100644 +index 09d2f2dc2b46..da413308a564 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c @@ -10,6 +10,7 @@ @@ -96706,7 +145049,7 @@ #include "debug.h" #include "firmware.h" -@@ -30,6 +31,8 @@ enum nvram_parser_state { +@@ -32,6 +33,8 @@ enum nvram_parser_state { END }; @@ -96715,7 +145058,7 @@ /** * struct nvram_parser - internal info for parser. * -@@ -545,10 +548,26 @@ static int brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx) +@@ -562,11 +565,27 @@ static int brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx) goto fail; } @@ -96738,130 +145081,255 @@ + nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length, fwctx->req->domain_nr, - fwctx->req->bus_nr); + fwctx->req->bus_nr, + fwctx->dev); + } if (free_bcm47xx_nvram) bcm47xx_nvram_release_contents(data); -@@ -613,7 +632,7 @@ static int brcmf_fw_request_firmware(const struct firmware **fw, - 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 --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c +index dac7eb77799b..cd0626a00333 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c +@@ -359,26 +359,42 @@ int brcmf_fweh_activate_events(struct brcmf_if *ifp) + { + struct brcmf_pub *drvr = ifp->drvr; + int i, err; +- s8 eventmaskBRCMF_EVENTING_MASK_LEN; ++ struct eventmsgs_ext *eventmask_msg; ++ u32 msglen; ++ ++ msglen = EVENTMSGS_EXT_STRUCT_SIZE + BRCMF_EVENTING_MASK_LEN; ++ eventmask_msg = kzalloc(msglen, GFP_KERNEL); ++ if (!eventmask_msg) ++ return -ENOMEM; + +- memset(eventmask, 0, sizeof(eventmask)); + for (i = 0; i < BRCMF_E_LAST; i++) { + if (ifp->drvr->fweh.evt_handleri) { + brcmf_dbg(EVENT, "enable event %s\n", + brcmf_fweh_event_name(i)); +- setbit(eventmask, i); ++ setbit(eventmask_msg->mask, i); + } } -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c -index a7554265f95f..db4ac19f0800 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c -@@ -10,6 +10,7 @@ - #include "debug.h" - #include "core.h" - #include "common.h" -+#include "firmware.h" - #include "of.h" - void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, -@@ -65,3 +66,38 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, - sdio->oob_irq_nr = irq; - sdio->oob_irq_flags = irqf; + /* want to handle IF event as well */ + brcmf_dbg(EVENT, "enable event IF\n"); +- setbit(eventmask, BRCMF_E_IF); ++ setbit(eventmask_msg->mask, BRCMF_E_IF); ++ ++ eventmask_msg->ver = EVENTMSGS_VER; ++ eventmask_msg->command = EVENTMSGS_SET_MASK; ++ eventmask_msg->len = BRCMF_EVENTING_MASK_LEN; ++ ++ err = brcmf_fil_iovar_data_set(ifp, "event_msgs_ext", eventmask_msg, ++ msglen); ++ if (!err) ++ goto end; + +- err = brcmf_fil_iovar_data_set(ifp, "event_msgs", +- eventmask, BRCMF_EVENTING_MASK_LEN); ++ err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask_msg->mask, ++ BRCMF_EVENTING_MASK_LEN); + if (err) + bphy_err(drvr, "Set event_msgs error (%d)\n", err); + ++end: ++ kfree(eventmask_msg); + return err; } + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h +index 48414e8b9389..65e33df996dd 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h +@@ -90,7 +90,12 @@ struct brcmf_cfg80211_info; + BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \ + BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) \ + BRCMF_ENUM_DEF(TDLS_PEER_EVENT, 92) \ +- BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) ++ BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) \ ++ BRCMF_ENUM_DEF(ULP, 146) \ ++ BRCMF_ENUM_DEF(EXT_AUTH_REQ, 187) \ ++ BRCMF_ENUM_DEF(EXT_AUTH_FRAME_RX, 188) \ ++ BRCMF_ENUM_DEF(MGMT_FRAME_TXSTATUS, 189) \ ++ BRCMF_ENUM_DEF(MGMT_FRAME_OFF_CHAN_COMPLETE, 190) + + #define BRCMF_ENUM_DEF(id, val) \ + BRCMF_E_##id = (val), +@@ -102,7 +107,7 @@ enum brcmf_fweh_event_code { + * minimum length check in device firmware so it is + * hard-coded here. + */ +- BRCMF_E_LAST = 139 ++ BRCMF_E_LAST = 191 + }; + #undef BRCMF_ENUM_DEF + +@@ -283,6 +288,28 @@ struct brcmf_if_event { + u8 role; + }; + ++enum event_msgs_ext_command { ++ EVENTMSGS_NONE = 0, ++ EVENTMSGS_SET_BIT = 1, ++ EVENTMSGS_RESET_BIT = 2, ++ EVENTMSGS_SET_MASK = 3 ++}; ++ ++#define EVENTMSGS_VER 1 ++#define EVENTMSGS_EXT_STRUCT_SIZE offsetof(struct eventmsgs_ext, mask0) ++ ++/* len- for SET it would be mask size from the application to the firmware */ ++/* for GET it would be actual firmware mask size */ ++/* maxgetsize - is only used for GET. indicate max mask size that the */ ++/* application can read from the firmware */ ++struct eventmsgs_ext { ++ u8 ver; ++ u8 command; ++ u8 len; ++ u8 maxgetsize; ++ u8 mask1; ++}; ++ + typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp, + const struct brcmf_event_msg *evtmsg, + void *data); +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +index 611d1a6aabb9..c02e852fcda4 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +@@ -178,6 +178,11 @@ + #define BRCMF_PMKSA_VER_3 3 + #define BRCMF_PMKSA_NO_EXPIRY 0xffffffff + ++#define BRCMF_EXTAUTH_START 1 ++#define BRCMF_EXTAUTH_ABORT 2 ++#define BRCMF_EXTAUTH_FAIL 3 ++#define BRCMF_EXTAUTH_SUCCESS 4 ++ + /* MAX_CHUNK_LEN is the maximum length for data passing to firmware in each + * ioctl. It is relatively small because firmware has small maximum size input + * playload restriction for ioctls. +@@ -598,6 +603,46 @@ struct brcmf_wsec_sae_pwd_le { + u8 keyBRCMF_WSEC_MAX_SAE_PASSWORD_LEN; + }; + ++/** ++ * struct brcmf_auth_req_status_le - external auth request and status update ++ * ++ * @flags: flags for external auth status ++ * @peer_mac: peer MAC address ++ * @ssid_len: length of ssid ++ * @ssid: ssid characters ++ */ ++struct brcmf_auth_req_status_le { ++ __le16 flags; ++ u8 peer_macETH_ALEN; ++ __le32 ssid_len; ++ u8 ssidIEEE80211_MAX_SSID_LEN; ++}; ++ ++/** ++ * struct brcmf_mf_params_le - management frame parameters for mgmt_frame iovar ++ * ++ * @version: version of the iovar ++ * @dwell_time: dwell duration in ms ++ * @len: length of frame data ++ * @frame_control: frame control ++ * @channel: channel ++ * @da: peer MAC address ++ * @bssid: BSS network identifier ++ * @packet_id: packet identifier ++ * @data: frame data ++ */ ++struct brcmf_mf_params_le { ++ __le32 version; ++ __le32 dwell_time; ++ __le16 len; ++ __le16 frame_control; ++ __le16 channel; ++ u8 daETH_ALEN; ++ u8 bssidETH_ALEN; ++ __le32 packet_id; ++ u8 data1; ++}; ++ + /* Used to get specific STA parameters */ + struct brcmf_scb_val_le { + __le32 val; +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +index d4492d02e4ea..7376f9f37d07 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +@@ -1281,6 +1281,10 @@ static s32 brcmf_p2p_abort_action_frame(struct brcmf_cfg80211_info *cfg) + brcmf_dbg(TRACE, "Enter\n"); + + vif = p2p->bss_idxP2PAPI_BSSCFG_DEVICE.vif; + -+struct brcmf_firmware_mapping * -+brcmf_of_fwnames(struct device *dev, u32 *fwname_count) -+{ -+ struct device_node *np = dev->of_node; -+ struct brcmf_firmware_mapping *fwnames; -+ struct device_node *map_np, *fw_np; -+ int of_count; -+ int count = 0; -+ -+ map_np = of_get_child_by_name(np, "firmwares"); -+ of_count = of_get_child_count(map_np); -+ if (!of_count) -+ return NULL; -+ -+ fwnames = devm_kcalloc(dev, of_count, -+ sizeof(struct brcmf_firmware_mapping), -+ GFP_KERNEL); -+ -+ for_each_child_of_node(map_np, fw_np) -+ { -+ struct brcmf_firmware_mapping *cur = &fwnamescount; -+ -+ if (of_property_read_u32(fw_np, "chipid", &cur->chipid) || -+ of_property_read_u32(fw_np, "revmask", &cur->revmask)) -+ continue; -+ cur->fw_base = of_get_property(fw_np, "fw_base", NULL); -+ if (cur->fw_base) -+ count++; -+ } -+ -+ *fwname_count = count; ++ if (!vif) ++ vif = p2p->bss_idxP2PAPI_BSSCFG_PRIMARY.vif; + -+ return count ? fwnames : NULL; -+} -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h -index 10bf52253337..5b39a39812d0 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h -@@ -5,9 +5,16 @@ - #ifdef CONFIG_OF - void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, - struct brcmf_mp_device *settings); -+struct brcmf_firmware_mapping * -+brcmf_of_fwnames(struct device *dev, u32 *map_count); - #else - static void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, - struct brcmf_mp_device *settings) - { - } -+static struct brcmf_firmware_mapping * -+brcmf_of_fwnames(struct device *dev, u32 *map_count) -+{ -+ return NULL; -+} - #endif /* CONFIG_OF */ + err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe_abort", &int_val, + sizeof(s32)); + if (err) +@@ -1826,6 +1830,7 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, + /* validate channel and p2p ies */ + if (config_af_params.search_channel && + IS_P2P_SOCIAL_CHANNEL(le32_to_cpu(af_params->channel)) && ++ p2p->bss_idxP2PAPI_BSSCFG_DEVICE.vif && + p2p->bss_idxP2PAPI_BSSCFG_DEVICE.vif->saved_ie.probe_req_ie_len) { + afx_hdl = &p2p->afx_hdl; + afx_hdl->peer_listen_chan = le32_to_cpu(af_params->channel); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c -index 1f12dfb33938..89cdd2075846 100644 +index 80220685f5e4..21a61f092820 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c -@@ -1400,7 +1400,8 @@ static int brcmf_pcie_get_memdump(struct device *dev, void *data, size_t len) - } +@@ -2207,7 +2207,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret, - 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; -@@ -1408,6 +1409,10 @@ int brcmf_pcie_get_fwname(struct device *dev, const char *ext, u8 *fw_name) - { ext, fw_name }, - }; + init_waitqueue_head(&devinfo->mbdata_resp_wait); + +- ret = brcmf_attach(&devinfo->pdev->dev); ++ ret = brcmf_attach(&devinfo->pdev->dev, true); + if (ret) + goto fail; -+ if (board_specific) { -+ fw_name0 = 0; -+ return 0; -+ } - fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev, - brcmf_pcie_fwnames, - ARRAY_SIZE(brcmf_pcie_fwnames), diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c -index 6d5d5c39c635..c8609fed3c32 100644 +index 6b38d9de71af..8a95bb2573a1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c -@@ -35,6 +35,7 @@ +@@ -35,9 +35,11 @@ #include "core.h" #include "common.h" #include "bcdc.h" -+#include "of.h" ++#include "fwil.h" #define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500) #define CTL_DONE_TIMEOUT msecs_to_jiffies(2500) -@@ -611,6 +612,7 @@ BRCMF_FW_DEF(4329, "brcmfmac4329-sdio"); ++#define ULP_HUDI_PROC_DONE_TIME msecs_to_jiffies(2500) + + /* watermark expressed in number of words */ + #define DEFAULT_F2_WATERMARK 0x8 +@@ -325,7 +327,16 @@ struct rte_console { + + #define KSO_WAIT_US 50 + #define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US) +-#define BRCMF_SDIO_MAX_ACCESS_ERRORS 5 ++#define BRCMF_SDIO_MAX_ACCESS_ERRORS 20 ++ ++static void brcmf_sdio_firmware_callback(struct device *dev, int err, ++ struct brcmf_fw_request *fwreq); ++static struct brcmf_fw_request * ++ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus); ++static int brcmf_sdio_f2_ready(struct brcmf_sdio *bus); ++static int brcmf_ulp_event_notify(struct brcmf_if *ifp, ++ const struct brcmf_event_msg *evtmsg, ++ void *data); + + #ifdef DEBUG + /* Device console log buffer state */ +@@ -609,6 +620,7 @@ BRCMF_FW_DEF(4329, "brcmfmac4329-sdio"); BRCMF_FW_DEF(4330, "brcmfmac4330-sdio"); BRCMF_FW_DEF(4334, "brcmfmac4334-sdio"); BRCMF_FW_DEF(43340, "brcmfmac43340-sdio"); @@ -96869,16 +145337,7 @@ BRCMF_FW_DEF(4335, "brcmfmac4335-sdio"); BRCMF_FW_DEF(43362, "brcmfmac43362-sdio"); BRCMF_FW_DEF(4339, "brcmfmac4339-sdio"); -@@ -625,7 +627,7 @@ BRCMF_FW_DEF(4359, "brcmfmac4359-sdio"); - BRCMF_FW_DEF(4373, "brcmfmac4373-sdio"); - BRCMF_FW_DEF(43012, "brcmfmac43012-sdio"); - --static const struct brcmf_firmware_mapping brcmf_sdio_fwnames = { -+static const struct brcmf_firmware_mapping sdio_fwnames = { - BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143), - BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x0000001F, 43241B0), - BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x00000020, 43241B4), -@@ -634,7 +636,7 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames = { +@@ -641,7 +653,7 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames = { 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), @@ -96887,285 +145346,671 @@ 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), -@@ -649,6 +651,9 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames = { - BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012) - }; - -+static const struct brcmf_firmware_mapping *brcmf_sdio_fwnames; -+static u32 brcmf_sdio_fwnames_count; -+ - #define TXCTL_CREDITS 2 - - static void pkt_align(struct sk_buff *p, int len, int align) -@@ -4114,17 +4119,27 @@ brcmf_sdio_watchdog(struct timer_list *t) +@@ -1104,7 +1116,7 @@ static void brcmf_sdio_get_console_addr(struct brcmf_sdio *bus) } + #endif /* DEBUG */ - 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) +-static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus) ++static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus, u32 *hmbd) { - 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_extBRCMF_FW_NAME_LEN; - struct brcmf_fw_name fwnames = { - { ext, fw_name }, - }; + struct brcmf_sdio_dev *sdiod = bus->sdiodev; + struct brcmf_core *core = bus->sdio_core; +@@ -1193,6 +1205,9 @@ static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus) + HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK)) + brcmf_err("Unknown mailbox data content: 0x%02x\n", + hmb_data); ++ /* Populate hmb_data if argument is passed for DS1 check later */ ++ if (hmbd) ++ *hmbd = hmb_data; -+ 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); -+ fwnames0.extension = board_ext; -+ } - fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev, - brcmf_sdio_fwnames, -- ARRAY_SIZE(brcmf_sdio_fwnames), -+ brcmf_sdio_fwnames_count, - fwnames, ARRAY_SIZE(fwnames)); - if (!fwreq) - return -ENOMEM; -@@ -4180,6 +4195,9 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = { - #define BRCMF_SDIO_FW_CODE 0 - #define BRCMF_SDIO_FW_NVRAM 1 + return intstatus; + } +@@ -2579,6 +2594,182 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) + return ret; + } -+static struct brcmf_fw_request * -+brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus); ++/* This Function is used to retrieve important ++ * details from dongle related to ULP mode Mostly ++ * values/SHM details that will be vary depending ++ * on the firmware branches ++ */ ++static void ++brcmf_sdio_ulp_preinit(struct device *dev) ++{ ++ struct brcmf_bus *bus_if = dev_get_drvdata(dev); ++ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++ struct brcmf_if *ifp = bus_if->drvr->iflist0; + - static void brcmf_sdio_firmware_callback(struct device *dev, int err, - struct brcmf_fw_request *fwreq) - { -@@ -4195,6 +4213,22 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, - - brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err); - -+ if (err && brcmf_sdio_fwnames != sdio_fwnames) { -+ /* Try again with the standard firmware names */ -+ brcmf_sdio_fwnames = sdio_fwnames; -+ brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames); ++ brcmf_dbg(ULP, "Enter\n"); ++ ++ /* Query ulp_sdioctrl iovar to get the ULP related SHM offsets */ ++ brcmf_fil_iovar_data_get(ifp, "ulp_sdioctrl", ++ &sdiodev->fmac_ulp.ulp_shm_offset, ++ sizeof(sdiodev->fmac_ulp.ulp_shm_offset)); ++ ++ sdiodev->ulp = false; ++ ++ brcmf_dbg(ULP, "m_ulp_ctrl_sdio%x m_ulp_wakeevt_ind %x\n", ++ M_DS1_CTRL_SDIO(sdiodev->fmac_ulp), ++ M_WAKEEVENT_IND(sdiodev->fmac_ulp)); ++ brcmf_dbg(ULP, "m_ulp_wakeind %x\n", ++ M_ULP_WAKE_IND(sdiodev->fmac_ulp)); ++} ++ ++/* Reinitialize ARM because In DS1 mode ARM got off */ ++static int ++brcmf_sdio_ulp_reinit_fw(struct brcmf_sdio *bus) ++{ ++ struct brcmf_sdio_dev *sdiodev = bus->sdiodev; ++ struct brcmf_fw_request *fwreq; ++ int err = 0; ++ ++ /* After firmware redownload tx/rx seq are reset accordingly ++ * these values are reset on FMAC side tx_max is initially set to 4, ++ * which later is updated by FW. ++ */ ++ bus->tx_seq = 0; ++ bus->rx_seq = 0; ++ bus->tx_max = 4; ++ ++ fwreq = brcmf_sdio_prepare_fw_request(bus); ++ if (!fwreq) ++ return -ENOMEM; ++ ++ err = brcmf_fw_get_firmwares(sdiodev->dev, fwreq, ++ brcmf_sdio_firmware_callback); ++ if (err != 0) { ++ brcmf_err("async firmware request failed: %d\n", err); + kfree(fwreq); -+ fwreq = brcmf_sdio_prepare_fw_request(bus); -+ if (!fwreq) { -+ err = -ENOMEM; -+ goto fail; ++ } ++ ++ return err; ++} ++ ++/* Check if device is in DS1 mode and handshake with ULP UCODE */ ++static bool ++brcmf_sdio_ulp_pre_redownload_check(struct brcmf_sdio *bus, u32 hmb_data) ++{ ++ struct brcmf_sdio_dev *sdiod = bus->sdiodev; ++ int err = 0; ++ u32 value = 0; ++ u32 val32, ulp_wake_ind, wowl_wake_ind; ++ int reg_addr; ++ unsigned long timeout; ++ struct brcmf_ulp *fmac_ulp = &bus->sdiodev->fmac_ulp; ++ int i = 0; ++ ++ /* If any host mail box data is present, ignore DS1 exit sequence */ ++ if (hmb_data) ++ return false; ++ /* Skip if DS1 Exit is already in progress ++ * This can happen if firmware download is taking more time ++ */ ++ if (fmac_ulp->ulp_state == FMAC_ULP_TRIGGERED) ++ return false; ++ ++ value = brcmf_sdiod_func0_rb(sdiod, SDIO_CCCR_IOEx, &err); ++ ++ if (value == SDIO_FUNC_ENABLE_1) { ++ brcmf_dbg(ULP, "GOT THE INTERRUPT FROM UCODE\n"); ++ sdiod->ulp = true; ++ fmac_ulp->ulp_state = FMAC_ULP_TRIGGERED; ++ ulp_wake_ind = D11SHM_RDW(sdiod, ++ M_ULP_WAKE_IND(sdiod->fmac_ulp), ++ &err); ++ wowl_wake_ind = D11SHM_RDW(sdiod, ++ M_WAKEEVENT_IND(sdiod->fmac_ulp), ++ &err); ++ ++ brcmf_dbg(ULP, "wowl_wake_ind: 0x%08x, ulp_wake_ind: 0x%08x state %s\n", ++ wowl_wake_ind, ulp_wake_ind, (fmac_ulp->ulp_state) ? ++ "DS1 Exit Triggered" : "IDLE State"); ++ ++ if (wowl_wake_ind || ulp_wake_ind) { ++ /* RX wake Don't do anything. ++ * Just bail out and re-download firmware. ++ */ ++ /* Print out PHY TX error block when bit 9 set */ ++ if ((ulp_wake_ind & C_DS1_PHY_TXERR) && ++ M_DS1_PHYTX_ERR_BLK(sdiod->fmac_ulp)) { ++ brcmf_err("Dump PHY TX Error SHM Locations\n"); ++ for (i = 0; i < PHYTX_ERR_BLK_SIZE; i++) { ++ pr_err("0x%x", ++ D11SHM_RDW(sdiod, ++ (M_DS1_PHYTX_ERR_BLK(sdiod->fmac_ulp) + ++ (i * 2)), &err)); ++ } ++ brcmf_err("\n"); ++ } ++ } else { ++ /* TX wake negotiate with MAC */ ++ brcmf_dbg(ULP, "M_DS1_CTRL_SDIO: 0x%08x\n", ++ (u32)D11SHM_RDW(sdiod, ++ M_DS1_CTRL_SDIO(sdiod->fmac_ulp), ++ &err)); ++ val32 = D11SHM_RD(sdiod, ++ M_DS1_CTRL_SDIO(sdiod->fmac_ulp), ++ &err); ++ D11SHM_WR(sdiod, M_DS1_CTRL_SDIO(sdiod->fmac_ulp), ++ val32, (C_DS1_CTRL_SDIO_DS1_EXIT | ++ C_DS1_CTRL_REQ_VALID), &err); ++ val32 = D11REG_RD(sdiod, D11_MACCONTROL_REG, &err); ++ val32 = val32 | D11_MACCONTROL_REG_WAKE; ++ D11REG_WR(sdiod, D11_MACCONTROL_REG, val32, &err); ++ ++ /* Poll for PROC_DONE to be set by ucode */ ++ value = D11SHM_RDW(sdiod, ++ M_DS1_CTRL_SDIO(sdiod->fmac_ulp), ++ &err); ++ /* Wait here (polling) for C_DS1_CTRL_PROC_DONE */ ++ timeout = jiffies + ULP_HUDI_PROC_DONE_TIME; ++ while (!(value & C_DS1_CTRL_PROC_DONE)) { ++ value = D11SHM_RDW(sdiod, ++ M_DS1_CTRL_SDIO(sdiod->fmac_ulp), ++ &err); ++ if (time_after(jiffies, timeout)) ++ break; ++ usleep_range(1000, 2000); ++ } ++ brcmf_dbg(ULP, "M_DS1_CTRL_SDIO: 0x%08x\n", ++ (u32)D11SHM_RDW(sdiod, ++ M_DS1_CTRL_SDIO(sdiod->fmac_ulp), &err)); ++ value = D11SHM_RDW(sdiod, ++ M_DS1_CTRL_SDIO(sdiod->fmac_ulp), ++ &err); ++ if (!(value & C_DS1_CTRL_PROC_DONE)) { ++ brcmf_err("Timeout Failed to enter DS1 Exit state!\n"); ++ return false; ++ } + } -+ err = brcmf_fw_get_firmwares(dev, fwreq, -+ brcmf_sdio_firmware_callback); -+ if (!err) -+ return; ++ ++ ulp_wake_ind = D11SHM_RDW(sdiod, ++ M_ULP_WAKE_IND(sdiod->fmac_ulp), ++ &err); ++ wowl_wake_ind = D11SHM_RDW(sdiod, ++ M_WAKEEVENT_IND(sdiod->fmac_ulp), ++ &err); ++ brcmf_dbg(ULP, "wowl_wake_ind: 0x%08x, ulp_wake_ind: 0x%08x\n", ++ wowl_wake_ind, ulp_wake_ind); ++ reg_addr = CORE_CC_REG( ++ brcmf_chip_get_pmu(bus->ci)->base, min_res_mask); ++ brcmf_sdiod_writel(sdiod, reg_addr, ++ DEFAULT_43012_MIN_RES_MASK, &err); ++ if (err) ++ brcmf_err("min_res_mask failed\n"); ++ ++ return true; + } + - if (err) - goto fail; ++ return false; ++} ++ + static void brcmf_sdio_dpc(struct brcmf_sdio *bus) + { + struct brcmf_sdio_dev *sdiod = bus->sdiodev; +@@ -2650,8 +2841,11 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) -@@ -4402,7 +4436,7 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus) + /* Handle host mailbox indication */ + if (intstatus & I_HMB_HOST_INT) { ++ u32 hmb_data = 0; + intstatus &= ~I_HMB_HOST_INT; +- intstatus |= brcmf_sdio_hostmail(bus); ++ intstatus |= brcmf_sdio_hostmail(bus, &hmb_data); ++ if (brcmf_sdio_ulp_pre_redownload_check(bus, hmb_data)) ++ brcmf_sdio_ulp_reinit_fw(bus); + } + + sdio_release_host(bus->sdiodev->func1); +@@ -2696,7 +2890,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) + brcmf_sdio_clrintr(bus); + + if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) && +- txctl_ok(bus)) { ++ txctl_ok(bus) && brcmf_sdio_f2_ready(bus)) { + sdio_claim_host(bus->sdiodev->func1); + if (bus->ctrl_frame_stat) { + err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf, +@@ -3566,6 +3760,10 @@ static int brcmf_sdio_bus_preinit(struct device *dev) + if (err < 0) + goto done; - fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev, - brcmf_sdio_fwnames, -- ARRAY_SIZE(brcmf_sdio_fwnames), -+ brcmf_sdio_fwnames_count, - fwnames, ARRAY_SIZE(fwnames)); - if (!fwreq) - return NULL; -@@ -4420,6 +4454,9 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) - struct brcmf_sdio *bus; - struct workqueue_struct *wq; - struct brcmf_fw_request *fwreq; -+ struct brcmf_firmware_mapping *of_fwnames, *fwnames = NULL; -+ const int fwname_size = sizeof(struct brcmf_firmware_mapping); -+ u32 of_fw_count; ++ /* initialize SHM address from firmware for DS1 */ ++ if (!bus->sdiodev->ulp) ++ brcmf_sdio_ulp_preinit(dev); ++ + bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN; + if (sdiodev->sg_support) { + bus->txglom = false; +@@ -4214,7 +4412,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, + u8 saveclk, bpreq; + u8 devctl; - brcmf_dbg(TRACE, "Enter\n"); +- brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err); ++ brcmf_dbg(ULP, "Enter: dev=%s, err=%d\n", dev_name(dev), err); -@@ -4502,6 +4539,23 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) + if (err) + goto fail; +@@ -4391,12 +4589,25 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, + } - brcmf_dbg(INFO, "completed!!\n"); + /* Attach to the common layer, reserve hdr space */ +- err = brcmf_attach(sdiod->dev); ++ err = brcmf_attach(sdiod->dev, !bus->sdiodev->ulp); + if (err != 0) { + brcmf_err("brcmf_attach failed\n"); + goto free; + } -+ brcmf_sdio_fwnames = sdio_fwnames; -+ brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames); -+ of_fwnames = brcmf_of_fwnames(sdiodev->dev, &of_fw_count); -+ if (of_fwnames) -+ fwnames = devm_kcalloc(sdiodev->dev, -+ of_fw_count + brcmf_sdio_fwnames_count, -+ fwname_size, GFP_KERNEL); -+ -+ if (fwnames) { -+ /* The array is scanned in order, so overrides come first */ -+ memcpy(fwnames, of_fwnames, of_fw_count * fwname_size); -+ memcpy(fwnames + of_fw_count, sdio_fwnames, -+ brcmf_sdio_fwnames_count * fwname_size); -+ brcmf_sdio_fwnames = fwnames; -+ brcmf_sdio_fwnames_count += of_fw_count; ++ /* Register for ULP events */ ++ if (sdiod->func1->device == SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012) ++ brcmf_fweh_register(bus_if->drvr, BRCMF_E_ULP, ++ brcmf_ulp_event_notify); ++ ++ if (bus->sdiodev->ulp) { ++ /* For ULP, after firmware redownload complete ++ * set ULP state to IDLE ++ */ ++ if (bus->sdiodev->fmac_ulp.ulp_state == FMAC_ULP_TRIGGERED) ++ bus->sdiodev->fmac_ulp.ulp_state = FMAC_ULP_IDLE; + } + - fwreq = brcmf_sdio_prepare_fw_request(bus); - if (!fwreq) { - ret = -ENOMEM; + /* ready */ + return; + +@@ -4639,3 +4850,40 @@ int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep) + + return ret; + } ++ ++/* Check F2 Ready bit before sending data to Firmware */ ++static int ++brcmf_sdio_f2_ready(struct brcmf_sdio *bus) ++{ ++ int ret = -1; ++ int iordy_status = 0; ++ ++ sdio_claim_host(bus->sdiodev->func1); ++ /* Read the status of IOR2 */ ++ iordy_status = brcmf_sdiod_func0_rb(bus->sdiodev, SDIO_CCCR_IORx, NULL); ++ ++ sdio_release_host(bus->sdiodev->func1); ++ ret = iordy_status & SDIO_FUNC_ENABLE_2; ++ return ret; ++} ++ ++static int brcmf_ulp_event_notify(struct brcmf_if *ifp, ++ const struct brcmf_event_msg *evtmsg, ++ void *data) ++{ ++ int err = 0; ++ struct brcmf_bus *bus_if = ifp->drvr->bus_if; ++ struct brcmf_sdio_dev *sdiodev; ++ struct brcmf_sdio *bus; ++ struct brcmf_ulp_event *ulp_event = (struct brcmf_ulp_event *)data; ++ ++ sdiodev = bus_if->bus_priv.sdio; ++ bus = sdiodev->bus; ++ ++ brcmf_dbg(ULP, "Chip went to DS1 state : action %d\n", ++ ulp_event->ulp_dongle_action); ++ if (ulp_event->ulp_dongle_action == FMAC_ULP_ENTRY) ++ bus->sdiodev->fmac_ulp.ulp_state = FMAC_ULP_ENTRY_RECV; ++ ++ return err; ++} +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +index 0d18ed15b403..aadf251d5440 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +@@ -165,6 +165,35 @@ struct brcmf_sdreg { + struct brcmf_sdio; + struct brcmf_sdiod_freezer; + ++/* ULP SHM Offsets info */ ++struct ulp_shm_info { ++ u32 m_ulp_ctrl_sdio; ++ u32 m_ulp_wakeevt_ind; ++ u32 m_ulp_wakeind; ++ u32 m_ulp_phytxblk; ++}; ++ ++/* FMAC ULP state machine */ ++#define FMAC_ULP_IDLE (0) ++#define FMAC_ULP_ENTRY_RECV (1) ++#define FMAC_ULP_TRIGGERED (2) ++ ++/* BRCMF_E_ULP event data */ ++#define FMAC_ULP_EVENT_VERSION 1 ++#define FMAC_ULP_DISABLE_CONSOLE 1 /* Disable console */ ++#define FMAC_ULP_UCODE_DOWNLOAD 2 /* Download ULP ucode file */ ++#define FMAC_ULP_ENTRY 3 /* Inform ulp entry to Host */ ++ ++struct brcmf_ulp { ++ uint ulp_state; ++ struct ulp_shm_info ulp_shm_offset; ++}; ++ ++struct brcmf_ulp_event { ++ u16 version; ++ u16 ulp_dongle_action; ++}; ++ + struct brcmf_sdio_dev { + struct sdio_func *func1; + struct sdio_func *func2; +@@ -193,6 +222,8 @@ struct brcmf_sdio_dev { + enum brcmf_sdiod_state state; + struct brcmf_sdiod_freezer *freezer; + const struct firmware *clm_fw; ++ struct brcmf_ulp fmac_ulp; ++ bool ulp; + }; + + /* sdio core registers */ +@@ -367,4 +398,83 @@ void brcmf_sdio_wowl_config(struct device *dev, bool enabled); + int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep); + void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus); + ++/* SHM offsets */ ++#define M_DS1_CTRL_SDIO(ptr) ((ptr).ulp_shm_offset.m_ulp_ctrl_sdio) ++#define M_WAKEEVENT_IND(ptr) ((ptr).ulp_shm_offset.m_ulp_wakeevt_ind) ++#define M_ULP_WAKE_IND(ptr) ((ptr).ulp_shm_offset.m_ulp_wakeind) ++#define M_DS1_PHYTX_ERR_BLK(ptr) ((ptr).ulp_shm_offset.m_ulp_phytxblk) ++ ++#define D11_BASE_ADDR 0x18001000 ++#define D11_AXI_BASE_ADDR 0xE8000000 ++#define D11_SHM_BASE_ADDR (D11_AXI_BASE_ADDR + 0x4000) ++ ++#define D11REG_ADDR(offset) (D11_BASE_ADDR + (offset)) ++#define D11IHR_ADDR(offset) (D11_AXI_BASE_ADDR + 0x400 + (2 * (offset))) ++#define D11SHM_ADDR(offset) (D11_SHM_BASE_ADDR + (offset)) ++ ++/* MacControl register */ ++#define D11_MACCONTROL_REG D11REG_ADDR(0x120) ++#define D11_MACCONTROL_REG_WAKE 0x4000000 ++ ++/* HUDI Sequence SHM bits */ ++#define C_DS1_CTRL_SDIO_DS1_SLEEP 0x1 ++#define C_DS1_CTRL_SDIO_MAC_ON 0x2 ++#define C_DS1_CTRL_SDIO_RADIO_PHY_ON 0x4 ++#define C_DS1_CTRL_SDIO_DS1_EXIT 0x8 ++#define C_DS1_CTRL_PROC_DONE 0x100 ++#define C_DS1_CTRL_REQ_VALID 0x200 ++ ++/* M_ULP_WAKEIND bits */ ++#define C_WATCHDOG_EXPIRY BIT(0) ++#define C_FCBS_ERROR BIT(1) ++#define C_RETX_FAILURE BIT(2) ++#define C_HOST_WAKEUP BIT(3) ++#define C_INVALID_FCBS_BLOCK BIT(4) ++#define C_HUDI_DS1_EXIT BIT(5) ++#define C_LOB_SLEEP BIT(6) ++#define C_DS1_PHY_TXERR BIT(9) ++#define C_DS1_WAKE_TIMER BIT(10) ++ ++#define PHYTX_ERR_BLK_SIZE 18 ++#define D11SHM_FIRST2BYTE_MASK 0xFFFF0000 ++#define D11SHM_SECOND2BYTE_MASK 0x0000FFFF ++#define D11SHM_2BYTE_SHIFT 16 ++ ++#define D11SHM_RD(sdh, offset, ret) \ ++ brcmf_sdiod_readl(sdh, D11SHM_ADDR(offset), ret) ++ ++/* SHM Read is motified based on SHM 4 byte alignment as SHM size is 2 bytes and ++ * 2 byte is currently not working on FMAC ++ * If SHM address is not 4 byte aligned, then right shift by 16 ++ * otherwise, mask the first two MSB bytes ++ * Suppose data in address 7260 is 0x440002 and it is 4 byte aligned ++ * Correct SHM value is 0x2 for this SHM offset and next SHM value is 0x44 ++ */ ++#define D11SHM_RDW(sdh, offset, ret) \ ++ ((offset % 4) ? \ ++ (brcmf_sdiod_readl(sdh, D11SHM_ADDR(offset), ret) \ ++ >> D11SHM_2BYTE_SHIFT) : \ ++ (brcmf_sdiod_readl(sdh, D11SHM_ADDR(offset), ret) \ ++ & D11SHM_SECOND2BYTE_MASK)) ++ ++/* SHM is of size 2 bytes, 4 bytes write will overwrite other SHM's ++ * First read 4 bytes and then clear the required two bytes based on ++ * 4 byte alignment, then update the required value and write the ++ * 4 byte value now ++ */ ++#define D11SHM_WR(sdh, offset, val, mask, ret) \ ++ do { \ ++ if ((offset) % 4) \ ++ val = (val & D11SHM_SECOND2BYTE_MASK) | \ ++ ((mask) << D11SHM_2BYTE_SHIFT); \ ++ else \ ++ val = (mask) | (val & D11SHM_FIRST2BYTE_MASK); \ ++ brcmf_sdiod_writel(sdh, D11SHM_ADDR(offset), val, ret); \ ++ } while (0) ++#define D11REG_WR(sdh, addr, val, ret) \ ++ brcmf_sdiod_writel(sdh, addr, val, ret) ++ ++#define D11REG_RD(sdh, addr, ret) \ ++ brcmf_sdiod_readl(sdh, addr, ret) ++ + #endif /* BRCMFMAC_SDIO_H */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c -index 9fb68c2dc7e3..9bf2dbd30ded 100644 +index 2178675ae1a4..bf7e9c5d47a0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c -@@ -1155,7 +1155,8 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo, - } +@@ -1207,7 +1207,7 @@ static void brcmf_usb_probe_phase2(struct device *dev, int ret, + goto error; - 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; -@@ -1163,6 +1164,10 @@ int brcmf_usb_get_fwname(struct device *dev, const char *ext, u8 *fw_name) - { ext, fw_name }, - }; + /* Attach to the common driver interface */ +- ret = brcmf_attach(devinfo->dev); ++ ret = brcmf_attach(devinfo->dev, true); + if (ret) + goto error; -+ if (board_specific) { -+ fw_name0 = 0; -+ return 0; -+ } - fwreq = brcmf_fw_alloc_request(bus->chip, bus->chiprev, - brcmf_usb_fwnames, - ARRAY_SIZE(brcmf_usb_fwnames), +@@ -1284,7 +1284,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo, + ret = brcmf_alloc(devinfo->dev, devinfo->settings); + if (ret) + goto fail; +- ret = brcmf_attach(devinfo->dev); ++ ret = brcmf_attach(devinfo->dev, true); + if (ret) + goto fail; + /* we are done */ +diff --git a/drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h b/drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h +index 0340bba96868..090a75bcd728 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h ++++ b/drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h +@@ -308,4 +308,6 @@ struct chipcregs { + */ + #define PMU_MAX_TRANSITION_DLY 15000 + ++#define DEFAULT_43012_MIN_RES_MASK 0x0f8bfe77 ++ + #endif /* _SBCHIPC_H */ diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig -index 954d3b4a52ab..fecc19b884bf 100644 +index 5bc9c4874fe3..37137f23eee1 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig -@@ -270,4 +270,12 @@ config SPRD_EFUSE - 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" +@@ -39,6 +39,18 @@ config NVMEM_APPLE_EFUSES + This driver can also be built as a module. If so, the module will + be called nvmem-apple-efuses. + ++config NVMEM_RASPBERRYPI_OTP ++ tristate "Raspberry Pi OTP support" ++ depends on (ARCH_BCM && RASPBERRYPI_FIRMWARE) || COMPILE_TEST ++ default ARCH_BCM && RASPBERRYPI_FIRMWARE + 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 ++ Say y here to enable support for accessing OTP on Raspberry Pi boards. ++ These are used to store non-volatile information such as serial number, ++ board revision and customer stored data. ++ ++ This driver can also be built as a module. If so, the module will ++ be called nvmem-raspberrypi-otp. ++ + config NVMEM_BCM_OCOTP + tristate "Broadcom On-Chip OTP Controller support" + depends on ARCH_BCM_IPROC || COMPILE_TEST diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile -index a7c377218341..5376b8e0dae5 100644 +index 423baf089515..0ff76c1f70b6 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile -@@ -55,3 +55,5 @@ obj-$(CONFIG_NVMEM_ZYNQMP) += nvmem_zynqmp_nvmem.o - 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 --git a/drivers/nvmem/rmem.c b/drivers/nvmem/rmem.c +@@ -10,6 +10,8 @@ obj-y += layouts/ + # Devices + obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o + nvmem-apple-efuses-y := apple-efuses.o ++obj-$(CONFIG_NVMEM_RASPBERRYPI_OTP) += nvmem-raspberrypi-otp.o ++nvmem-raspberrypi-otp-y := raspberrypi-otp.o + obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o + nvmem-bcm-ocotp-y := bcm-ocotp.o + obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o +diff --git a/drivers/nvmem/raspberrypi-otp.c b/drivers/nvmem/raspberrypi-otp.c new file mode 100644 -index 000000000000..b11c3c974b3d +index 000000000000..31167069d371 --- /dev/null -+++ b/drivers/nvmem/rmem.c -@@ -0,0 +1,97 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2020 Nicolas Saenz Julienne <nsaenzjulienne@suse.de> ++++ b/drivers/nvmem/raspberrypi-otp.c +@@ -0,0 +1,133 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/** ++ * raspberrypi-otp.c ++ * ++ * nvmem driver using firmware mailbox to access otp ++ * ++ * Copyright (c) 2024, Raspberry Pi Ltd. + */ + -+#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; ++#include <soc/bcm2835/raspberrypi-firmware.h> + -+ phys_addr_t size; ++struct rpi_otp_priv { ++ struct rpi_firmware *fw; ++ u32 block; +}; + -+static int rmem_read(void *context, unsigned int offset, -+ void *val, size_t bytes) ++#define MAX_ROWS 192 ++ ++#define RPI_FIRMWARE_GET_USER_OTP 0x00030024 ++#define RPI_FIRMWARE_SET_USER_OTP 0x00038024 ++ ++static int rpi_otp_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; ++ struct rpi_otp_priv *priv = context; ++ int words = bytes / sizeof(u32); ++ int index = offset / sizeof(u32); ++ u32 data3 + MAX_ROWS = {priv->block, index, words}; ++ int err = 0; + -+ /* -+ * 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); -+ } ++ if (words > MAX_ROWS) ++ return -EINVAL; ++ ++ err = rpi_firmware_property(priv->fw, RPI_FIRMWARE_GET_USER_OTP, ++ &data, sizeof(data)); ++ if (err == 0) ++ memcpy(val, data + 3, bytes); ++ else ++ memset(val, 0xee, bytes); ++ return err; ++} + -+ count = memory_read_from_buffer(val, bytes, &off, addr, available); ++static int rpi_otp_write(void *context, unsigned int offset, void *val, ++ size_t bytes) ++{ ++ struct rpi_otp_priv *priv = context; ++ int words = bytes / sizeof(u32); ++ int index = offset / sizeof(u32); ++ u32 data3 + MAX_ROWS = {priv->block, index, words}; + -+ memunmap(addr); ++ if (bytes > MAX_ROWS * sizeof(u32)) ++ return -EINVAL; + -+ return count; ++ memcpy(data + 3, val, bytes); ++ return rpi_firmware_property(priv->fw, RPI_FIRMWARE_SET_USER_OTP, ++ &data, sizeof(data)); +} + -+static int rmem_probe(struct platform_device *pdev) ++static int rpi_otp_probe(struct platform_device *pdev) +{ -+ struct nvmem_config config = { }; ++ struct rpi_otp_priv *priv; ++ struct nvmem_config config = { ++ .dev = &pdev->dev, ++ .reg_read = rpi_otp_read, ++ .reg_write = rpi_otp_write, ++ .stride = sizeof(u32), ++ .word_size = sizeof(u32), ++ .type = NVMEM_TYPE_OTP, ++ .root_only = true, ++ }; + 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; ++ struct device_node *np = dev->of_node; ++ struct device_node *fw_node; ++ struct rpi_firmware *fw; ++ u32 reg2; ++ const char *pname; + -+ mem = of_reserved_mem_lookup(dev->of_node); -+ if (!mem) { -+ dev_err(dev, "Failed to lookup reserved memory\n"); ++ if (of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg))) { ++ dev_err(dev, "Failed to parse \"reg\" property\n"); + return -EINVAL; + } -+ priv->mem = mem; + -+ config.dev = dev; ++ pname = of_get_property(np, "name", NULL); ++ if (!pname) { ++ dev_err(dev, "Failed to parse \"name\" property\n"); ++ return -ENOENT; ++ } ++ ++ config.name = pname; ++ config.size = reg1 * sizeof(u32); ++ config.read_only = !of_property_read_bool(np, "rw"); ++ ++ 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; ++ ++ priv = devm_kzalloc(config.dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->fw = fw; ++ priv->block = reg0; + 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)); ++ return PTR_ERR_OR_ZERO(devm_nvmem_register(config.dev, &config)); +} + -+static const struct of_device_id rmem_match = { -+ { .compatible = "nvmem-rmem", }, -+ { /* sentinel */ }, ++static const struct of_device_id rpi_otp_of_match = { ++ { .compatible = "raspberrypi,rpi-otp", }, ++ {} +}; -+MODULE_DEVICE_TABLE(of, rmem_match); + -+static struct platform_driver rmem_driver = { -+ .probe = rmem_probe, ++MODULE_DEVICE_TABLE(of, rpi_otp_of_match); ++ ++static struct platform_driver rpi_otp_driver = { + .driver = { -+ .name = "rmem", -+ .of_match_table = rmem_match, ++ .name = "rpi_otp", ++ .of_match_table = rpi_otp_of_match, + }, ++ .probe = rpi_otp_probe, +}; -+module_platform_driver(rmem_driver); + -+MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>"); -+MODULE_DESCRIPTION("Reserved Memory Based nvmem Driver"); ++module_platform_driver(rpi_otp_driver); ++ ++MODULE_AUTHOR("Dom Cobley <popcornmix@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig -index 18450437d5d5..0fec52ff94ac 100644 +index da9826accb1b..69e7c420b8f4 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig -@@ -100,4 +100,11 @@ config OF_DMA_DEFAULT_COHERENT - # arches should select this if DMA is coherent by default for OF devices +@@ -102,4 +102,15 @@ config OF_OVERLAY + config OF_NUMA bool ++config OF_DMA_DEFAULT_COHERENT ++ # 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 @@ -97175,12 +146020,12 @@ + endif # OF diff --git a/drivers/of/Makefile b/drivers/of/Makefile -index c13b982084a3..957a5b60c167 100644 +index eff624854575..61bd05f08ca1 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 - obj-y = base.o device.o platform.o property.o + obj-y = base.o cpu.o device.o module.o platform.o property.o obj-$(CONFIG_OF_KOBJ) += kobj.o +obj-$(CONFIG_OF_CONFIGFS) += configfs.o obj-$(CONFIG_OF_DYNAMIC) += dynamic.o @@ -97188,7 +146033,7 @@ obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o diff --git a/drivers/of/configfs.c b/drivers/of/configfs.c new file mode 100644 -index 000000000000..ac04301dabe1 +index 000000000000..1c30f35c3ca1 --- /dev/null +++ b/drivers/of/configfs.c @@ -0,0 +1,277 @@ @@ -97275,7 +146120,7 @@ + goto out_err; + + err = of_overlay_fdt_apply((void *)overlay->fw->data, -+ (u32)overlay->fw->size, &overlay->ov_id); ++ (u32)overlay->fw->size, &overlay->ov_id, NULL); + if (err != 0) + goto out_err; + @@ -97349,7 +146194,7 @@ + overlay->dtbo_size = count; + + err = of_overlay_fdt_apply(overlay->dtbo, overlay->dtbo_size, -+ &overlay->ov_id); ++ &overlay->ov_id, NULL); + if (err != 0) + goto out_err; + @@ -97470,10 +146315,10 @@ +} +late_initcall(of_cfs_init); diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c -index 43a77d720008..bccef312f4c3 100644 +index a9a292d6d59b..2cc25b5811b9 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c -@@ -245,6 +245,8 @@ static struct property *dup_and_fixup_symbol_prop( +@@ -241,6 +241,8 @@ static struct property *dup_and_fixup_symbol_prop( if (!target_path) return NULL; target_path_len = strlen(target_path); @@ -97482,107 +146327,999 @@ new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL); if (!new_prop) -diff --git a/drivers/of/platform.c b/drivers/of/platform.c -index b557a0fcd4ba..281856ac1988 100644 ---- a/drivers/of/platform.c -+++ b/drivers/of/platform.c -@@ -511,6 +511,7 @@ static const struct of_device_id reserved_mem_matches = { - { .compatible = "qcom,rmtfs-mem" }, - { .compatible = "qcom,cmd-db" }, - { .compatible = "ramoops" }, -+ { .compatible = "nvmem-rmem" }, - {} - }; - diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c -index 9c3d2982248d..840f264f7a9b 100644 +index f9dd6622fe10..4b2c457c26fe 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c -@@ -114,8 +114,9 @@ +@@ -14,6 +14,7 @@ + #include <linux/irqchip/chained_irq.h> + #include <linux/irqdomain.h> + #include <linux/kernel.h> ++#include <linux/kthread.h> + #include <linux/list.h> + #include <linux/log2.h> + #include <linux/module.h> +@@ -48,10 +49,23 @@ + #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc + #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00 + ++#define PCIE_RC_TL_VDM_CTL0 0x0a20 ++#define PCIE_RC_TL_VDM_CTL0_VDM_ENABLED_MASK 0x10000 ++#define PCIE_RC_TL_VDM_CTL0_VDM_IGNORETAG_MASK 0x20000 ++#define PCIE_RC_TL_VDM_CTL0_VDM_IGNOREVNDRID_MASK 0x40000 ++ ++#define PCIE_RC_TL_VDM_CTL1 0x0a0c ++#define PCIE_RC_TL_VDM_CTL1_VDM_VNDRID0_MASK 0x0000ffff ++#define PCIE_RC_TL_VDM_CTL1_VDM_VNDRID1_MASK 0xffff0000 ++ + #define PCIE_RC_DL_MDIO_ADDR 0x1100 + #define PCIE_RC_DL_MDIO_WR_DATA 0x1104 + #define PCIE_RC_DL_MDIO_RD_DATA 0x1108 + ++#define PCIE_RC_PL_PHY_CTL_15 0x184c ++#define PCIE_RC_PL_PHY_CTL_15_DIS_PLL_PD_MASK 0x400000 ++#define PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK 0xff ++ + #define PCIE_MISC_MISC_CTRL 0x4008 + #define PCIE_MISC_MISC_CTRL_PCIE_RCB_64B_MODE_MASK 0x80 + #define PCIE_MISC_MISC_CTRL_PCIE_RCB_MPS_MODE_MASK 0x400 +@@ -74,6 +88,7 @@ + + #define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c + #define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f ++#define PCIE_MISC_RC_BAR1_CONFIG_HI 0x4030 + + #define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034 + #define PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK 0x1f +@@ -81,6 +96,7 @@ + + #define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c + #define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f ++#define PCIE_MISC_RC_BAR3_CONFIG_HI 0x4040 + + #define PCIE_MISC_MSI_BAR_CONFIG_LO 0x4044 + #define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048 +@@ -89,12 +105,15 @@ + #define PCIE_MISC_MSI_DATA_CONFIG_VAL_32 0xffe06540 + #define PCIE_MISC_MSI_DATA_CONFIG_VAL_8 0xfff86540 + ++#define PCIE_MISC_RC_CONFIG_RETRY_TIMEOUT 0x405c ++ + #define PCIE_MISC_PCIE_CTRL 0x4064 + #define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1 + #define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK 0x4 + + #define PCIE_MISC_PCIE_STATUS 0x4068 + #define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK 0x80 ++#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK_2712 0x40 + #define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK 0x20 + #define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK 0x10 + #define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK 0x40 +@@ -119,13 +138,77 @@ + #define PCIE_MEM_WIN0_LIMIT_HI(win) \ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8) - #define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204 --#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_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_MISC_HARD_PCIE_HARD_DEBUG 0x4204 ++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG pcie->reg_offsetsPCIE_HARD_DEBUG + #define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2 ++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK 0x8 + #define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000 + #define PCIE_BMIPS_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x00800000 +- +- +-#define PCIE_INTR2_CPU_BASE 0x4300 ++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK 0x00200000 ++ ++#define PCIE_MISC_CTRL_1 0x40A0 ++#define PCIE_MISC_CTRL_1_OUTBOUND_TC_MASK 0xf ++#define PCIE_MISC_CTRL_1_OUTBOUND_NO_SNOOP_MASK BIT(3) ++#define PCIE_MISC_CTRL_1_OUTBOUND_RO_MASK BIT(4) ++#define PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK BIT(5) ++ ++#define PCIE_MISC_UBUS_CTRL 0x40a4 ++#define PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_ERR_DIS_MASK BIT(13) ++#define PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_DECERR_DIS_MASK BIT(19) ++ ++#define PCIE_MISC_UBUS_TIMEOUT 0x40A8 ++ ++#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP 0x40ac ++#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_ACCESS_ENABLE_MASK BIT(0) ++#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_HI 0x40b0 ++ ++#define PCIE_MISC_UBUS_BAR2_CONFIG_REMAP 0x40b4 ++#define PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_ACCESS_ENABLE_MASK BIT(0) ++ ++/* Additional RC BARs */ ++#define PCIE_MISC_RC_BAR_CONFIG_LO_SIZE_MASK 0x1f ++#define PCIE_MISC_RC_BAR4_CONFIG_LO 0x40d4 ++#define PCIE_MISC_RC_BAR4_CONFIG_HI 0x40d8 ++/* ... */ ++#define PCIE_MISC_RC_BAR10_CONFIG_LO 0x4104 ++#define PCIE_MISC_RC_BAR10_CONFIG_HI 0x4108 ++ ++#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_ENABLE 0x1 ++#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_LO_MASK 0xfffff000 ++#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_HI_MASK 0xff ++#define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_LO 0x410c ++#define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_HI 0x4110 ++/* ... */ ++#define PCIE_MISC_UBUS_BAR10_CONFIG_REMAP_LO 0x413c ++#define PCIE_MISC_UBUS_BAR10_CONFIG_REMAP_HI 0x4140 ++ ++/* AXI priority forwarding - automatic level-based */ ++#define PCIE_MISC_TC_QUEUE_TO_QOS_MAP(x) (0x4160 - (x) * 4) ++/* Defined in quarter-fullness */ ++#define QUEUE_THRESHOLD_34_TO_QOS_MAP_SHIFT 12 ++#define QUEUE_THRESHOLD_23_TO_QOS_MAP_SHIFT 8 ++#define QUEUE_THRESHOLD_12_TO_QOS_MAP_SHIFT 4 ++#define QUEUE_THRESHOLD_01_TO_QOS_MAP_SHIFT 0 ++#define QUEUE_THRESHOLD_MASK 0xf ++ ++/* VDM messages indexing TCs to AXI priorities */ ++/* Indexes 8-15 */ ++#define PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_HI 0x4164 ++/* Indexes 0-7 */ ++#define PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_LO 0x4168 ++#define VDM_PRIORITY_TO_QOS_MAP_SHIFT(x) (4 * (x)) ++#define VDM_PRIORITY_TO_QOS_MAP_MASK 0xf ++ ++#define PCIE_MISC_AXI_INTF_CTRL 0x416C ++#define AXI_EN_RCLK_QOS_ARRAY_FIX BIT(13) ++#define AXI_EN_QOS_UPDATE_TIMING_FIX BIT(12) ++#define AXI_DIS_QOS_GATING_IN_MASTER BIT(11) ++#define AXI_REQFIFO_EN_QOS_PROPAGATION BIT(7) ++#define AXI_BRIDGE_LOW_LATENCY_MODE BIT(6) ++#define AXI_MASTER_MAX_OUTSTANDING_REQUESTS_MASK 0x3f ++ ++#define PCIE_MISC_AXI_READ_ERROR_DATA 0x4170 ++ ++#define PCIE_INTR2_CPU_BASE (pcie->reg_offsetsINTR2_CPU) + #define PCIE_MSI_INTR2_BASE 0x4500 + /* Offsets from PCIE_INTR2_CPU_BASE and PCIE_MSI_INTR2_BASE */ + #define MSI_INT_STATUS 0x0 +@@ -199,6 +282,8 @@ enum { + RGR1_SW_INIT_1, + EXT_CFG_INDEX, + EXT_CFG_DATA, ++ PCIE_HARD_DEBUG, ++ INTR2_CPU, + }; - #define PCIE_INTR2_CPU_BASE 0x4300 -@@ -276,6 +277,7 @@ struct brcm_pcie { + enum { +@@ -213,6 +298,7 @@ enum pcie_type { + BCM4908, + BCM7278, + BCM2711, ++ BCM2712, + }; + + struct pcie_cfg_data { +@@ -220,6 +306,7 @@ struct pcie_cfg_data { + const enum pcie_type type; + void (*perst_set)(struct brcm_pcie *pcie, u32 val); + void (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val); ++ bool (*rc_mode)(struct brcm_pcie *pcie); + }; + + struct subdev_regulators { +@@ -236,7 +323,7 @@ struct brcm_msi { + struct mutex lock; /* guards the alloc/free operations */ + u64 target_addr; + int irq; +- DECLARE_BITMAP(used, BRCM_INT_PCI_MSI_NR); ++ DECLARE_BITMAP(used, 64); + bool legacy; + /* Some chips have MSIs in bits 31..24 of a shared register. */ + int legacy_shift; +@@ -252,6 +339,8 @@ struct brcm_pcie { struct clk *clk; struct device_node *np; bool ssc; + bool l1ss; ++ bool rcb_mps_mode; int gen; u64 msi_target_addr; struct brcm_msi *msi; -@@ -461,7 +463,8 @@ static struct irq_chip brcm_msi_irq_chip = { +@@ -259,13 +348,17 @@ struct brcm_pcie { + enum pcie_type type; + struct reset_control *rescal; + struct reset_control *perst_reset; ++ struct reset_control *bridge_reset; + int num_memc; + u64 memc_sizePCIE_BRCM_MAX_MEMC; + u32 hw_rev; ++ u32 qos_map; + void (*perst_set)(struct brcm_pcie *pcie, u32 val); + void (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val); ++ bool (*rc_mode)(struct brcm_pcie *pcie); + struct subdev_regulators *sr; + bool ep_wakeup_capable; ++ u32 tperst_clk_ms; + }; + + static inline bool is_bmips(const struct brcm_pcie *pcie) +@@ -284,8 +377,8 @@ static int brcm_pcie_encode_ibar_size(u64 size) + if (log2_in >= 12 && log2_in <= 15) + /* Covers 4KB to 32KB (inclusive) */ + return (log2_in - 12) + 0x1c; +- else if (log2_in >= 16 && log2_in <= 35) +- /* Covers 64KB to 32GB, (inclusive) */ ++ else if (log2_in >= 16 && log2_in <= 36) ++ /* Covers 64KB to 64GB, (inclusive) */ + return log2_in - 15; + /* Something is awry so disable */ + return 0; +@@ -374,6 +467,35 @@ static int brcm_pcie_set_ssc(struct brcm_pcie *pcie) + return ssc && pll ? 0 : -EIO; + } + ++static void brcm_pcie_munge_pll(struct brcm_pcie *pcie) ++{ ++ //print "MDIO block 0x1600 written per Dannys instruction" ++ //tmp = pcie_mdio_write(phyad, &h16&, &h50b9&) ++ //tmp = pcie_mdio_write(phyad, &h17&, &hbd1a&) ++ //tmp = pcie_mdio_write(phyad, &h1b&, &h5030&) ++ //tmp = pcie_mdio_write(phyad, &h1e&, &h0007&) ++ ++ u32 tmp; ++ int ret, i; ++ u8 regs = { 0x16, 0x17, 0x18, 0x19, 0x1b, 0x1c, 0x1e }; ++ u16 data = { 0x50b9, 0xbda1, 0x0094, 0x97b4, 0x5030, 0x5030, 0x0007 }; ++ ++ ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, SET_ADDR_OFFSET, ++ 0x1600); ++ for (i = 0; i < ARRAY_SIZE(regs); i++) { ++ brcm_pcie_mdio_read(pcie->base, MDIO_PORT0, regsi, &tmp); ++ dev_dbg(pcie->dev, "PCIE MDIO pre_refclk 0x%02x = 0x%04x\n", ++ regsi, tmp); ++ } ++ for (i = 0; i < ARRAY_SIZE(regs); i++) { ++ brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, regsi, datai); ++ brcm_pcie_mdio_read(pcie->base, MDIO_PORT0, regsi, &tmp); ++ dev_dbg(pcie->dev, "PCIE MDIO post_refclk 0x%02x = 0x%04x\n", ++ regsi, tmp); ++ } ++ usleep_range(100, 200); ++} ++ + /* Limits operation to a specific generation (1, 2, or 3) */ + static void brcm_pcie_set_gen(struct brcm_pcie *pcie, int gen) + { +@@ -431,6 +553,99 @@ static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie, + writel(tmp, pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win)); + } + ++static void brcm_pcie_set_tc_qos(struct brcm_pcie *pcie) ++{ ++ int i; ++ u32 reg; ++ ++ if (pcie->type != BCM2712) ++ return; ++ ++ /* Disable broken QOS forwarding search. Set chicken bits for 2712D0 */ ++ reg = readl(pcie->base + PCIE_MISC_AXI_INTF_CTRL); ++ reg &= ~AXI_REQFIFO_EN_QOS_PROPAGATION; ++ reg |= AXI_EN_RCLK_QOS_ARRAY_FIX | AXI_EN_QOS_UPDATE_TIMING_FIX | ++ AXI_DIS_QOS_GATING_IN_MASTER; ++ writel(reg, pcie->base + PCIE_MISC_AXI_INTF_CTRL); ++ ++ /* Disable VDM reception by default - QoS map defaults to 0 */ ++ reg = readl(pcie->base + PCIE_MISC_CTRL_1); ++ reg &= ~PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK; ++ writel(reg, pcie->base + PCIE_MISC_CTRL_1); ++ ++ if (!of_property_read_u32(pcie->np, "brcm,fifo-qos-map", &pcie->qos_map)) { ++ /* ++ * Backpressure mode - bottom 4 nibbles are QoS for each ++ * quartile of FIFO level. Each TC gets the same map, because ++ * this mode is intended for nonrealtime EPs. ++ */ ++ ++ pcie->qos_map &= 0x0000ffff; ++ for (i = 0; i < 8; i++) ++ writel(pcie->qos_map, pcie->base + PCIE_MISC_TC_QUEUE_TO_QOS_MAP(i)); ++ ++ return; ++ } ++ ++ if (!of_property_read_u32(pcie->np, "brcm,vdm-qos-map", &pcie->qos_map)) { ++ ++ reg = readl(pcie->base + PCIE_MISC_CTRL_1); ++ reg |= PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK; ++ writel(reg, pcie->base + PCIE_MISC_CTRL_1); ++ ++ /* No forwarding means no point separating panic priorities from normal */ ++ writel(pcie->qos_map, pcie->base + PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_LO); ++ writel(pcie->qos_map, pcie->base + PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_HI); ++ ++ /* Match Vendor ID of 0 */ ++ writel(0, pcie->base + PCIE_RC_TL_VDM_CTL1); ++ /* Forward VDMs to priority interface - at least the rx counters work */ ++ reg = readl(pcie->base + PCIE_RC_TL_VDM_CTL0); ++ reg |= PCIE_RC_TL_VDM_CTL0_VDM_ENABLED_MASK | ++ PCIE_RC_TL_VDM_CTL0_VDM_IGNORETAG_MASK | ++ PCIE_RC_TL_VDM_CTL0_VDM_IGNOREVNDRID_MASK; ++ writel(reg, pcie->base + PCIE_RC_TL_VDM_CTL0); ++ } ++} ++ ++static void brcm_pcie_config_clkreq(struct brcm_pcie *pcie) ++{ ++ void __iomem *base = pcie->base; ++ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); ++ int domain = pci_domain_nr(bridge->bus); ++ const struct pci_bus *bus = pci_find_bus(domain, 1); ++ struct pci_dev *pdev = (struct pci_dev *)bus->devices.next; ++ u32 tmp, link_cap = 0; ++ u16 link_ctl = 0; ++ int clkpm = 0; ++ int substates = 0; ++ ++ pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &link_cap); ++ if ((link_cap & PCI_EXP_LNKCAP_CLKPM)) ++ clkpm = 1; ++ ++ pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &link_ctl); ++ if (!(link_ctl & PCI_EXP_LNKCTL_CLKREQ_EN)) ++ clkpm = 0; ++ ++ if (pcie->l1ss && pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS)) ++ substates = 1; ++ ++ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK; ++ tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK; ++ ++ if (substates) ++ tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK; ++ else if (clkpm) ++ tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK; ++ ++ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ ++ if (substates || clkpm) ++ dev_info(pcie->dev, "clkreq control enabled\n"); ++} ++ + static struct irq_chip brcm_msi_irq_chip = { + .name = "BRCM STB PCIe MSI", + .irq_ack = irq_chip_ack_parent, +@@ -440,14 +655,14 @@ static struct irq_chip brcm_msi_irq_chip = { 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), + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | +- MSI_FLAG_MULTI_PCI_MSI), ++ MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX), .chip = &brcm_msi_irq_chip, }; -@@ -869,6 +872,8 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) + static void brcm_pcie_msi_isr(struct irq_desc *desc) + { + struct irq_chip *chip = irq_desc_get_chip(desc); +- unsigned long status; ++ unsigned long status, virq; + struct brcm_msi *msi; + struct device *dev; + u32 bit; +@@ -459,10 +674,22 @@ static void brcm_pcie_msi_isr(struct irq_desc *desc) + status = readl(msi->intr_base + MSI_INT_STATUS); + status >>= msi->legacy_shift; + +- for_each_set_bit(bit, &status, msi->nr) { +- int ret; +- ret = generic_handle_domain_irq(msi->inner_domain, bit); +- if (ret) ++ for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR/*msi->nr*/) { ++ bool found = false; ++ ++ virq = irq_find_mapping(msi->inner_domain, bit); ++ if (virq) { ++ found = true; ++ dev_dbg(dev, "MSI -> %ld\n", virq); ++ generic_handle_irq(virq); ++ } ++ virq = irq_find_mapping(msi->inner_domain, bit + 32); ++ if (virq) { ++ found = true; ++ dev_dbg(dev, "MSI -> %ld\n", virq); ++ generic_handle_irq(virq); ++ } ++ if (!found) + dev_dbg(dev, "unexpected MSI\n"); + } + +@@ -475,7 +702,7 @@ static void brcm_msi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) + + msg->address_lo = lower_32_bits(msi->target_addr); + msg->address_hi = upper_32_bits(msi->target_addr); +- msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL_32) | data->hwirq; ++ msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL_32) | (data->hwirq & 0x1f); + } + + static int brcm_msi_set_affinity(struct irq_data *irq_data, +@@ -487,7 +714,7 @@ static int brcm_msi_set_affinity(struct irq_data *irq_data, + static void brcm_msi_ack_irq(struct irq_data *data) + { + struct brcm_msi *msi = irq_data_get_irq_chip_data(data); +- const int shift_amt = data->hwirq + msi->legacy_shift; ++ const int shift_amt = (data->hwirq & 0x1f) + msi->legacy_shift; + + writel(1 << shift_amt, msi->intr_base + MSI_INT_CLR); + } +@@ -648,7 +875,7 @@ static int brcm_pcie_enable_msi(struct brcm_pcie *pcie) + msi->legacy_shift = 24; + } else { + msi->intr_base = msi->base + PCIE_MSI_INTR2_BASE; +- msi->nr = BRCM_INT_PCI_MSI_NR; ++ msi->nr = 64; //BRCM_INT_PCI_MSI_NR; + msi->legacy_shift = 0; + } + +@@ -665,7 +892,7 @@ static int brcm_pcie_enable_msi(struct brcm_pcie *pcie) + } + + /* The controller is capable of serving in both RC and EP roles */ +-static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie) ++static bool brcm_pcie_rc_mode_generic(struct brcm_pcie *pcie) + { + void __iomem *base = pcie->base; + u32 val = readl(base + PCIE_MISC_PCIE_STATUS); +@@ -673,6 +900,14 @@ static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie) + return !!FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK, val); + } + ++static bool brcm_pcie_rc_mode_2712(struct brcm_pcie *pcie) ++{ ++ void __iomem *base = pcie->base; ++ u32 val = readl(base + PCIE_MISC_PCIE_STATUS); ++ ++ return !!FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK_2712, val) | 1; //XXX ++} ++ + static bool brcm_pcie_link_up(struct brcm_pcie *pcie) + { + u32 val = readl(pcie->base + PCIE_MISC_PCIE_STATUS); +@@ -744,6 +979,18 @@ static void brcm_pcie_bridge_sw_init_set_7278(struct brcm_pcie *pcie, u32 val) + writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); + } + ++static void brcm_pcie_bridge_sw_init_set_2712(struct brcm_pcie *pcie, u32 val) ++{ ++ if (WARN_ONCE(!pcie->bridge_reset, ++ "missing bridge reset controller\n")) ++ return; ++ ++ if (val) ++ reset_control_assert(pcie->bridge_reset); ++ else ++ reset_control_deassert(pcie->bridge_reset); ++} ++ + static void brcm_pcie_perst_set_4908(struct brcm_pcie *pcie, u32 val) + { + if (WARN_ONCE(!pcie->perst_reset, "missing PERST# reset controller\n")) +@@ -765,6 +1012,16 @@ static void brcm_pcie_perst_set_7278(struct brcm_pcie *pcie, u32 val) + writel(tmp, pcie->base + PCIE_MISC_PCIE_CTRL); + } + ++static void brcm_pcie_perst_set_2712(struct brcm_pcie *pcie, u32 val) ++{ ++ u32 tmp; ++ ++ /* Perst bit has moved and assert value is 0 */ ++ tmp = readl(pcie->base + PCIE_MISC_PCIE_CTRL); ++ u32p_replace_bits(&tmp, !val, PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK); ++ writel(tmp, pcie->base + PCIE_MISC_PCIE_CTRL); ++} ++ + static void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val) + { + u32 tmp; +@@ -791,6 +1048,8 @@ static int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie, + size += entry->res->end - entry->res->start + 1; + if (pcie_beg < lowest_pcie_addr) + lowest_pcie_addr = pcie_beg; ++ if (pcie->type == BCM2711 || pcie->type == BCM2712) ++ break; // Only consider the first entry + } + + if (lowest_pcie_addr == ~(u64)0) { +@@ -861,6 +1120,30 @@ static int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie, + return 0; + } + ++static int brcm_pcie_get_rc_bar_n(struct brcm_pcie *pcie, ++ int idx, ++ u64 *rc_bar_cpu, ++ u64 *rc_bar_size, ++ u64 *rc_bar_pci) ++{ ++ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); ++ struct resource_entry *entry; ++ int i = 0; ++ ++ resource_list_for_each_entry(entry, &bridge->dma_ranges) { ++ if (i == idx) { ++ *rc_bar_cpu = entry->res->start; ++ *rc_bar_size = entry->res->end - entry->res->start + 1; ++ *rc_bar_pci = entry->res->start - entry->offset; ++ return 0; ++ } ++ ++ i++; ++ } ++ ++ return -EINVAL; ++} ++ + static int brcm_pcie_setup(struct brcm_pcie *pcie) + { + u64 rc_bar2_offset, rc_bar2_size; +@@ -869,7 +1152,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) + struct resource_entry *entry; + u32 tmp, burst, aspm_support; + int num_out_wins = 0; +- int ret, memc; ++ int ret, memc, count, i; /* Reset the bridge */ pcie->bridge_sw_init_set(pcie, 1); -+ pcie->perst_set(pcie, 1); -+ +@@ -892,6 +1175,17 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) + /* Wait for SerDes to be stable */ usleep_range(100, 200); - /* Take the bridge out of reset */ -@@ -1025,12 +1030,25 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) - PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK); - writel(tmp, base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1); ++ if (pcie->type == BCM2712) { ++ /* Allow a 54MHz (xosc) refclk source */ ++ brcm_pcie_munge_pll(pcie); ++ /* Fix for L1SS errata */ ++ tmp = readl(base + PCIE_RC_PL_PHY_CTL_15); ++ tmp &= ~PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK; ++ /* PM clock period is 18.52ns (round down) */ ++ tmp |= 0x12; ++ writel(tmp, base + PCIE_RC_PL_PHY_CTL_15); ++ } ++ + /* + * SCB_MAX_BURST_SIZE is a two bit field. For GENERIC chips it + * is encoded as 0=128, 1=256, 2=512, 3=Rsvd, for BCM7278 it +@@ -901,6 +1195,8 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) + burst = 0x1; /* 256 bytes */ + else if (pcie->type == BCM2711) + burst = 0x0; /* 128 bytes */ ++ else if (pcie->type == BCM2712) ++ burst = 0x1; /* 128 bytes */ + else if (pcie->type == BCM7278) + burst = 0x3; /* 512 bytes */ + else +@@ -908,16 +1204,18 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) -- /* -- * 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) { + /* + * Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN, +- * RCB_MPS_MODE, RCB_64B_MODE ++ * RCB_MPS_MODE + */ + tmp = readl(base + PCIE_MISC_MISC_CTRL); + u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK); + u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK); + u32p_replace_bits(&tmp, burst, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK); +- u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_PCIE_RCB_MPS_MODE_MASK); +- u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_PCIE_RCB_64B_MODE_MASK); ++ if (pcie->rcb_mps_mode) ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_PCIE_RCB_MPS_MODE_MASK); + writel(tmp, base + PCIE_MISC_MISC_CTRL); + ++ brcm_pcie_set_tc_qos(pcie); ++ + ret = brcm_pcie_get_rc_bar2_size_and_offset(pcie, &rc_bar2_size, + &rc_bar2_offset); + if (ret) +@@ -930,7 +1228,11 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) + writel(upper_32_bits(rc_bar2_offset), + base + PCIE_MISC_RC_BAR2_CONFIG_HI); + ++ tmp = readl(base + PCIE_MISC_UBUS_BAR2_CONFIG_REMAP); ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_ACCESS_ENABLE_MASK); ++ writel(tmp, base + PCIE_MISC_UBUS_BAR2_CONFIG_REMAP); + tmp = readl(base + PCIE_MISC_MISC_CTRL); ++ + for (memc = 0; memc < pcie->num_memc; memc++) { + u32 scb_size_val = ilog2(pcie->memc_sizememc) - 15; + +@@ -941,8 +1243,32 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) + else if (memc == 2) + u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(2)); + } ++ + writel(tmp, base + PCIE_MISC_MISC_CTRL); + ++ if (pcie->type == BCM2712) { ++ /* Suppress AXI error responses and return 1s for read failures */ ++ tmp = readl(base + PCIE_MISC_UBUS_CTRL); ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_ERR_DIS_MASK); ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_DECERR_DIS_MASK); ++ writel(tmp, base + PCIE_MISC_UBUS_CTRL); ++ writel(0xffffffff, base + PCIE_MISC_AXI_READ_ERROR_DATA); ++ + /* -+ * 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. ++ * Adjust timeouts. The UBUS timeout also affects CRS ++ * completion retries, as the request will get terminated if ++ * either timeout expires, so both have to be a large value ++ * (in clocks of 750MHz). ++ * Set UBUS timeout to 250ms, then set RC config retry timeout ++ * to be ~240ms. ++ * ++ * Setting CRSVis=1 will stop the core from blocking on a CRS ++ * response, but does require the device to be well-behaved... + */ -+ tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK; -+ tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK; -+ } else { ++ writel(0xB2D0000, base + PCIE_MISC_UBUS_TIMEOUT); ++ writel(0xABA0000, base + PCIE_MISC_RC_CONFIG_RETRY_TIMEOUT); ++ } ++ + /* + * We ideally want the MSI target address to be located in the 32bit + * addressable memory area. Some devices might depend on it. This is +@@ -955,7 +1281,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) + else + pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB; + +- if (!brcm_pcie_rc_mode(pcie)) { ++ if (!pcie->rc_mode(pcie)) { + dev_err(pcie->dev, "PCIe RC controller misconfigured as Endpoint\n"); + return -EINVAL; + } +@@ -979,6 +1305,38 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK); + writel(tmp, base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY); + ++ /* program additional inbound windows (RC_BAR4..RC_BAR10) */ ++ count = (pcie->type == BCM2712) ? 7 : 0; ++ for (i = 0; i < count; i++) { ++ u64 bar_cpu, bar_size, bar_pci; ++ ++ ret = brcm_pcie_get_rc_bar_n(pcie, 1 + i, &bar_cpu, &bar_size, ++ &bar_pci); ++ if (ret) ++ break; ++ ++ tmp = lower_32_bits(bar_pci); ++ u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(bar_size), ++ PCIE_MISC_RC_BAR_CONFIG_LO_SIZE_MASK); ++ writel(tmp, base + PCIE_MISC_RC_BAR4_CONFIG_LO + i * 8); ++ writel(upper_32_bits(bar_pci), ++ base + PCIE_MISC_RC_BAR4_CONFIG_HI + i * 8); ++ ++ tmp = upper_32_bits(bar_cpu) & ++ PCIE_MISC_UBUS_BAR_CONFIG_REMAP_HI_MASK; ++ writel(tmp, ++ base + PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_HI + i * 8); ++ tmp = lower_32_bits(bar_cpu) & ++ PCIE_MISC_UBUS_BAR_CONFIG_REMAP_LO_MASK; ++ writel(tmp | PCIE_MISC_UBUS_BAR_CONFIG_REMAP_ENABLE, ++ base + PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_LO + i * 8); ++ } ++ ++ if (pcie->gen) { ++ dev_info(pcie->dev, "Forcing gen %d\n", pcie->gen); ++ brcm_pcie_set_gen(pcie, pcie->gen); ++ } ++ + /* + * For config space accesses on the RC, show the right class for + * a PCIe-PCIe bridge (the default setting is to be EP mode). +@@ -1032,13 +1390,31 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie) + { + struct device *dev = pcie->dev; + void __iomem *base = pcie->base; +- u16 nlw, cls, lnksta; ++ u16 nlw, cls, lnksta, tmp16; + bool ssc_good = false; +- u32 tmp; + int ret, i; ++ u32 tmp; + + /* Unassert the fundamental reset */ +- pcie->perst_set(pcie, 0); ++ if (pcie->tperst_clk_ms) { + /* -+ * 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; ++ * Increase Tperst_clk time by forcing PERST# output low while ++ * the internal reset is released, so the PLL generates stable ++ * refclk output further in advance of PERST# deassertion. ++ */ ++ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK); ++ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ ++ pcie->perst_set(pcie, 0); ++ msleep(pcie->tperst_clk_ms); ++ ++ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ u32p_replace_bits(&tmp, 0, PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK); ++ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ } else { ++ pcie->perst_set(pcie, 0); + } - writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); + /* + * Wait for 100ms after PERST# deassertion; see PCIe CEM specification +@@ -1070,6 +1446,7 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie) + dev_err(dev, "failed attempt to enter ssc mode\n"); + } + ++ + lnksta = readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKSTA); + cls = FIELD_GET(PCI_EXP_LNKSTA_CLS, lnksta); + nlw = FIELD_GET(PCI_EXP_LNKSTA_NLW, lnksta); +@@ -1078,13 +1455,15 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie) + ssc_good ? "(SSC)" : "(!SSC)"); + + /* +- * Refclk from RC should be gated with CLKREQ# input when ASPM L0s,L1 +- * is enabled => setting the CLKREQ_DEBUG_ENABLE field to 1. ++ * RootCtl bits are reset by perst_n, which undoes pci_enable_crs() ++ * called prior to pci_add_new_bus() during probe. Re-enable here. + */ +- tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); +- tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK; +- writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); +- ++ tmp16 = readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_RTCAP); ++ if (tmp16 & PCI_EXP_RTCAP_CRSVIS) { ++ tmp16 = readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_RTCTL); ++ u16p_replace_bits(&tmp16, 1, PCI_EXP_RTCTL_CRSSVE); ++ writew(tmp16, base + BRCM_PCIE_CAP_REGS + PCI_EXP_RTCTL); ++ } return 0; -@@ -1251,6 +1269,7 @@ static int brcm_pcie_probe(struct platform_device *pdev) + } + +@@ -1192,6 +1571,7 @@ static void brcm_pcie_enter_l23(struct brcm_pcie *pcie) + + static int brcm_phy_cntl(struct brcm_pcie *pcie, const int start) + { ++#if 0 + static const u32 shiftsPCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS = { + PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_SHIFT, + PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_SHIFT, +@@ -1224,6 +1604,9 @@ static int brcm_phy_cntl(struct brcm_pcie *pcie, const int start) + dev_err(pcie->dev, "failed to %s phy\n", (start ? "start" : "stop")); + + return ret; ++#else ++ return 0; ++#endif + } + + static inline int brcm_phy_start(struct brcm_pcie *pcie) +@@ -1256,6 +1639,12 @@ static void brcm_pcie_turn_off(struct brcm_pcie *pcie) + u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK); + writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); + ++ /* ++ * Shutting down this bridge on pcie1 means accesses to rescal block ++ * will hang the chip if another RC wants to assert/deassert rescal. ++ */ ++ if (pcie->type == BCM2712) ++ return; + /* Shutdown PCIe bridge */ + pcie->bridge_sw_init_set(pcie, 1); + } +@@ -1286,9 +1675,9 @@ static int brcm_pcie_suspend_noirq(struct device *dev) + if (brcm_phy_stop(pcie)) + dev_err(dev, "Could not stop phy for suspend\n"); + +- ret = reset_control_rearm(pcie->rescal); ++ ret = reset_control_assert(pcie->rescal); + if (ret) { +- dev_err(dev, "Could not rearm rescal reset\n"); ++ dev_err(dev, "Could not assert rescal reset\n"); + return ret; + } + +@@ -1383,7 +1772,7 @@ static int brcm_pcie_resume_noirq(struct device *dev) + if (pcie->sr) + regulator_bulk_disable(pcie->sr->num_supplies, pcie->sr->supplies); + err_reset: +- reset_control_rearm(pcie->rescal); ++ reset_control_assert(pcie->rescal); + err_disable_clk: + clk_disable_unprepare(pcie->clk); + return ret; +@@ -1395,8 +1784,8 @@ static void __brcm_pcie_remove(struct brcm_pcie *pcie) + brcm_pcie_turn_off(pcie); + if (brcm_phy_stop(pcie)) + dev_err(pcie->dev, "Could not stop phy\n"); +- if (reset_control_rearm(pcie->rescal)) +- dev_err(pcie->dev, "Could not rearm rescal reset\n"); ++ if (reset_control_assert(pcie->rescal)) ++ dev_err(pcie->dev, "Could not assert rescal reset\n"); + clk_disable_unprepare(pcie->clk); + } + +@@ -1414,12 +1803,16 @@ static const int pcie_offsets = { + RGR1_SW_INIT_1 = 0x9210, + EXT_CFG_INDEX = 0x9000, + EXT_CFG_DATA = 0x9004, ++ PCIE_HARD_DEBUG = 0x4204, ++ INTR2_CPU = 0x4300, + }; + + static const int pcie_offsets_bmips_7425 = { + RGR1_SW_INIT_1 = 0x8010, + EXT_CFG_INDEX = 0x8300, + EXT_CFG_DATA = 0x8304, ++ PCIE_HARD_DEBUG = 0x4204, ++ INTR2_CPU = 0x4300, + }; + + static const struct pcie_cfg_data generic_cfg = { +@@ -1427,6 +1820,7 @@ static const struct pcie_cfg_data generic_cfg = { + .type = GENERIC, + .perst_set = brcm_pcie_perst_set_generic, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, ++ .rc_mode = brcm_pcie_rc_mode_generic, + }; + + static const struct pcie_cfg_data bcm7425_cfg = { +@@ -1434,6 +1828,7 @@ static const struct pcie_cfg_data bcm7425_cfg = { + .type = BCM7425, + .perst_set = brcm_pcie_perst_set_generic, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, ++ .rc_mode = brcm_pcie_rc_mode_generic, + }; + + static const struct pcie_cfg_data bcm7435_cfg = { +@@ -1448,12 +1843,15 @@ static const struct pcie_cfg_data bcm4908_cfg = { + .type = BCM4908, + .perst_set = brcm_pcie_perst_set_4908, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, ++ .rc_mode = brcm_pcie_rc_mode_generic, + }; + + static const int pcie_offset_bcm7278 = { + RGR1_SW_INIT_1 = 0xc010, + EXT_CFG_INDEX = 0x9000, + EXT_CFG_DATA = 0x9004, ++ PCIE_HARD_DEBUG = 0x4204, ++ INTR2_CPU = 0x4300, + }; + + static const struct pcie_cfg_data bcm7278_cfg = { +@@ -1461,6 +1859,7 @@ static const struct pcie_cfg_data bcm7278_cfg = { + .type = BCM7278, + .perst_set = brcm_pcie_perst_set_7278, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_7278, ++ .rc_mode = brcm_pcie_rc_mode_generic, + }; + + static const struct pcie_cfg_data bcm2711_cfg = { +@@ -1468,10 +1867,27 @@ static const struct pcie_cfg_data bcm2711_cfg = { + .type = BCM2711, + .perst_set = brcm_pcie_perst_set_generic, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, ++ .rc_mode = brcm_pcie_rc_mode_generic, ++}; ++ ++static const int pcie_offsets_bcm2712 = { ++ EXT_CFG_INDEX = 0x9000, ++ EXT_CFG_DATA = 0x9004, ++ PCIE_HARD_DEBUG = 0x4304, ++ INTR2_CPU = 0x4400, ++}; ++ ++static const struct pcie_cfg_data bcm2712_cfg = { ++ .offsets = pcie_offsets_bcm2712, ++ .type = BCM2712, ++ .perst_set = brcm_pcie_perst_set_2712, ++ .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_2712, ++ .rc_mode = brcm_pcie_rc_mode_2712, + }; + + static const struct of_device_id brcm_pcie_match = { + { .compatible = "brcm,bcm2711-pcie", .data = &bcm2711_cfg }, ++ { .compatible = "brcm,bcm2712-pcie", .data = &bcm2712_cfg }, + { .compatible = "brcm,bcm4908-pcie", .data = &bcm4908_cfg }, + { .compatible = "brcm,bcm7211-pcie", .data = &generic_cfg }, + { .compatible = "brcm,bcm7278-pcie", .data = &bcm7278_cfg }, +@@ -1512,7 +1928,7 @@ static int brcm_pcie_probe(struct platform_device *pdev) + + data = of_device_get_match_data(&pdev->dev); + if (!data) { +- pr_err("failed to look up compatible string\n"); ++ dev_err(&pdev->dev, "failed to look up compatible string\n"); + return -EINVAL; + } + +@@ -1523,6 +1939,7 @@ static int brcm_pcie_probe(struct platform_device *pdev) + pcie->type = data->type; + pcie->perst_set = data->perst_set; + pcie->bridge_sw_init_set = data->bridge_sw_init_set; ++ pcie->rc_mode = data->rc_mode; + + pcie->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pcie->base)) +@@ -1536,6 +1953,9 @@ static int brcm_pcie_probe(struct platform_device *pdev) 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"); ++ pcie->rcb_mps_mode = of_property_read_bool(np, "brcm,enable-mps-rcb"); ++ of_property_read_u32(np, "brcm,tperst-clk-ms", &pcie->tperst_clk_ms); ret = clk_prepare_enable(pcie->clk); if (ret) { +@@ -1552,14 +1972,20 @@ static int brcm_pcie_probe(struct platform_device *pdev) + clk_disable_unprepare(pcie->clk); + return PTR_ERR(pcie->perst_reset); + } ++ pcie->bridge_reset = ++ devm_reset_control_get_optional_exclusive(&pdev->dev, "bridge"); ++ if (IS_ERR(pcie->bridge_reset)) { ++ clk_disable_unprepare(pcie->clk); ++ return PTR_ERR(pcie->bridge_reset); ++ } + +- ret = reset_control_reset(pcie->rescal); ++ ret = reset_control_deassert(pcie->rescal); + if (ret) + dev_err(&pdev->dev, "failed to deassert 'rescal'\n"); + + ret = brcm_phy_start(pcie); + if (ret) { +- reset_control_rearm(pcie->rescal); ++ reset_control_assert(pcie->rescal); + clk_disable_unprepare(pcie->clk); + return ret; + } +@@ -1582,6 +2008,33 @@ static int brcm_pcie_probe(struct platform_device *pdev) + dev_err(pcie->dev, "probe of internal MSI failed"); + goto fail; + } ++ } else if (pci_msi_enabled() && msi_np != pcie->np) { ++ /* Use RC_BAR1 for MIP access */ ++ u64 msi_pci_addr; ++ u64 msi_phys_addr; ++ ++ if (of_property_read_u64(msi_np, "brcm,msi-pci-addr", &msi_pci_addr)) { ++ dev_err(pcie->dev, "Unable to find MSI PCI address\n"); ++ ret = -EINVAL; ++ goto fail; ++ } ++ ++ if (of_property_read_u64(msi_np, "reg", &msi_phys_addr)) { ++ dev_err(pcie->dev, "Unable to find MSI physical address\n"); ++ ret = -EINVAL; ++ goto fail; ++ } ++ ++ writel(lower_32_bits(msi_pci_addr) | brcm_pcie_encode_ibar_size(0x1000), ++ pcie->base + PCIE_MISC_RC_BAR1_CONFIG_LO); ++ writel(upper_32_bits(msi_pci_addr), ++ pcie->base + PCIE_MISC_RC_BAR1_CONFIG_HI); ++ ++ writel(lower_32_bits(msi_phys_addr) | ++ PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_ACCESS_ENABLE_MASK, ++ pcie->base + PCIE_MISC_UBUS_BAR1_CONFIG_REMAP); ++ writel(upper_32_bits(msi_phys_addr), ++ pcie->base + PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_HI); + } + + bridge->ops = pcie->type == BCM7425 ? &brcm7425_pcie_ops : &brcm_pcie_ops; +@@ -1598,6 +2051,8 @@ static int brcm_pcie_probe(struct platform_device *pdev) + return ret; + } + ++ brcm_pcie_config_clkreq(pcie); ++ + return 0; + + fail: diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig -index 1e82ab01e75f..585a4411c90b 100644 +index 273d67ecf6d2..b73a4880578e 100644 --- a/drivers/perf/Kconfig +++ b/drivers/perf/Kconfig -@@ -130,6 +130,14 @@ config ARM_SPE_PMU - Extension, which provides periodic sampling of operations in - the CPU pipeline and reports this via the perf AUX interface. +@@ -208,6 +208,14 @@ config ALIBABA_UNCORE_DRW_PMU + Support for Driveway PMU events monitoring on Yitian 710 DDR + Sub-system. +config RPI_AXIPERF + depends on ARCH_BCM2835 @@ -97594,22 +147331,22 @@ + source "drivers/perf/hisilicon/Kconfig" - endmenu + config MARVELL_CN10K_DDR_PMU diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile -index 5365fd56f88f..fe8c4eb61511 100644 +index 16b3ec4db916..d33610e432dc 100644 --- a/drivers/perf/Makefile +++ b/drivers/perf/Makefile -@@ -13,3 +13,4 @@ obj-$(CONFIG_QCOM_L3_PMU) += qcom_l3_pmu.o - obj-$(CONFIG_THUNDERX2_PMU) += thunderx2_pmu.o - obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o - obj-$(CONFIG_ARM_SPE_PMU) += arm_spe_pmu.o +@@ -26,3 +26,4 @@ obj-$(CONFIG_ALIBABA_UNCORE_DRW_PMU) += alibaba_uncore_drw_pmu.o + obj-$(CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU) += arm_cspmu/ + obj-$(CONFIG_MESON_DDR_PMU) += amlogic/ + obj-$(CONFIG_CXL_PMU) += cxl_pmu.o +obj-$(CONFIG_RPI_AXIPERF) += raspberrypi_axi_monitor.o diff --git a/drivers/perf/raspberrypi_axi_monitor.c b/drivers/perf/raspberrypi_axi_monitor.c new file mode 100644 -index 000000000000..5ae2bdaa88b4 +index 000000000000..0bdc04d5085f --- /dev/null +++ b/drivers/perf/raspberrypi_axi_monitor.c -@@ -0,0 +1,637 @@ +@@ -0,0 +1,830 @@ +/* + * raspberrypi_axi_monitor.c + * @@ -97645,7 +147382,7 @@ +#define MAX_BUSES 16 +#define DEFAULT_SAMPLE_TIME 100 + -+#define NUM_BUS_WATCHER_RESULTS 9 ++#define NUM_BUS_WATCHER_RESULTS 11 + +struct bus_watcher_data { + union { @@ -97660,6 +147397,8 @@ + u32 rtrans; + u32 rtwait; + u32 rmax; ++ u32 rpend; ++ u32 ratrans; + }; + }; +}; @@ -97677,6 +147416,9 @@ + /* Sample time spent on for each bus */ + int sample_time; + ++ /* chip specific bus config */ ++ const struct bwconfig_config *config; ++ + /* Now storage for the per monitor settings and the resulting + * performance figures + */ @@ -97719,6 +147461,7 @@ + +const int GEN_CTL_ENABLE_BIT = BIT(0); +const int GEN_CTL_RESET_BIT = BIT(1); ++const int GEN_CTL_WATCH_BIT = BIT(2); + +/* Bus watcher registers */ +const int BW_PITCH = 0x40; @@ -97748,7 +147491,7 @@ +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 = { ++static const char *bus_filter_strings = { + "", + "CORE0_V", + "ICACHE0", @@ -97783,9 +147526,96 @@ + "M30" +}; + -+const int num_bus_filters = ARRAY_SIZE(bus_filter_strings); ++static const char * const bus_filter_strings_2711 = { ++ "AIO", ++ "CORE0_V", ++ "ICACHE0", ++ "DCACHE0", ++ "CORE1_V", ++ "ICACHE1", ++ "DCACHE1", ++ "L2_MAIN", ++ "ARGON", ++ "PCIE", ++ "HVS", ++ "ISP", ++ "VIDEO_DCT", ++ "VIDEO_SD2AXI", ++ "CAM0", ++ "CAM1", ++ "DMA0", ++ "DMA1", ++ "DMA2", ++ "JPEG", ++ "VIDEO_CME", ++ "TRANSPOSER", ++ "VIDEO_FME", ++ "GIGE", ++ "USB", ++ "V3D0", ++ "V3D1", ++ "V3D2", ++ "GISB_AXI", ++ "DEBUG", ++ "ARM", ++ "EMMCSTB", ++}; ++ ++static const char * const bus_filter_strings_2712 = { ++ "", ++ "VPU_UC0", ++ "VPU_IC0", ++ "VPU_DC0", ++ "VPU_UC1", ++ "VPU_IC1", ++ "VPU_DC1", ++ "VPU_L2", ++ "DMA2", ++ "VPU_DEBUG", ++ "ARM", ++ "DMA0", ++ "DMA1", ++ "RAAGA", ++ "BBSI", ++ "PCIE0", ++ "PCIE1", ++ "PCIE2", ++ "UMR", ++ "SAGE", ++ "HVDP", ++ "BSP", ++ "HVS", ++ "HVS_WMK", ++ "MOP0", ++ "MOP1", ++ "MBVN", ++ "DSI", ++ "XPT", ++ "EMMC0", ++ "GENET", ++ "USB", ++ "ARGON", ++ "UNICAM", ++ "PISP", ++ "PISPFE", ++ "JPEG", ++ "EMMC1", ++ "EMMC2", ++ "TRC", ++ "BSTM0", ++ "BSTM1", ++ "BSTM0_SEC", ++ "BSTM1_SEC", ++ "AIO", ++ "MAP", ++ "SYS_DMA", ++ "MMUCACHE0", ++ "MMUCACHE1", ++ "MPUCACHE0", ++ "MPUCACHE1", ++}; + -+const static char *system_bus_string = { ++static const char *system_bus_string = { + "DMA_L2", + "TRANS", + "JPEG", @@ -97804,9 +147634,38 @@ + "CPU_L2" +}; + -+const int num_system_buses = ARRAY_SIZE(system_bus_string); ++static const char * const system_bus_string_2711 = { ++ "DMA_L2", ++ "TRANS", ++ "JPEG", ++ "VPU_UC", ++ "DMA_UC", ++ "SYSTEM_L2", ++ "HVS", ++ "ARGON", ++ "H264", ++ "PERIPHERAL", ++ "ARM_UC", ++ "ARM_L2", ++}; ++ ++static const char * const system_bus_string_2712 = { ++ "VPU_UC", ++ "DISPLAY_TOP", ++ "V3D", ++ "ARM", ++ "XPT", ++ "BSTM_TOP", ++ "PCIE_01", ++ "ARGON_TOP", ++ "ARB3", ++ "SRC", ++ "HVDP", ++ "PER", ++ "SYSTEM_L2", ++}; + -+const static char *vpu_bus_string = { ++static const char *vpu_bus_string = { + "VPU1_D_L2", + "VPU0_D_L2", + "VPU1_I_L2", @@ -97825,7 +147684,66 @@ + "L2_IN" +}; + -+const int num_vpu_buses = ARRAY_SIZE(vpu_bus_string); ++static const char * const vpu_bus_string_2711 = { ++ "VPU1_D_L2", ++ "VPU0_D_L2", ++ "VPU1_I_L2", ++ "VPU0_I_L2", ++ "SYSTEM_L2", ++ "DMA_L2", ++ "VPU1_D_UC", ++ "VPU0_D_UC", ++ "VPU1_I_UC", ++ "VPU0_I_UC", ++ "VPU_UC", ++ "L2_OUT", ++ "DMA_UC", ++ "L2_IN" ++}; ++ ++static const char * const vpu_bus_string_2712 = { ++ "VPU1_D_L2", ++ "VPU0_D_L2", ++ "VPU1_I_L2", ++ "VPU0_I_L2", ++ "SYSTEM_L2", ++ "DMA_L2", ++ "VPU1_D_UC", ++ "VPU0_D_UC", ++ "VPU1_I_UC", ++ "VPU0_I_UC", ++ "VPU_UC", ++ "L2_OUT", ++ "DMA_UC", ++ "L2_IN" ++}; ++ ++struct bwconfig_config { ++ const char * const *bus_filter_strings; ++ const int num_bus_filters; ++ const char * const *system_bus_string; ++ const int num_system_buses; ++ const char * const *vpu_bus_string; ++ const int num_vpu_buses; ++}; ++ ++static const struct bwconfig_config config_2835 = { ++ bus_filter_strings, ARRAY_SIZE(bus_filter_strings), ++ system_bus_string, ARRAY_SIZE(system_bus_string), ++ vpu_bus_string, ARRAY_SIZE(vpu_bus_string), ++}; ++ ++static const struct bwconfig_config config_2711 = { ++ bus_filter_strings_2711, ARRAY_SIZE(bus_filter_strings_2711), ++ system_bus_string_2711, ARRAY_SIZE(system_bus_string_2711), ++ vpu_bus_string_2711, ARRAY_SIZE(vpu_bus_string_2711), ++}; ++ ++static const struct bwconfig_config config_2712 = { ++ bus_filter_strings_2712, ARRAY_SIZE(bus_filter_strings_2712), ++ system_bus_string_2712, ARRAY_SIZE(system_bus_string_2712), ++ vpu_bus_string_2712, ARRAY_SIZE(vpu_bus_string_2712), ++}; + +const static char *monitor_name = { + "System", @@ -97845,10 +147763,10 @@ +static void read_bus_watcher(int monitor, int watcher, u32 *results) +{ + if (state->monitormonitor.use_mailbox_interface) { -+ /* We have 9 results, plus the overheads of start address and -+ * length So 11 u32 to define ++ /* We have NUM_BUS_WATCHER_RESULTS results, plus the overheads ++ * of start address and length + */ -+ u32 tmp11; ++ u32 tmpNUM_BUS_WATCHER_RESULTS+2; + int err; + + tmp0 = (u32)(uintptr_t)(state->monitormonitor.base_address + watcher @@ -97964,7 +147882,7 @@ + } + + /* start monitoring */ -+ set_monitor_control(monitor, GEN_CTL_ENABLE_BIT); ++ set_monitor_control(monitor, GEN_CTL_ENABLE_BIT | GEN_CTL_WATCH_BIT); + } + + mutex_unlock(&state->lock); @@ -98021,11 +147939,12 @@ + int buff_size = INIT_BUFF_SIZE; + char *p; + typeof(state->monitor0) *mon = &(state->monitoridx); ++ const struct bwconfig_config *config = state->config; + + if (idx < 0 || idx > NUM_MONITORS) + idx = 0; + -+ num_buses = idx == SYSTEM_MONITOR ? num_system_buses : num_vpu_buses; ++ num_buses = idx == SYSTEM_MONITOR ? config->num_system_buses : config->num_vpu_buses; + + string_buffer = kmalloc(buff_size, GFP_KERNEL); + @@ -98040,17 +147959,17 @@ + mutex_lock(&state->lock); + + if (mon->bus_filter) { -+ int filt = min(mon->bus_filter & 0x1f, num_bus_filters); ++ int filt = min(mon->bus_filter & 0x1f, config->num_bus_filters); + + cnt = snprintf(p, buff_size, + "\nMonitoring transactions from %s only\n", -+ bus_filter_stringsfilt); ++ config->bus_filter_stringsfilt); + p += cnt; + buff_size -= cnt; + } + -+ cnt = snprintf(p, buff_size, " Bus | Atrans Atwait AMax Wtrans Wtwait WMax Rtrans Rtwait RMax\n" -+ "======================================================================================================\n"); ++ cnt = snprintf(p, buff_size, " Bus | Atrans Atwait AMax Wtrans Wtwait WMax Rtrans Rtwait RMax RPend RAtrans\n" ++ "===========================================================================================================================\n"); + + if (cnt >= buff_size) + goto done; @@ -98058,25 +147977,29 @@ + p += cnt; + buff_size -= cnt; + ++#define M(x) ((x) >= 1000000000 ? (x)/1000000 : (x) >= 1000 ? (x)/1000 : (x)) ++#define N(x) ((x) >= 1000000000 ? 'M' : (x) >= 1000 ? 'K' : ' ') ++ + for (i = 0; i < num_buses; i++) { + if (mon->bus_enabled & (1 << i)) { -+#define DIVIDER (1024) + typeof(mon->results0) *res = &(mon->resultsi); + + cnt = snprintf(p, buff_size, -+ "%10s | %8uK %8uK %8uK %8uK %8uK %8uK %8uK %8uK %8uK\n", ++ "%11s | %8u%c %8u%c %8u%c %8u%c %8u%c %8u%c %8u%c %8u%c %8u%c %8u%c %8u%c\n", + idx == SYSTEM_MONITOR ? -+ system_bus_stringi : -+ vpu_bus_stringi, -+ 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 ++ config->system_bus_stringi : ++ config->vpu_bus_stringi, ++ M(res->atrans), N(res->atrans), ++ M(res->atwait), N(res->atwait), ++ M(res->amax), N(res->amax), ++ M(res->wtrans), N(res->wtrans), ++ M(res->wtwait), N(res->wtwait), ++ M(res->wmax), N(res->wmax), ++ M(res->rtrans), N(res->rtrans), ++ M(res->rtwait), N(res->rtwait), ++ M(res->rmax), N(res->rmax), ++ M(res->rpend), N(res->rpend), ++ M(res->ratrans), N(res->ratrans) + ); + if (cnt >= buff_size) + goto done; @@ -98138,6 +148061,10 @@ + if (!state) + return -ENOMEM; + ++ state->config = of_device_get_match_data(dev); ++ if (!state->config) ++ return -EINVAL; ++ + /* Get the firmware handle for future rpi-firmware-xxx calls */ + fw_node = of_parse_phandle(np, "firmware", 0); + if (!fw_node) { @@ -98224,9 +148151,12 @@ +} + +static const struct of_device_id rpi_axiperf_match = { -+ { -+ .compatible = "brcm,bcm2835-axiperf", -+ }, ++ { .compatible = "brcm,bcm2835-axiperf", ++ .data = &config_2835 }, ++ { .compatible = "brcm,bcm2711-axiperf", ++ .data = &config_2711 }, ++ { .compatible = "brcm,bcm2712-axiperf", ++ .data = &config_2712 }, + {}, +}; +MODULE_DEVICE_TABLE(of, rpi_axiperf_match); @@ -98247,45 +148177,1562 @@ +MODULE_DESCRIPTION("RPI AXI Performance monitor driver"); +MODULE_LICENSE("GPL"); + +diff --git a/drivers/phy/broadcom/Kconfig b/drivers/phy/broadcom/Kconfig +index 1d89a2fd9b79..a67ac49a0d59 100644 +--- a/drivers/phy/broadcom/Kconfig ++++ b/drivers/phy/broadcom/Kconfig +@@ -93,7 +93,7 @@ config PHY_BRCM_SATA + + config PHY_BRCM_USB + tristate "Broadcom STB USB PHY driver" +- depends on ARCH_BCMBCA || ARCH_BRCMSTB || COMPILE_TEST ++ depends on ARCH_BCMBCA || ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST + depends on OF + select GENERIC_PHY + select SOC_BRCMSTB if ARCH_BRCMSTB +diff --git a/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c b/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c +index 4c10cafded4e..8d9e91c99bb4 100644 +--- a/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c ++++ b/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c +@@ -335,6 +335,36 @@ static void usb_init_common_7216(struct brcm_usb_init_params *params) + usb_init_common(params); + } + ++static void usb_init_common_2712(struct brcm_usb_init_params *params) ++{ ++ void __iomem *ctrl = params->regsBRCM_REGS_CTRL; ++ void __iomem *bdc_ec = params->regsBRCM_REGS_BDC_EC; ++ u32 reg; ++ ++ if (params->syscon_piarbctl) ++ syscon_piarbctl_init(params->syscon_piarbctl); ++ ++ USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN); ++ ++ usb_wake_enable_7211b0(params, false); ++ ++ usb_init_common(params); ++ ++ /* ++ * The BDC controller will get occasional failures with ++ * the default "Read Transaction Size" of 6 (1024 bytes). ++ * Set it to 4 (256 bytes). ++ */ ++ if ((params->supported_port_modes != USB_CTLR_MODE_HOST) && bdc_ec) { ++ reg = brcm_usb_readl(bdc_ec + BDC_EC_AXIRDA); ++ reg &= ~BDC_EC_AXIRDA_RTS_MASK; ++ reg |= (0x4 << BDC_EC_AXIRDA_RTS_SHIFT); ++ brcm_usb_writel(reg, bdc_ec + BDC_EC_AXIRDA); ++ } ++ ++ usb2_eye_fix_7211b0(params); ++} ++ + static void usb_init_xhci(struct brcm_usb_init_params *params) + { + pr_debug("%s\n", __func__); +@@ -380,6 +410,18 @@ static void usb_uninit_common_7211b0(struct brcm_usb_init_params *params) + + } + ++static void usb_uninit_common_2712(struct brcm_usb_init_params *params) ++{ ++ void __iomem *ctrl = params->regsBRCM_REGS_CTRL; ++ ++ if (params->wake_enabled) { ++ USB_CTRL_SET(ctrl, TEST_PORT_CTL, TPOUT_SEL_PME_GEN); ++ usb_wake_enable_7211b0(params, true); ++ } else { ++ USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN); ++ } ++} ++ + static void usb_uninit_xhci(struct brcm_usb_init_params *params) + { + +@@ -434,6 +476,16 @@ static const struct brcm_usb_init_ops bcm7211b0_ops = { + .set_dual_select = usb_set_dual_select, + }; + ++static const struct brcm_usb_init_ops bcm2712_ops = { ++ .init_ipp = usb_init_ipp, ++ .init_common = usb_init_common_2712, ++ .init_xhci = usb_init_xhci, ++ .uninit_common = usb_uninit_common_2712, ++ .uninit_xhci = usb_uninit_xhci, ++ .get_dual_select = usb_get_dual_select, ++ .set_dual_select = usb_set_dual_select, ++}; ++ + void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params) + { + +@@ -451,3 +503,10 @@ void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params) + params->family_name = "7211"; + params->ops = &bcm7211b0_ops; + } ++ ++void brcm_usb_dvr_init_2712(struct brcm_usb_init_params *params) ++{ ++ params->family_name = "2712"; ++ params->ops = &bcm2712_ops; ++ params->suspend_with_clocks = true; ++} +diff --git a/drivers/phy/broadcom/phy-brcm-usb-init.h b/drivers/phy/broadcom/phy-brcm-usb-init.h +index c1a88f5cd4cd..67083474126d 100644 +--- a/drivers/phy/broadcom/phy-brcm-usb-init.h ++++ b/drivers/phy/broadcom/phy-brcm-usb-init.h +@@ -70,12 +70,14 @@ struct brcm_usb_init_params { + const struct brcm_usb_init_ops *ops; + struct regmap *syscon_piarbctl; + bool wake_enabled; ++ bool suspend_with_clocks; + }; + + void brcm_usb_dvr_init_4908(struct brcm_usb_init_params *params); + void brcm_usb_dvr_init_7445(struct brcm_usb_init_params *params); + void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params); + void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params); ++void brcm_usb_dvr_init_2712(struct brcm_usb_init_params *params); + + static inline u32 brcm_usb_readl(void __iomem *addr) + { +diff --git a/drivers/phy/broadcom/phy-brcm-usb.c b/drivers/phy/broadcom/phy-brcm-usb.c +index a16f0b58eb74..edac75f59879 100644 +--- a/drivers/phy/broadcom/phy-brcm-usb.c ++++ b/drivers/phy/broadcom/phy-brcm-usb.c +@@ -75,7 +75,7 @@ struct brcm_usb_phy_data { + }; + + static s8 *node_reg_namesBRCM_REGS_MAX = { +- "crtl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec" ++ "ctrl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec" + }; + + static int brcm_pm_notifier(struct notifier_block *notifier, +@@ -315,6 +315,18 @@ static const struct match_chip_info chip_info_7211b0 = { + .optional_reg = BRCM_REGS_BDC_EC, + }; + ++static const struct match_chip_info chip_info_2712 = { ++ .init_func = &brcm_usb_dvr_init_2712, ++ .required_regs = { ++ BRCM_REGS_CTRL, ++ BRCM_REGS_XHCI_EC, ++ BRCM_REGS_XHCI_GBL, ++ BRCM_REGS_USB_MDIO, ++ -1, ++ }, ++ .optional_reg = BRCM_REGS_BDC_EC, ++}; ++ + static const struct match_chip_info chip_info_7445 = { + .init_func = &brcm_usb_dvr_init_7445, + .required_regs = { +@@ -337,6 +349,10 @@ static const struct of_device_id brcm_usb_dt_ids = { + .compatible = "brcm,bcm7211-usb-phy", + .data = &chip_info_7211b0, + }, ++ { ++ .compatible = "brcm,bcm2712-usb-phy", ++ .data = &chip_info_2712, ++ }, + { + .compatible = "brcm,brcmstb-usb-phy", + .data = &chip_info_7445, +diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig +index 79753411b778..ba97f86d0c8f 100644 +--- a/drivers/pinctrl/Kconfig ++++ b/drivers/pinctrl/Kconfig +@@ -505,6 +505,13 @@ config PINCTRL_MLXBF3 + each pin. This driver can also be built as a module called + pinctrl-mlxbf3. + ++config PINCTRL_RP1 ++ bool "Pinctrl driver for RP1" ++ select PINMUX ++ select PINCONF ++ select GENERIC_PINCONF ++ select GPIOLIB_IRQCHIP ++ + source "drivers/pinctrl/actions/Kconfig" + source "drivers/pinctrl/aspeed/Kconfig" + source "drivers/pinctrl/bcm/Kconfig" +diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile +index 4275eca92488..edc10368d47f 100644 +--- a/drivers/pinctrl/Makefile ++++ b/drivers/pinctrl/Makefile +@@ -43,6 +43,7 @@ obj-$(CONFIG_PINCTRL_PIC32) += pinctrl-pic32.o + obj-$(CONFIG_PINCTRL_PISTACHIO) += pinctrl-pistachio.o + obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o + obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o ++obj-$(CONFIG_PINCTRL_RP1) += pinctrl-rp1.o + obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o + obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o + obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o +diff --git a/drivers/pinctrl/bcm/Kconfig b/drivers/pinctrl/bcm/Kconfig +index 35b51ce4298e..f2ce009999e7 100644 +--- a/drivers/pinctrl/bcm/Kconfig ++++ b/drivers/pinctrl/bcm/Kconfig +@@ -3,6 +3,15 @@ + # Broadcom pinctrl drivers + # + ++config PINCTRL_BCM2712 ++ bool "Broadcom BCM2712 PINCONF driver" ++ depends on OF && (ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST) ++ select PINMUX ++ select PINCONF ++ select GENERIC_PINCONF ++ help ++ Say Y here to enable the Broadcom BCM2712 PINCONF driver. ++ + config PINCTRL_BCM281XX + bool "Broadcom BCM281xx pinctrl driver" + depends on OF && (ARCH_BCM_MOBILE || COMPILE_TEST) +diff --git a/drivers/pinctrl/bcm/Makefile b/drivers/pinctrl/bcm/Makefile +index 82b868ec1471..d298e4785829 100644 +--- a/drivers/pinctrl/bcm/Makefile ++++ b/drivers/pinctrl/bcm/Makefile +@@ -1,6 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + # Broadcom pinctrl support + ++obj-$(CONFIG_PINCTRL_BCM2712) += pinctrl-bcm2712.o + obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o + obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o + obj-$(CONFIG_PINCTRL_BCM4908) += pinctrl-bcm4908.o +diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2712.c b/drivers/pinctrl/bcm/pinctrl-bcm2712.c +new file mode 100644 +index 000000000000..80a6aea8d6c9 +--- /dev/null ++++ b/drivers/pinctrl/bcm/pinctrl-bcm2712.c +@@ -0,0 +1,1247 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Driver for Broadcom BCM2712 GPIO units (pinctrl only) ++ * ++ * Copyright (C) 2021-3 Raspberry Pi Ltd. ++ * Copyright (C) 2012 Chris Boot, Simon Arlott, Stephen Warren ++ * ++ * Based heavily on the BCM2835 GPIO & pinctrl driver, which was inspired by: ++ * pinctrl-nomadik.c, please see original file for copyright information ++ * pinctrl-tegra.c, please see original file for copyright information ++ */ ++ ++#include <linux/bitmap.h> ++#include <linux/bug.h> ++#include <linux/delay.h> ++#include <linux/device.h> ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/of_address.h> ++#include <linux/of.h> ++#include <linux/pinctrl/consumer.h> ++#include <linux/pinctrl/machine.h> ++#include <linux/pinctrl/pinconf.h> ++#include <linux/pinctrl/pinctrl.h> ++#include <linux/pinctrl/pinmux.h> ++#include <linux/pinctrl/pinconf-generic.h> ++#include <linux/platform_device.h> ++#include <linux/seq_file.h> ++#include <linux/slab.h> ++#include <linux/spinlock.h> ++#include <linux/types.h> ++ ++#define MODULE_NAME "pinctrl-bcm2712" ++ ++/* Register offsets */ ++ ++#define BCM2712_PULL_NONE 0 ++#define BCM2712_PULL_DOWN 1 ++#define BCM2712_PULL_UP 2 ++#define BCM2712_PULL_MASK 0x3 ++ ++#define BCM2712_FSEL_COUNT 9 ++#define BCM2712_FSEL_MASK 0xf ++ ++#define FUNC(f) \ ++ func_##f = #f ++#define PIN(i, f1, f2, f3, f4, f5, f6, f7, f8) \ ++ i = { \ ++ .funcs = { \ ++ func_##f1, \ ++ func_##f2, \ ++ func_##f3, \ ++ func_##f4, \ ++ func_##f5, \ ++ func_##f6, \ ++ func_##f7, \ ++ func_##f8, \ ++ }, \ ++ } ++ ++#define MUX_BIT_VALID 0x8000 ++#define REG_BIT_INVALID 0xffff ++ ++#define BIT_TO_REG(b) (((b) >> 5) << 2) ++#define BIT_TO_SHIFT(b) ((b) & 0x1f) ++ ++#define MUX_BIT(mr, mb) (MUX_BIT_VALID + ((mr)*4)*8 + (mb)*4) ++#define GPIO_REGS(n, mr, mb, pr, pb) \ ++ n = { MUX_BIT(mr, mb), ((pr)*4)*8 + (pb)*2 } ++ ++#define EMMC_REGS(n, pr, pb) \ ++ n = { 0, ((pr)*4)*8 + (pb)*2 } ++ ++#define AGPIO_REGS(n, mr, mb, pr, pb) \ ++ n = { MUX_BIT(mr, mb), ((pr)*4)*8 + (pb)*2 } ++ ++#define SGPIO_REGS(n, mr, mb) \ ++ n+32 = { MUX_BIT(mr, mb), REG_BIT_INVALID } ++ ++#define GPIO_PIN(a) PINCTRL_PIN(a, "gpio" #a) ++#define AGPIO_PIN(a) PINCTRL_PIN(a, "aon_gpio" #a) ++#define SGPIO_PIN(a) PINCTRL_PIN(a+32, "aon_sgpio" #a) ++ ++struct pin_regs { ++ u16 mux_bit; ++ u16 pad_bit; ++}; ++ ++struct bcm2712_pinctrl { ++ struct device *dev; ++ void __iomem *base; ++ struct pinctrl_dev *pctl_dev; ++ struct pinctrl_desc pctl_desc; ++ const struct pin_regs *pin_regs; ++ const struct bcm2712_pin_funcs *pin_funcs; ++ const char *const *gpio_groups; ++ struct pinctrl_gpio_range gpio_range; ++ spinlock_t lock; ++}; ++ ++struct bcm_plat_data { ++ const struct pinctrl_desc *pctl_desc; ++ const struct pinctrl_gpio_range *gpio_range; ++ const struct pin_regs *pin_regs; ++ const struct bcm2712_pin_funcs *pin_funcs; ++}; ++ ++struct bcm2712_pin_funcs { ++ u8 funcsBCM2712_FSEL_COUNT - 1; ++}; ++ ++enum bcm2712_funcs { ++ func_gpio, ++ func_alt1, ++ func_alt2, ++ func_alt3, ++ func_alt4, ++ func_alt5, ++ func_alt6, ++ func_alt7, ++ func_alt8, ++ func_aon_cpu_standbyb, ++ func_aon_fp_4sec_resetb, ++ func_aon_gpclk, ++ func_aon_pwm, ++ func_arm_jtag, ++ func_aud_fs_clk0, ++ func_avs_pmu_bsc, ++ func_bsc_m0, ++ func_bsc_m1, ++ func_bsc_m2, ++ func_bsc_m3, ++ func_clk_observe, ++ func_ctl_hdmi_5v, ++ func_enet0, ++ func_enet0_mii, ++ func_enet0_rgmii, ++ func_ext_sc_clk, ++ func_fl0, ++ func_fl1, ++ func_gpclk0, ++ func_gpclk1, ++ func_gpclk2, ++ func_hdmi_tx0_auto_i2c, ++ func_hdmi_tx0_bsc, ++ func_hdmi_tx1_auto_i2c, ++ func_hdmi_tx1_bsc, ++ func_i2s_in, ++ func_i2s_out, ++ func_ir_in, ++ func_mtsif, ++ func_mtsif_alt, ++ func_mtsif_alt1, ++ func_pdm, ++ func_pkt, ++ func_pm_led_out, ++ func_sc0, ++ func_sd0, ++ func_sd2, ++ func_sd_card_a, ++ func_sd_card_b, ++ func_sd_card_c, ++ func_sd_card_d, ++ func_sd_card_e, ++ func_sd_card_f, ++ func_sd_card_g, ++ func_spdif_out, ++ func_spi_m, ++ func_spi_s, ++ func_sr_edm_sense, ++ func_te0, ++ func_te1, ++ func_tsio, ++ func_uart0, ++ func_uart1, ++ func_uart2, ++ func_usb_pwr, ++ func_usb_vbus, ++ func_uui, ++ func_vc_i2c0, ++ func_vc_i2c3, ++ func_vc_i2c4, ++ func_vc_i2c5, ++ func_vc_i2csl, ++ func_vc_pcm, ++ func_vc_pwm0, ++ func_vc_pwm1, ++ func_vc_spi0, ++ func_vc_spi3, ++ func_vc_spi4, ++ func_vc_spi5, ++ func_vc_uart0, ++ func_vc_uart2, ++ func_vc_uart3, ++ func_vc_uart4, ++ func__, ++ func_count = func__ ++}; ++ ++static const struct pin_regs bcm2712_c0_gpio_pin_regs = { ++ GPIO_REGS(0, 0, 0, 7, 7), ++ GPIO_REGS(1, 0, 1, 7, 8), ++ GPIO_REGS(2, 0, 2, 7, 9), ++ GPIO_REGS(3, 0, 3, 7, 10), ++ GPIO_REGS(4, 0, 4, 7, 11), ++ GPIO_REGS(5, 0, 5, 7, 12), ++ GPIO_REGS(6, 0, 6, 7, 13), ++ GPIO_REGS(7, 0, 7, 7, 14), ++ GPIO_REGS(8, 1, 0, 8, 0), ++ GPIO_REGS(9, 1, 1, 8, 1), ++ GPIO_REGS(10, 1, 2, 8, 2), ++ GPIO_REGS(11, 1, 3, 8, 3), ++ GPIO_REGS(12, 1, 4, 8, 4), ++ GPIO_REGS(13, 1, 5, 8, 5), ++ GPIO_REGS(14, 1, 6, 8, 6), ++ GPIO_REGS(15, 1, 7, 8, 7), ++ GPIO_REGS(16, 2, 0, 8, 8), ++ GPIO_REGS(17, 2, 1, 8, 9), ++ GPIO_REGS(18, 2, 2, 8, 10), ++ GPIO_REGS(19, 2, 3, 8, 11), ++ GPIO_REGS(20, 2, 4, 8, 12), ++ GPIO_REGS(21, 2, 5, 8, 13), ++ GPIO_REGS(22, 2, 6, 8, 14), ++ GPIO_REGS(23, 2, 7, 9, 0), ++ GPIO_REGS(24, 3, 0, 9, 1), ++ GPIO_REGS(25, 3, 1, 9, 2), ++ GPIO_REGS(26, 3, 2, 9, 3), ++ GPIO_REGS(27, 3, 3, 9, 4), ++ GPIO_REGS(28, 3, 4, 9, 5), ++ GPIO_REGS(29, 3, 5, 9, 6), ++ GPIO_REGS(30, 3, 6, 9, 7), ++ GPIO_REGS(31, 3, 7, 9, 8), ++ GPIO_REGS(32, 4, 0, 9, 9), ++ GPIO_REGS(33, 4, 1, 9, 10), ++ GPIO_REGS(34, 4, 2, 9, 11), ++ GPIO_REGS(35, 4, 3, 9, 12), ++ GPIO_REGS(36, 4, 4, 9, 13), ++ GPIO_REGS(37, 4, 5, 9, 14), ++ GPIO_REGS(38, 4, 6, 10, 0), ++ GPIO_REGS(39, 4, 7, 10, 1), ++ GPIO_REGS(40, 5, 0, 10, 2), ++ GPIO_REGS(41, 5, 1, 10, 3), ++ GPIO_REGS(42, 5, 2, 10, 4), ++ GPIO_REGS(43, 5, 3, 10, 5), ++ GPIO_REGS(44, 5, 4, 10, 6), ++ GPIO_REGS(45, 5, 5, 10, 7), ++ GPIO_REGS(46, 5, 6, 10, 8), ++ GPIO_REGS(47, 5, 7, 10, 9), ++ GPIO_REGS(48, 6, 0, 10, 10), ++ GPIO_REGS(49, 6, 1, 10, 11), ++ GPIO_REGS(50, 6, 2, 10, 12), ++ GPIO_REGS(51, 6, 3, 10, 13), ++ GPIO_REGS(52, 6, 4, 10, 14), ++ GPIO_REGS(53, 6, 5, 11, 0), ++ EMMC_REGS(54, 11, 1), /* EMMC_CMD */ ++ EMMC_REGS(55, 11, 2), /* EMMC_DS */ ++ EMMC_REGS(56, 11, 3), /* EMMC_CLK */ ++ EMMC_REGS(57, 11, 4), /* EMMC_DAT0 */ ++ EMMC_REGS(58, 11, 5), /* EMMC_DAT1 */ ++ EMMC_REGS(59, 11, 6), /* EMMC_DAT2 */ ++ EMMC_REGS(60, 11, 7), /* EMMC_DAT3 */ ++ EMMC_REGS(61, 11, 8), /* EMMC_DAT4 */ ++ EMMC_REGS(62, 11, 9), /* EMMC_DAT5 */ ++ EMMC_REGS(63, 11, 10), /* EMMC_DAT6 */ ++ EMMC_REGS(64, 11, 11), /* EMMC_DAT7 */ ++}; ++ ++static struct pin_regs bcm2712_c0_aon_gpio_pin_regs = { ++ AGPIO_REGS(0, 3, 0, 6, 10), ++ AGPIO_REGS(1, 3, 1, 6, 11), ++ AGPIO_REGS(2, 3, 2, 6, 12), ++ AGPIO_REGS(3, 3, 3, 6, 13), ++ AGPIO_REGS(4, 3, 4, 6, 14), ++ AGPIO_REGS(5, 3, 5, 7, 0), ++ AGPIO_REGS(6, 3, 6, 7, 1), ++ AGPIO_REGS(7, 3, 7, 7, 2), ++ AGPIO_REGS(8, 4, 0, 7, 3), ++ AGPIO_REGS(9, 4, 1, 7, 4), ++ AGPIO_REGS(10, 4, 2, 7, 5), ++ AGPIO_REGS(11, 4, 3, 7, 6), ++ AGPIO_REGS(12, 4, 4, 7, 7), ++ AGPIO_REGS(13, 4, 5, 7, 8), ++ AGPIO_REGS(14, 4, 6, 7, 9), ++ AGPIO_REGS(15, 4, 7, 7, 10), ++ AGPIO_REGS(16, 5, 0, 7, 11), ++ SGPIO_REGS(0, 0, 0), ++ SGPIO_REGS(1, 0, 1), ++ SGPIO_REGS(2, 0, 2), ++ SGPIO_REGS(3, 0, 3), ++ SGPIO_REGS(4, 1, 0), ++ SGPIO_REGS(5, 2, 0), ++}; ++ ++static const struct pinctrl_pin_desc bcm2712_c0_gpio_pins = { ++ GPIO_PIN(0), ++ GPIO_PIN(1), ++ GPIO_PIN(2), ++ GPIO_PIN(3), ++ GPIO_PIN(4), ++ GPIO_PIN(5), ++ GPIO_PIN(6), ++ GPIO_PIN(7), ++ GPIO_PIN(8), ++ GPIO_PIN(9), ++ GPIO_PIN(10), ++ GPIO_PIN(11), ++ GPIO_PIN(12), ++ GPIO_PIN(13), ++ GPIO_PIN(14), ++ GPIO_PIN(15), ++ GPIO_PIN(16), ++ GPIO_PIN(17), ++ GPIO_PIN(18), ++ GPIO_PIN(19), ++ GPIO_PIN(20), ++ GPIO_PIN(21), ++ GPIO_PIN(22), ++ GPIO_PIN(23), ++ GPIO_PIN(24), ++ GPIO_PIN(25), ++ GPIO_PIN(26), ++ GPIO_PIN(27), ++ GPIO_PIN(28), ++ GPIO_PIN(29), ++ GPIO_PIN(30), ++ GPIO_PIN(31), ++ GPIO_PIN(32), ++ GPIO_PIN(33), ++ GPIO_PIN(34), ++ GPIO_PIN(35), ++ GPIO_PIN(36), ++ GPIO_PIN(37), ++ GPIO_PIN(38), ++ GPIO_PIN(39), ++ GPIO_PIN(40), ++ GPIO_PIN(41), ++ GPIO_PIN(42), ++ GPIO_PIN(43), ++ GPIO_PIN(44), ++ GPIO_PIN(45), ++ GPIO_PIN(46), ++ GPIO_PIN(47), ++ GPIO_PIN(48), ++ GPIO_PIN(49), ++ GPIO_PIN(50), ++ GPIO_PIN(51), ++ GPIO_PIN(52), ++ GPIO_PIN(53), ++ PINCTRL_PIN(54, "emmc_cmd"), ++ PINCTRL_PIN(55, "emmc_ds"), ++ PINCTRL_PIN(56, "emmc_clk"), ++ PINCTRL_PIN(57, "emmc_dat0"), ++ PINCTRL_PIN(58, "emmc_dat1"), ++ PINCTRL_PIN(59, "emmc_dat2"), ++ PINCTRL_PIN(60, "emmc_dat3"), ++ PINCTRL_PIN(61, "emmc_dat4"), ++ PINCTRL_PIN(62, "emmc_dat5"), ++ PINCTRL_PIN(63, "emmc_dat6"), ++ PINCTRL_PIN(64, "emmc_dat7"), ++}; ++ ++static struct pinctrl_pin_desc bcm2712_c0_aon_gpio_pins = { ++ AGPIO_PIN(0), ++ AGPIO_PIN(1), ++ AGPIO_PIN(2), ++ AGPIO_PIN(3), ++ AGPIO_PIN(4), ++ AGPIO_PIN(5), ++ AGPIO_PIN(6), ++ AGPIO_PIN(7), ++ AGPIO_PIN(8), ++ AGPIO_PIN(9), ++ AGPIO_PIN(10), ++ AGPIO_PIN(11), ++ AGPIO_PIN(12), ++ AGPIO_PIN(13), ++ AGPIO_PIN(14), ++ AGPIO_PIN(15), ++ AGPIO_PIN(16), ++ SGPIO_PIN(0), ++ SGPIO_PIN(1), ++ SGPIO_PIN(2), ++ SGPIO_PIN(3), ++ SGPIO_PIN(4), ++ SGPIO_PIN(5), ++}; ++ ++static const struct pin_regs bcm2712_d0_gpio_pin_regs = { ++ GPIO_REGS(1, 0, 0, 4, 5), ++ GPIO_REGS(2, 0, 1, 4, 6), ++ GPIO_REGS(3, 0, 2, 4, 7), ++ GPIO_REGS(4, 0, 3, 4, 8), ++ GPIO_REGS(10, 0, 4, 4, 9), ++ GPIO_REGS(11, 0, 5, 4, 10), ++ GPIO_REGS(12, 0, 6, 4, 11), ++ GPIO_REGS(13, 0, 7, 4, 12), ++ GPIO_REGS(14, 1, 0, 4, 13), ++ GPIO_REGS(15, 1, 1, 4, 14), ++ GPIO_REGS(18, 1, 2, 5, 0), ++ GPIO_REGS(19, 1, 3, 5, 1), ++ GPIO_REGS(20, 1, 4, 5, 2), ++ GPIO_REGS(21, 1, 5, 5, 3), ++ GPIO_REGS(22, 1, 6, 5, 4), ++ GPIO_REGS(23, 1, 7, 5, 5), ++ GPIO_REGS(24, 2, 0, 5, 6), ++ GPIO_REGS(25, 2, 1, 5, 7), ++ GPIO_REGS(26, 2, 2, 5, 8), ++ GPIO_REGS(27, 2, 3, 5, 9), ++ GPIO_REGS(28, 2, 4, 5, 10), ++ GPIO_REGS(29, 2, 5, 5, 11), ++ GPIO_REGS(30, 2, 6, 5, 12), ++ GPIO_REGS(31, 2, 7, 5, 13), ++ GPIO_REGS(32, 3, 0, 5, 14), ++ GPIO_REGS(33, 3, 1, 6, 0), ++ GPIO_REGS(34, 3, 2, 6, 1), ++ GPIO_REGS(35, 3, 3, 6, 2), ++ EMMC_REGS(36, 6, 3), /* EMMC_CMD */ ++ EMMC_REGS(37, 6, 4), /* EMMC_DS */ ++ EMMC_REGS(38, 6, 5), /* EMMC_CLK */ ++ EMMC_REGS(39, 6, 6), /* EMMC_DAT0 */ ++ EMMC_REGS(40, 6, 7), /* EMMC_DAT1 */ ++ EMMC_REGS(41, 6, 8), /* EMMC_DAT2 */ ++ EMMC_REGS(42, 6, 9), /* EMMC_DAT3 */ ++ EMMC_REGS(43, 6, 10), /* EMMC_DAT4 */ ++ EMMC_REGS(44, 6, 11), /* EMMC_DAT5 */ ++ EMMC_REGS(45, 6, 12), /* EMMC_DAT6 */ ++ EMMC_REGS(46, 6, 13), /* EMMC_DAT7 */ ++}; ++ ++static struct pin_regs bcm2712_d0_aon_gpio_pin_regs = { ++ AGPIO_REGS(0, 3, 0, 5, 9), ++ AGPIO_REGS(1, 3, 1, 5, 10), ++ AGPIO_REGS(2, 3, 2, 5, 11), ++ AGPIO_REGS(3, 3, 3, 5, 12), ++ AGPIO_REGS(4, 3, 4, 5, 13), ++ AGPIO_REGS(5, 3, 5, 5, 14), ++ AGPIO_REGS(6, 3, 6, 6, 0), ++ AGPIO_REGS(8, 3, 7, 6, 1), ++ AGPIO_REGS(9, 4, 0, 6, 2), ++ AGPIO_REGS(12, 4, 1, 6, 3), ++ AGPIO_REGS(13, 4, 2, 6, 4), ++ AGPIO_REGS(14, 4, 3, 6, 5), ++ SGPIO_REGS(0, 0, 0), ++ SGPIO_REGS(1, 0, 1), ++ SGPIO_REGS(2, 0, 2), ++ SGPIO_REGS(3, 0, 3), ++ SGPIO_REGS(4, 1, 0), ++ SGPIO_REGS(5, 2, 0), ++}; ++ ++static const struct pinctrl_pin_desc bcm2712_d0_gpio_pins = { ++ GPIO_PIN(1), ++ GPIO_PIN(2), ++ GPIO_PIN(3), ++ GPIO_PIN(4), ++ GPIO_PIN(10), ++ GPIO_PIN(11), ++ GPIO_PIN(12), ++ GPIO_PIN(13), ++ GPIO_PIN(14), ++ GPIO_PIN(15), ++ GPIO_PIN(18), ++ GPIO_PIN(19), ++ GPIO_PIN(20), ++ GPIO_PIN(21), ++ GPIO_PIN(22), ++ GPIO_PIN(23), ++ GPIO_PIN(24), ++ GPIO_PIN(25), ++ GPIO_PIN(26), ++ GPIO_PIN(27), ++ GPIO_PIN(28), ++ GPIO_PIN(29), ++ GPIO_PIN(30), ++ GPIO_PIN(31), ++ GPIO_PIN(32), ++ GPIO_PIN(33), ++ GPIO_PIN(34), ++ GPIO_PIN(35), ++ PINCTRL_PIN(36, "emmc_cmd"), ++ PINCTRL_PIN(37, "emmc_ds"), ++ PINCTRL_PIN(38, "emmc_clk"), ++ PINCTRL_PIN(39, "emmc_dat0"), ++ PINCTRL_PIN(40, "emmc_dat1"), ++ PINCTRL_PIN(41, "emmc_dat2"), ++ PINCTRL_PIN(42, "emmc_dat3"), ++ PINCTRL_PIN(43, "emmc_dat4"), ++ PINCTRL_PIN(44, "emmc_dat5"), ++ PINCTRL_PIN(45, "emmc_dat6"), ++ PINCTRL_PIN(46, "emmc_dat7"), ++}; ++ ++static struct pinctrl_pin_desc bcm2712_d0_aon_gpio_pins = { ++ AGPIO_PIN(0), ++ AGPIO_PIN(1), ++ AGPIO_PIN(2), ++ AGPIO_PIN(3), ++ AGPIO_PIN(4), ++ AGPIO_PIN(5), ++ AGPIO_PIN(6), ++ AGPIO_PIN(8), ++ AGPIO_PIN(9), ++ AGPIO_PIN(12), ++ AGPIO_PIN(13), ++ AGPIO_PIN(14), ++ SGPIO_PIN(0), ++ SGPIO_PIN(1), ++ SGPIO_PIN(2), ++ SGPIO_PIN(3), ++ SGPIO_PIN(4), ++ SGPIO_PIN(5), ++}; ++ ++static const char * const bcm2712_func_names = { ++ FUNC(gpio), ++ FUNC(alt1), ++ FUNC(alt2), ++ FUNC(alt3), ++ FUNC(alt4), ++ FUNC(alt5), ++ FUNC(alt6), ++ FUNC(alt7), ++ FUNC(alt8), ++ FUNC(aon_cpu_standbyb), ++ FUNC(aon_fp_4sec_resetb), ++ FUNC(aon_gpclk), ++ FUNC(aon_pwm), ++ FUNC(arm_jtag), ++ FUNC(aud_fs_clk0), ++ FUNC(avs_pmu_bsc), ++ FUNC(bsc_m0), ++ FUNC(bsc_m1), ++ FUNC(bsc_m2), ++ FUNC(bsc_m3), ++ FUNC(clk_observe), ++ FUNC(ctl_hdmi_5v), ++ FUNC(enet0), ++ FUNC(enet0_mii), ++ FUNC(enet0_rgmii), ++ FUNC(ext_sc_clk), ++ FUNC(fl0), ++ FUNC(fl1), ++ FUNC(gpclk0), ++ FUNC(gpclk1), ++ FUNC(gpclk2), ++ FUNC(hdmi_tx0_auto_i2c), ++ FUNC(hdmi_tx0_bsc), ++ FUNC(hdmi_tx1_auto_i2c), ++ FUNC(hdmi_tx1_bsc), ++ FUNC(i2s_in), ++ FUNC(i2s_out), ++ FUNC(ir_in), ++ FUNC(mtsif), ++ FUNC(mtsif_alt), ++ FUNC(mtsif_alt1), ++ FUNC(pdm), ++ FUNC(pkt), ++ FUNC(pm_led_out), ++ FUNC(sc0), ++ FUNC(sd0), ++ FUNC(sd2), ++ FUNC(sd_card_a), ++ FUNC(sd_card_b), ++ FUNC(sd_card_c), ++ FUNC(sd_card_d), ++ FUNC(sd_card_e), ++ FUNC(sd_card_f), ++ FUNC(sd_card_g), ++ FUNC(spdif_out), ++ FUNC(spi_m), ++ FUNC(spi_s), ++ FUNC(sr_edm_sense), ++ FUNC(te0), ++ FUNC(te1), ++ FUNC(tsio), ++ FUNC(uart0), ++ FUNC(uart1), ++ FUNC(uart2), ++ FUNC(usb_pwr), ++ FUNC(usb_vbus), ++ FUNC(uui), ++ FUNC(vc_i2c0), ++ FUNC(vc_i2c3), ++ FUNC(vc_i2c4), ++ FUNC(vc_i2c5), ++ FUNC(vc_i2csl), ++ FUNC(vc_pcm), ++ FUNC(vc_pwm0), ++ FUNC(vc_pwm1), ++ FUNC(vc_spi0), ++ FUNC(vc_spi3), ++ FUNC(vc_spi4), ++ FUNC(vc_spi5), ++ FUNC(vc_uart0), ++ FUNC(vc_uart2), ++ FUNC(vc_uart3), ++ FUNC(vc_uart4), ++}; ++ ++static const struct bcm2712_pin_funcs bcm2712_c0_aon_gpio_pin_funcs = { ++ PIN(0, ir_in, vc_spi0, vc_uart3, vc_i2c3, te0, vc_i2c0, _, _), ++ PIN(1, vc_pwm0, vc_spi0, vc_uart3, vc_i2c3, te1, aon_pwm, vc_i2c0, vc_pwm1), ++ PIN(2, vc_pwm0, vc_spi0, vc_uart3, ctl_hdmi_5v, fl0, aon_pwm, ir_in, vc_pwm1), ++ PIN(3, ir_in, vc_spi0, vc_uart3, aon_fp_4sec_resetb, fl1, sd_card_g, aon_gpclk, _), ++ PIN(4, gpclk0, vc_spi0, vc_i2csl, aon_gpclk, pm_led_out, aon_pwm, sd_card_g, vc_pwm0), ++ PIN(5, gpclk1, ir_in, vc_i2csl, clk_observe, aon_pwm, sd_card_g, vc_pwm0, _), ++ PIN(6, uart1, vc_uart4, gpclk2, ctl_hdmi_5v, vc_uart0, vc_spi3, _, _), ++ PIN(7, uart1, vc_uart4, gpclk0, aon_pwm, vc_uart0, vc_spi3, _, _), ++ PIN(8, uart1, vc_uart4, vc_i2csl, ctl_hdmi_5v, vc_uart0, vc_spi3, _, _), ++ PIN(9, uart1, vc_uart4, vc_i2csl, aon_pwm, vc_uart0, vc_spi3, _, _), ++ PIN(10, tsio, ctl_hdmi_5v, sc0, spdif_out, vc_spi5, usb_pwr, aon_gpclk, sd_card_f), ++ PIN(11, tsio, uart0, sc0, aud_fs_clk0, vc_spi5, usb_vbus, vc_uart2, sd_card_f), ++ PIN(12, tsio, uart0, vc_uart0, tsio, vc_spi5, usb_pwr, vc_uart2, sd_card_f), ++ PIN(13, bsc_m1, uart0, vc_uart0, uui, vc_spi5, arm_jtag, vc_uart2, vc_i2c3), ++ PIN(14, bsc_m1, uart0, vc_uart0, uui, vc_spi5, arm_jtag, vc_uart2, vc_i2c3), ++ PIN(15, ir_in, aon_fp_4sec_resetb, vc_uart0, pm_led_out, ctl_hdmi_5v, aon_pwm, aon_gpclk, _), ++ PIN(16, aon_cpu_standbyb, gpclk0, pm_led_out, ctl_hdmi_5v, vc_pwm0, usb_pwr, aud_fs_clk0, _), ++}; ++ ++static const struct bcm2712_pin_funcs bcm2712_c0_aon_sgpio_pin_funcs = { ++ PIN(0, hdmi_tx0_bsc, hdmi_tx0_auto_i2c, bsc_m0, vc_i2c0, _, _, _, _), ++ PIN(1, hdmi_tx0_bsc, hdmi_tx0_auto_i2c, bsc_m0, vc_i2c0, _, _, _, _), ++ PIN(2, hdmi_tx1_bsc, hdmi_tx1_auto_i2c, bsc_m1, vc_i2c4, ctl_hdmi_5v, _, _, _), ++ PIN(3, hdmi_tx1_bsc, hdmi_tx1_auto_i2c, bsc_m1, vc_i2c4, _, _, _, _), ++ PIN(4, avs_pmu_bsc, bsc_m2, vc_i2c5, ctl_hdmi_5v, _, _, _, _), ++ PIN(5, avs_pmu_bsc, bsc_m2, vc_i2c5, _, _, _, _, _), ++}; ++ ++static const struct bcm2712_pin_funcs bcm2712_c0_gpio_pin_funcs = { ++ PIN(0, bsc_m3, vc_i2c0, gpclk0, enet0, vc_pwm1, vc_spi0, ir_in, _), ++ PIN(1, bsc_m3, vc_i2c0, gpclk1, enet0, vc_pwm1, sr_edm_sense, vc_spi0, vc_uart3), ++ PIN(2, pdm, i2s_in, gpclk2, vc_spi4, pkt, vc_spi0, vc_uart3, _), ++ PIN(3, pdm, i2s_in, vc_spi4, pkt, vc_spi0, vc_uart3, _, _), ++ PIN(4, pdm, i2s_in, arm_jtag, vc_spi4, pkt, vc_spi0, vc_uart3, _), ++ PIN(5, pdm, vc_i2c3, arm_jtag, sd_card_e, vc_spi4, pkt, vc_pcm, vc_i2c5), ++ PIN(6, pdm, vc_i2c3, arm_jtag, sd_card_e, vc_spi4, pkt, vc_pcm, vc_i2c5), ++ PIN(7, i2s_out, spdif_out, arm_jtag, sd_card_e, vc_i2c3, enet0_rgmii, vc_pcm, vc_spi4), ++ PIN(8, i2s_out, aud_fs_clk0, arm_jtag, sd_card_e, vc_i2c3, enet0_mii, vc_pcm, vc_spi4), ++ PIN(9, i2s_out, aud_fs_clk0, arm_jtag, sd_card_e, enet0_mii, sd_card_c, vc_spi4, _), ++ PIN(10, bsc_m3, mtsif_alt1, i2s_in, i2s_out, vc_spi5, enet0_mii, sd_card_c, vc_spi4), ++ PIN(11, bsc_m3, mtsif_alt1, i2s_in, i2s_out, vc_spi5, enet0_mii, sd_card_c, vc_spi4), ++ PIN(12, spi_s, mtsif_alt1, i2s_in, i2s_out, vc_spi5, vc_i2csl, sd0, sd_card_d), ++ PIN(13, spi_s, mtsif_alt1, i2s_out, usb_vbus, vc_spi5, vc_i2csl, sd0, sd_card_d), ++ PIN(14, spi_s, vc_i2csl, enet0_rgmii, arm_jtag, vc_spi5, vc_pwm0, vc_i2c4, sd_card_d), ++ PIN(15, spi_s, vc_i2csl, vc_spi3, arm_jtag, vc_pwm0, vc_i2c4, gpclk0, _), ++ PIN(16, sd_card_b, i2s_out, vc_spi3, i2s_in, sd0, enet0_rgmii, gpclk1, _), ++ PIN(17, sd_card_b, i2s_out, vc_spi3, i2s_in, ext_sc_clk, sd0, enet0_rgmii, gpclk2), ++ PIN(18, sd_card_b, i2s_out, vc_spi3, i2s_in, sd0, enet0_rgmii, vc_pwm1, _), ++ PIN(19, sd_card_b, usb_pwr, vc_spi3, pkt, spdif_out, sd0, ir_in, vc_pwm1), ++ PIN(20, sd_card_b, uui, vc_uart0, arm_jtag, uart2, usb_pwr, vc_pcm, vc_uart4), ++ PIN(21, usb_pwr, uui, vc_uart0, arm_jtag, uart2, sd_card_b, vc_pcm, vc_uart4), ++ PIN(22, usb_pwr, enet0, vc_uart0, mtsif, uart2, usb_vbus, vc_pcm, vc_i2c5), ++ PIN(23, usb_vbus, enet0, vc_uart0, mtsif, uart2, i2s_out, vc_pcm, vc_i2c5), ++ PIN(24, mtsif, pkt, uart0, enet0_rgmii, enet0_rgmii, vc_i2c4, vc_uart3, _), ++ PIN(25, mtsif, pkt, sc0, uart0, enet0_rgmii, enet0_rgmii, vc_i2c4, vc_uart3), ++ PIN(26, mtsif, pkt, sc0, uart0, enet0_rgmii, vc_uart4, vc_spi5, _), ++ PIN(27, mtsif, pkt, sc0, uart0, enet0_rgmii, vc_uart4, vc_spi5, _), ++ PIN(28, mtsif, pkt, sc0, enet0_rgmii, vc_uart4, vc_spi5, _, _), ++ PIN(29, mtsif, pkt, sc0, enet0_rgmii, vc_uart4, vc_spi5, _, _), ++ PIN(30, mtsif, pkt, sc0, sd2, enet0_rgmii, gpclk0, vc_pwm0, _), ++ PIN(31, mtsif, pkt, sc0, sd2, enet0_rgmii, vc_spi3, vc_pwm0, _), ++ PIN(32, mtsif, pkt, sc0, sd2, enet0_rgmii, vc_spi3, vc_uart3, _), ++ PIN(33, mtsif, pkt, sd2, enet0_rgmii, vc_spi3, vc_uart3, _, _), ++ PIN(34, mtsif, pkt, ext_sc_clk, sd2, enet0_rgmii, vc_spi3, vc_i2c5, _), ++ PIN(35, mtsif, pkt, sd2, enet0_rgmii, vc_spi3, vc_i2c5, _, _), ++ PIN(36, sd0, mtsif, sc0, i2s_in, vc_uart3, vc_uart2, _, _), ++ PIN(37, sd0, mtsif, sc0, vc_spi0, i2s_in, vc_uart3, vc_uart2, _), ++ PIN(38, sd0, mtsif_alt, sc0, vc_spi0, i2s_in, vc_uart3, vc_uart2, _), ++ PIN(39, sd0, mtsif_alt, sc0, vc_spi0, vc_uart3, vc_uart2, _, _), ++ PIN(40, sd0, mtsif_alt, sc0, vc_spi0, bsc_m3, _, _, _), ++ PIN(41, sd0, mtsif_alt, sc0, vc_spi0, bsc_m3, _, _, _), ++ PIN(42, vc_spi0, mtsif_alt, vc_i2c0, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m), ++ PIN(43, vc_spi0, mtsif_alt, vc_i2c0, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m), ++ PIN(44, vc_spi0, mtsif_alt, enet0, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m), ++ PIN(45, vc_spi0, mtsif_alt, enet0, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m), ++ PIN(46, vc_spi0, mtsif_alt, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m, _), ++ PIN(47, enet0, mtsif_alt, i2s_out, mtsif_alt1, arm_jtag, _, _, _), ++ PIN(48, sc0, usb_pwr, spdif_out, mtsif, _, _, _, _), ++ PIN(49, sc0, usb_pwr, aud_fs_clk0, mtsif, _, _, _, _), ++ PIN(50, sc0, usb_vbus, sc0, _, _, _, _, _), ++ PIN(51, sc0, enet0, sc0, sr_edm_sense, _, _, _, _), ++ PIN(52, sc0, enet0, vc_pwm1, _, _, _, _, _), ++ PIN(53, sc0, enet0_rgmii, ext_sc_clk, _, _, _, _, _), ++}; ++ ++static const struct bcm2712_pin_funcs bcm2712_d0_aon_gpio_pin_funcs = { ++ PIN(0, ir_in, vc_spi0, vc_uart0, vc_i2c3, uart0, vc_i2c0, _, _), ++ PIN(1, vc_pwm0, vc_spi0, vc_uart0, vc_i2c3, uart0, aon_pwm, vc_i2c0, vc_pwm1), ++ PIN(2, vc_pwm0, vc_spi0, vc_uart0, ctl_hdmi_5v, uart0, aon_pwm, ir_in, vc_pwm1), ++ PIN(3, ir_in, vc_spi0, vc_uart0, uart0, sd_card_g, aon_gpclk, _, _), ++ PIN(4, gpclk0, vc_spi0, pm_led_out, aon_pwm, sd_card_g, vc_pwm0, _, _), ++ PIN(5, gpclk1, ir_in, aon_pwm, sd_card_g, vc_pwm0, _, _, _), ++ PIN(6, uart1, vc_uart2, ctl_hdmi_5v, gpclk2, vc_spi3, _, _, _), ++ PIN(7, _, _, _, _, _, _, _, _), ++ PIN(8, uart1, vc_uart2, ctl_hdmi_5v, vc_spi0, vc_spi3, _, _, _), ++ PIN(9, uart1, vc_uart2, vc_uart0, aon_pwm, vc_spi0, vc_uart2, vc_spi3, _), ++ PIN(10, _, _, _, _, _, _, _, _), ++ PIN(11, _, _, _, _, _, _, _, _), ++ PIN(12, uart1, vc_uart2, vc_uart0, vc_spi0, usb_pwr, vc_uart2, vc_spi3, _), ++ PIN(13, bsc_m1, vc_uart0, uui, vc_spi0, arm_jtag, vc_uart2, vc_i2c3, _), ++ PIN(14, bsc_m1, aon_gpclk, vc_uart0, uui, vc_spi0, arm_jtag, vc_uart2, vc_i2c3), ++}; ++ ++static const struct bcm2712_pin_funcs bcm2712_d0_aon_sgpio_pin_funcs = { ++ PIN(0, hdmi_tx0_bsc, hdmi_tx0_auto_i2c, bsc_m0, vc_i2c0, _, _, _, _), ++ PIN(1, hdmi_tx0_bsc, hdmi_tx0_auto_i2c, bsc_m0, vc_i2c0, _, _, _, _), ++ PIN(2, hdmi_tx1_bsc, hdmi_tx1_auto_i2c, bsc_m1, vc_i2c0, ctl_hdmi_5v, _, _, _), ++ PIN(3, hdmi_tx1_bsc, hdmi_tx1_auto_i2c, bsc_m1, vc_i2c0, _, _, _, _), ++ PIN(4, avs_pmu_bsc, bsc_m2, vc_i2c3, ctl_hdmi_5v, _, _, _, _), ++ PIN(5, avs_pmu_bsc, bsc_m2, vc_i2c3, _, _, _, _, _), ++}; ++ ++static const struct bcm2712_pin_funcs bcm2712_d0_gpio_pin_funcs = { ++ PIN(1, vc_i2c0, usb_pwr, gpclk0, sd_card_e, vc_spi3, sr_edm_sense, vc_spi0, vc_uart0), ++ PIN(2, vc_i2c0, usb_pwr, gpclk1, sd_card_e, vc_spi3, clk_observe, vc_spi0, vc_uart0), ++ PIN(3, vc_i2c3, usb_vbus, gpclk2, sd_card_e, vc_spi3, vc_spi0, vc_uart0, _), ++ PIN(4, vc_i2c3, vc_pwm1, vc_spi3, sd_card_e, vc_spi3, vc_spi0, vc_uart0, _), ++ PIN(10, bsc_m3, vc_pwm1, vc_spi3, sd_card_e, vc_spi3, gpclk0, _, _), ++ PIN(11, bsc_m3, vc_spi3, clk_observe, sd_card_c, gpclk1, _, _, _), ++ PIN(12, spi_s, vc_spi3, sd_card_c, sd_card_d, _, _, _, _), ++ PIN(13, spi_s, vc_spi3, sd_card_c, sd_card_d, _, _, _, _), ++ PIN(14, spi_s, uui, arm_jtag, vc_pwm0, vc_i2c0, sd_card_d, _, _), ++ PIN(15, spi_s, uui, arm_jtag, vc_pwm0, vc_i2c0, gpclk0, _, _), ++ PIN(18, sd_card_f, vc_pwm1, _, _, _, _, _, _), ++ PIN(19, sd_card_f, usb_pwr, vc_pwm1, _, _, _, _, _), ++ PIN(20, vc_i2c3, uui, vc_uart0, arm_jtag, vc_uart2, _, _, _), ++ PIN(21, vc_i2c3, uui, vc_uart0, arm_jtag, vc_uart2, _, _, _), ++ PIN(22, sd_card_f, vc_uart0, vc_i2c3, _, _, _, _, _), ++ PIN(23, vc_uart0, vc_i2c3, _, _, _, _, _, _), ++ PIN(24, sd_card_b, vc_spi0, arm_jtag, uart0, usb_pwr, vc_uart2, vc_uart0, _), ++ PIN(25, sd_card_b, vc_spi0, arm_jtag, uart0, usb_pwr, vc_uart2, vc_uart0, _), ++ PIN(26, sd_card_b, vc_spi0, arm_jtag, uart0, usb_vbus, vc_uart2, vc_spi0, _), ++ PIN(27, sd_card_b, vc_spi0, arm_jtag, uart0, vc_uart2, vc_spi0, _, _), ++ PIN(28, sd_card_b, vc_spi0, arm_jtag, vc_i2c0, vc_spi0, _, _, _), ++ PIN(29, arm_jtag, vc_i2c0, vc_spi0, _, _, _, _, _), ++ PIN(30, sd2, gpclk0, vc_pwm0, _, _, _, _, _), ++ PIN(31, sd2, vc_spi3, vc_pwm0, _, _, _, _, _), ++ PIN(32, sd2, vc_spi3, vc_uart3, _, _, _, _, _), ++ PIN(33, sd2, vc_spi3, vc_uart3, _, _, _, _, _), ++ PIN(34, sd2, vc_spi3, vc_i2c5, _, _, _, _, _), ++ PIN(35, sd2, vc_spi3, vc_i2c5, _, _, _, _, _), ++}; ++ ++static inline u32 bcm2712_reg_rd(struct bcm2712_pinctrl *pc, unsigned reg) ++{ ++ return readl(pc->base + reg); ++} ++ ++static inline void bcm2712_reg_wr(struct bcm2712_pinctrl *pc, unsigned reg, ++ u32 val) ++{ ++ writel(val, pc->base + reg); ++} ++ ++static enum bcm2712_funcs bcm2712_pinctrl_fsel_get( ++ struct bcm2712_pinctrl *pc, unsigned pin) ++{ ++ u32 bit = pc->pin_regspin.mux_bit; ++ enum bcm2712_funcs func; ++ int fsel; ++ u32 val; ++ ++ if (!bit) ++ return func_gpio; ++ bit &= ~MUX_BIT_VALID; ++ ++ val = bcm2712_reg_rd(pc, BIT_TO_REG(bit)); ++ fsel = (val >> BIT_TO_SHIFT(bit)) & BCM2712_FSEL_MASK; ++ func = pc->pin_funcspin.funcsfsel; ++ if (func >= func_count) ++ func = (enum bcm2712_funcs)fsel; ++ ++ dev_dbg(pc->dev, "get %04x: %08x (%u => %s)\n", ++ BIT_TO_REG(bit), val, pin, ++ bcm2712_func_namesfunc); ++ ++ return func; ++} ++ ++static void bcm2712_pinctrl_fsel_set( ++ struct bcm2712_pinctrl *pc, unsigned pin, ++ enum bcm2712_funcs func) ++{ ++ u32 bit = pc->pin_regspin.mux_bit, val; ++ const u8 *pin_funcs; ++ unsigned long flags; ++ int fsel; ++ int cur; ++ int i; ++ ++ if (!bit || func >= func_count) ++ return; ++ bit &= ~MUX_BIT_VALID; ++ ++ fsel = BCM2712_FSEL_COUNT; ++ ++ if (func >= BCM2712_FSEL_COUNT) { ++ /* Convert to an fsel number */ ++ pin_funcs = pc->pin_funcspin.funcs; ++ for (i = 1; i < BCM2712_FSEL_COUNT; i++) { ++ if (pin_funcsi - 1 == func) { ++ fsel = i; ++ break; ++ } ++ } ++ } else { ++ fsel = (enum bcm2712_funcs)func; ++ } ++ if (fsel >= BCM2712_FSEL_COUNT) ++ return; ++ ++ spin_lock_irqsave(&pc->lock, flags); ++ ++ val = bcm2712_reg_rd(pc, BIT_TO_REG(bit)); ++ cur = (val >> BIT_TO_SHIFT(bit)) & BCM2712_FSEL_MASK; ++ ++ dev_dbg(pc->dev, "read %04x: %08x (%u => %s)\n", ++ BIT_TO_REG(bit), val, pin, ++ bcm2712_func_namescur); ++ ++ if (cur != fsel) { ++ val &= ~(BCM2712_FSEL_MASK << BIT_TO_SHIFT(bit)); ++ val |= fsel << BIT_TO_SHIFT(bit); ++ ++ dev_dbg(pc->dev, "write %04x: %08x (%u <= %s)\n", ++ BIT_TO_REG(bit), val, pin, ++ bcm2712_func_namesfsel); ++ bcm2712_reg_wr(pc, BIT_TO_REG(bit), val); ++ } ++ ++ spin_unlock_irqrestore(&pc->lock, flags); ++} ++ ++static int bcm2712_pctl_get_groups_count(struct pinctrl_dev *pctldev) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ ++ return pc->pctl_desc.npins; ++} ++ ++static const char *bcm2712_pctl_get_group_name(struct pinctrl_dev *pctldev, ++ unsigned selector) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ ++ return pc->gpio_groupsselector; ++} ++ ++static int bcm2712_pctl_get_group_pins(struct pinctrl_dev *pctldev, ++ unsigned selector, ++ const unsigned **pins, ++ unsigned *num_pins) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ ++ *pins = &pc->pctl_desc.pinsselector.number; ++ *num_pins = 1; ++ ++ return 0; ++} ++ ++static void bcm2712_pctl_pin_dbg_show(struct pinctrl_dev *pctldev, ++ struct seq_file *s, ++ unsigned offset) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ enum bcm2712_funcs fsel = bcm2712_pinctrl_fsel_get(pc, offset); ++ const char *fname = bcm2712_func_namesfsel; ++ ++ seq_printf(s, "function %s", fname); ++} ++ ++static void bcm2712_pctl_dt_free_map(struct pinctrl_dev *pctldev, ++ struct pinctrl_map *maps, unsigned num_maps) ++{ ++ int i; ++ ++ for (i = 0; i < num_maps; i++) ++ if (mapsi.type == PIN_MAP_TYPE_CONFIGS_PIN) ++ kfree(mapsi.data.configs.configs); ++ ++ kfree(maps); ++} ++ ++static const struct pinctrl_ops bcm2712_pctl_ops = { ++ .get_groups_count = bcm2712_pctl_get_groups_count, ++ .get_group_name = bcm2712_pctl_get_group_name, ++ .get_group_pins = bcm2712_pctl_get_group_pins, ++ .pin_dbg_show = bcm2712_pctl_pin_dbg_show, ++ .dt_node_to_map = pinconf_generic_dt_node_to_map_all, ++ .dt_free_map = bcm2712_pctl_dt_free_map, ++}; ++ ++static int bcm2712_pmx_free(struct pinctrl_dev *pctldev, ++ unsigned offset) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ ++ /* disable by setting to GPIO */ ++ bcm2712_pinctrl_fsel_set(pc, offset, func_gpio); ++ return 0; ++} ++ ++static int bcm2712_pmx_get_functions_count(struct pinctrl_dev *pctldev) ++{ ++ return func_count; ++} ++ ++static const char *bcm2712_pmx_get_function_name(struct pinctrl_dev *pctldev, ++ unsigned selector) ++{ ++ return (selector < func_count) ? bcm2712_func_namesselector : NULL; ++} ++ ++static int bcm2712_pmx_get_function_groups(struct pinctrl_dev *pctldev, ++ unsigned selector, ++ const char * const **groups, ++ unsigned * const num_groups) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ /* every pin can do every function */ ++ *groups = pc->gpio_groups; ++ *num_groups = pc->pctl_desc.npins; ++ ++ return 0; ++} ++ ++static int bcm2712_pmx_set(struct pinctrl_dev *pctldev, ++ unsigned func_selector, ++ unsigned group_selector) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ const struct pinctrl_desc *pctldesc = &pc->pctl_desc; ++ const struct pinctrl_pin_desc *pindesc; ++ ++ if (group_selector >= pctldesc->npins) ++ return -EINVAL; ++ pindesc = &pctldesc->pinsgroup_selector; ++ bcm2712_pinctrl_fsel_set(pc, pindesc->number, func_selector); ++ ++ return 0; ++} ++static int bcm2712_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned pin) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ ++ bcm2712_pinctrl_fsel_set(pc, pin, func_gpio); ++ ++ return 0; ++} ++ ++static void bcm2712_pmx_gpio_disable_free(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned offset) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ ++ /* disable by setting to GPIO */ ++ bcm2712_pinctrl_fsel_set(pc, offset, func_gpio); ++} ++ ++static const struct pinmux_ops bcm2712_pmx_ops = { ++ .free = bcm2712_pmx_free, ++ .get_functions_count = bcm2712_pmx_get_functions_count, ++ .get_function_name = bcm2712_pmx_get_function_name, ++ .get_function_groups = bcm2712_pmx_get_function_groups, ++ .set_mux = bcm2712_pmx_set, ++ .gpio_request_enable = bcm2712_pmx_gpio_request_enable, ++ .gpio_disable_free = bcm2712_pmx_gpio_disable_free, ++}; ++ ++static unsigned int bcm2712_pull_config_get(struct bcm2712_pinctrl *pc, ++ unsigned int pin) ++{ ++ u32 bit = pc->pin_regspin.pad_bit, val; ++ ++ if (unlikely(bit == REG_BIT_INVALID)) ++ return BCM2712_PULL_NONE; ++ ++ val = bcm2712_reg_rd(pc, BIT_TO_REG(bit)); ++ return (val >> BIT_TO_SHIFT(bit)) & BCM2712_PULL_MASK; ++} ++ ++static void bcm2712_pull_config_set(struct bcm2712_pinctrl *pc, ++ unsigned int pin, unsigned int arg) ++{ ++ u32 bit = pc->pin_regspin.pad_bit, val; ++ unsigned long flags; ++ ++ if (unlikely(bit == REG_BIT_INVALID)) { ++ dev_warn(pc->dev, "can't set pulls for %s\n", pc->gpio_groupspin); ++ return; ++ } ++ ++ spin_lock_irqsave(&pc->lock, flags); ++ ++ val = bcm2712_reg_rd(pc, BIT_TO_REG(bit)); ++ val &= ~(BCM2712_PULL_MASK << BIT_TO_SHIFT(bit)); ++ val |= (arg << BIT_TO_SHIFT(bit)); ++ bcm2712_reg_wr(pc, BIT_TO_REG(bit), val); ++ ++ spin_unlock_irqrestore(&pc->lock, flags); ++} ++ ++static int bcm2712_pinconf_get(struct pinctrl_dev *pctldev, ++ unsigned pin, unsigned long *config) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ enum pin_config_param param = pinconf_to_config_param(*config); ++ u32 arg; ++ ++ switch (param) { ++ case PIN_CONFIG_BIAS_DISABLE: ++ arg = (bcm2712_pull_config_get(pc, pin) == BCM2712_PULL_NONE); ++ break; ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ arg = (bcm2712_pull_config_get(pc, pin) == BCM2712_PULL_DOWN); ++ break; ++ case PIN_CONFIG_BIAS_PULL_UP: ++ arg = (bcm2712_pull_config_get(pc, pin) == BCM2712_PULL_UP); ++ break; ++ default: ++ return -ENOTSUPP; ++ } ++ ++ *config = pinconf_to_config_packed(param, arg); ++ ++ return -ENOTSUPP; ++} ++ ++static int bcm2712_pinconf_set(struct pinctrl_dev *pctldev, ++ unsigned int pin, unsigned long *configs, ++ unsigned int num_configs) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ u32 param, arg; ++ int i; ++ ++ for (i = 0; i < num_configs; i++) { ++ param = pinconf_to_config_param(configsi); ++ arg = pinconf_to_config_argument(configsi); ++ ++ switch (param) { ++ case PIN_CONFIG_BIAS_DISABLE: ++ bcm2712_pull_config_set(pc, pin, BCM2712_PULL_NONE); ++ break; ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ bcm2712_pull_config_set(pc, pin, BCM2712_PULL_DOWN); ++ break; ++ case PIN_CONFIG_BIAS_PULL_UP: ++ bcm2712_pull_config_set(pc, pin, BCM2712_PULL_UP); ++ break; ++ default: ++ return -ENOTSUPP; ++ } ++ } /* for each config */ ++ ++ return 0; ++} ++ ++static const struct pinconf_ops bcm2712_pinconf_ops = { ++ .is_generic = true, ++ .pin_config_get = bcm2712_pinconf_get, ++ .pin_config_set = bcm2712_pinconf_set, ++}; ++ ++static const struct pinctrl_desc bcm2712_c0_pinctrl_desc = { ++ .name = "pinctrl-bcm2712", ++ .pins = bcm2712_c0_gpio_pins, ++ .npins = ARRAY_SIZE(bcm2712_c0_gpio_pins), ++ .pctlops = &bcm2712_pctl_ops, ++ .pmxops = &bcm2712_pmx_ops, ++ .confops = &bcm2712_pinconf_ops, ++ .owner = THIS_MODULE, ++}; ++ ++static const struct pinctrl_desc bcm2712_c0_aon_pinctrl_desc = { ++ .name = "aon-pinctrl-bcm2712", ++ .pins = bcm2712_c0_aon_gpio_pins, ++ .npins = ARRAY_SIZE(bcm2712_c0_aon_gpio_pins), ++ .pctlops = &bcm2712_pctl_ops, ++ .pmxops = &bcm2712_pmx_ops, ++ .confops = &bcm2712_pinconf_ops, ++ .owner = THIS_MODULE, ++}; ++ ++static const struct pinctrl_desc bcm2712_d0_pinctrl_desc = { ++ .name = "pinctrl-bcm2712", ++ .pins = bcm2712_d0_gpio_pins, ++ .npins = ARRAY_SIZE(bcm2712_d0_gpio_pins), ++ .pctlops = &bcm2712_pctl_ops, ++ .pmxops = &bcm2712_pmx_ops, ++ .confops = &bcm2712_pinconf_ops, ++ .owner = THIS_MODULE, ++}; ++ ++static const struct pinctrl_desc bcm2712_d0_aon_pinctrl_desc = { ++ .name = "aon-pinctrl-bcm2712", ++ .pins = bcm2712_d0_aon_gpio_pins, ++ .npins = ARRAY_SIZE(bcm2712_d0_aon_gpio_pins), ++ .pctlops = &bcm2712_pctl_ops, ++ .pmxops = &bcm2712_pmx_ops, ++ .confops = &bcm2712_pinconf_ops, ++ .owner = THIS_MODULE, ++}; ++ ++static const struct pinctrl_gpio_range bcm2712_c0_pinctrl_gpio_range = { ++ .name = "pinctrl-bcm2712", ++ .npins = ARRAY_SIZE(bcm2712_c0_gpio_pins), ++}; ++ ++static const struct pinctrl_gpio_range bcm2712_c0_aon_pinctrl_gpio_range = { ++ .name = "aon-pinctrl-bcm2712", ++ .npins = ARRAY_SIZE(bcm2712_c0_aon_gpio_pins), ++}; ++ ++static const struct pinctrl_gpio_range bcm2712_d0_pinctrl_gpio_range = { ++ .name = "pinctrl-bcm2712", ++ .npins = ARRAY_SIZE(bcm2712_d0_gpio_pins), ++}; ++ ++static const struct pinctrl_gpio_range bcm2712_d0_aon_pinctrl_gpio_range = { ++ .name = "aon-pinctrl-bcm2712", ++ .npins = ARRAY_SIZE(bcm2712_d0_aon_gpio_pins), ++}; ++ ++static const struct bcm_plat_data bcm2712_c0_plat_data = { ++ .pctl_desc = &bcm2712_c0_pinctrl_desc, ++ .gpio_range = &bcm2712_c0_pinctrl_gpio_range, ++ .pin_regs = bcm2712_c0_gpio_pin_regs, ++ .pin_funcs = bcm2712_c0_gpio_pin_funcs, ++}; ++ ++static const struct bcm_plat_data bcm2712_c0_aon_plat_data = { ++ .pctl_desc = &bcm2712_c0_aon_pinctrl_desc, ++ .gpio_range = &bcm2712_c0_aon_pinctrl_gpio_range, ++ .pin_regs = bcm2712_c0_aon_gpio_pin_regs, ++ .pin_funcs = bcm2712_c0_aon_gpio_pin_funcs, ++}; ++ ++static const struct bcm_plat_data bcm2712_d0_plat_data = { ++ .pctl_desc = &bcm2712_d0_pinctrl_desc, ++ .gpio_range = &bcm2712_d0_pinctrl_gpio_range, ++ .pin_regs = bcm2712_d0_gpio_pin_regs, ++ .pin_funcs = bcm2712_d0_gpio_pin_funcs, ++}; ++ ++static const struct bcm_plat_data bcm2712_d0_aon_plat_data = { ++ .pctl_desc = &bcm2712_d0_aon_pinctrl_desc, ++ .gpio_range = &bcm2712_d0_aon_pinctrl_gpio_range, ++ .pin_regs = bcm2712_d0_aon_gpio_pin_regs, ++ .pin_funcs = bcm2712_d0_aon_gpio_pin_funcs, ++}; ++ ++static const struct of_device_id bcm2712_pinctrl_match = { ++ { ++ .compatible = "brcm,bcm2712-pinctrl", ++ .data = &bcm2712_c0_plat_data, ++ }, ++ { ++ .compatible = "brcm,bcm2712-aon-pinctrl", ++ .data = &bcm2712_c0_aon_plat_data, ++ }, ++ ++ { ++ .compatible = "brcm,bcm2712c0-pinctrl", ++ .data = &bcm2712_c0_plat_data, ++ }, ++ { ++ .compatible = "brcm,bcm2712c0-aon-pinctrl", ++ .data = &bcm2712_c0_aon_plat_data, ++ }, ++ ++ { ++ .compatible = "brcm,bcm2712d0-pinctrl", ++ .data = &bcm2712_d0_plat_data, ++ }, ++ { ++ .compatible = "brcm,bcm2712d0-aon-pinctrl", ++ .data = &bcm2712_d0_aon_plat_data, ++ }, ++ {} ++}; ++ ++static int bcm2712_pinctrl_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ const struct bcm_plat_data *pdata; ++ const struct of_device_id *match; ++ struct bcm2712_pinctrl *pc; ++ const char **names; ++ int num_pins, i; ++ ++ match = of_match_node(bcm2712_pinctrl_match, np); ++ if (!match) ++ return -EINVAL; ++ pdata = match->data; ++ ++ pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL); ++ if (!pc) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, pc); ++ pc->dev = dev; ++ spin_lock_init(&pc->lock); ++ ++ pc->base = devm_of_iomap(dev, np, 0, NULL); ++ if (IS_ERR(pc->base)) { ++ dev_err(dev, "could not get IO memory\n"); ++ return PTR_ERR(pc->base); ++ } ++ ++ pc->pctl_desc = *pdata->pctl_desc; ++ num_pins = pc->pctl_desc.npins; ++ names = devm_kmalloc_array(dev, num_pins, sizeof(const char *), ++ GFP_KERNEL); ++ if (!names) ++ return -ENOMEM; ++ for (i = 0; i < num_pins; i++) ++ namesi = pc->pctl_desc.pinsi.name; ++ pc->gpio_groups = names; ++ pc->pin_regs = pdata->pin_regs; ++ pc->pin_funcs = pdata->pin_funcs; ++ pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc); ++ if (IS_ERR(pc->pctl_dev)) ++ return PTR_ERR(pc->pctl_dev); ++ ++ pc->gpio_range = *pdata->gpio_range; ++ pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range); ++ ++ return 0; ++} ++ ++static struct platform_driver bcm2712_pinctrl_driver = { ++ .probe = bcm2712_pinctrl_probe, ++ .driver = { ++ .name = MODULE_NAME, ++ .of_match_table = bcm2712_pinctrl_match, ++ .suppress_bind_attrs = true, ++ }, ++}; ++builtin_platform_driver(bcm2712_pinctrl_driver); diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c -index 6768b2f03d68..a94a9c82f0e5 100644 +index 1489191a213f..8b178b8d7242 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c -@@ -362,7 +362,7 @@ static const struct gpio_chip bcm2835_gpio_chip = { - .get = bcm2835_gpio_get, - .set = bcm2835_gpio_set, - .set_config = gpiochip_generic_config, -- .base = -1, -+ .base = 0, - .ngpio = BCM2835_NUM_GPIOS, - .can_sleep = false, - }; -@@ -378,7 +378,7 @@ static const struct gpio_chip bcm2711_gpio_chip = { - .get = bcm2835_gpio_get, - .set = bcm2835_gpio_set, - .set_config = gpiochip_generic_config, -- .base = -1, -+ .base = 0, - .ngpio = BCM2711_NUM_GPIOS, - .can_sleep = false, - }; -@@ -1290,9 +1290,13 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev) - char *name; - - girq->parentsi = irq_of_parse_and_map(np, i); -- if (!is_7211) -+ if (!is_7211) { -+ if (!girq->parentsi) { -+ girq->num_parents = i; -+ break; -+ } - continue; +@@ -420,15 +420,32 @@ static void bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc, + unsigned long events; + unsigned offset; + unsigned gpio; ++ u32 levs, levs2; + + events = bcm2835_gpio_rd(pc, GPEDS0 + bank * 4); ++ levs = bcm2835_gpio_rd(pc, GPLEV0 + bank * 4); + events &= mask; + events &= pc->enabled_irq_mapbank; ++ bcm2835_gpio_wr(pc, GPEDS0 + bank * 4, events); ++ ++retry: + for_each_set_bit(offset, &events, 32) { + gpio = (32 * bank) + offset; + generic_handle_domain_irq(pc->gpio_chip.irq.domain, + gpio); + } ++ events = bcm2835_gpio_rd(pc, GPEDS0 + bank * 4); ++ levs2 = bcm2835_gpio_rd(pc, GPLEV0 + bank * 4); ++ ++ events |= levs2 & ~levs & bcm2835_gpio_rd(pc, GPREN0 + bank * 4); ++ events |= ~levs2 & levs & bcm2835_gpio_rd(pc, GPFEN0 + bank * 4); ++ events &= mask; ++ events &= pc->enabled_irq_mapbank; ++ if (events) { ++ bcm2835_gpio_wr(pc, GPEDS0 + bank * 4, events); ++ levs = levs2; ++ goto retry; ++ } + } + + static void bcm2835_gpio_irq_handler(struct irq_desc *desc) +@@ -668,11 +685,7 @@ static int bcm2835_gpio_irq_set_type(struct irq_data *data, unsigned int type) + + static void bcm2835_gpio_irq_ack(struct irq_data *data) + { +- struct gpio_chip *chip = irq_data_get_irq_chip_data(data); +- struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); +- unsigned gpio = irqd_to_hwirq(data); - -+ } - /* Skip over the all banks interrupts */ - pc->wake_irqi = irq_of_parse_and_map(np, i + - BCM2835_NUM_IRQS + 1); -@@ -1318,7 +1322,7 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev) +- bcm2835_gpio_set_bit(pc, GPEDS0, gpio); ++ /* Nothing to do - the main interrupt handler includes the ACK */ + } + + static int bcm2835_gpio_irq_set_wake(struct irq_data *data, unsigned int on) +@@ -926,9 +939,12 @@ static int bcm2835_pmx_free(struct pinctrl_dev *pctldev, + unsigned offset) + { + struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ enum bcm2835_fsel fsel = bcm2835_pinctrl_fsel_get(pc, offset); ++ ++ /* Return non-GPIOs to GPIO_IN */ ++ if (fsel != BCM2835_FSEL_GPIO_IN && fsel != BCM2835_FSEL_GPIO_OUT) ++ bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_IN); + +- /* disable by setting to GPIO_IN */ +- bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_IN); + return 0; + } + +@@ -970,10 +986,7 @@ static void bcm2835_pmx_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) + { +- struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); +- +- /* disable by setting to GPIO_IN */ +- bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_IN); ++ (void)bcm2835_pmx_free(pctldev, offset); + } + + static int bcm2835_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, +@@ -1355,7 +1368,7 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev) girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_level_irq; @@ -98294,11 +149741,1702 @@ if (err) { dev_err(dev, "could not add GPIO chip\n"); goto out_remove; +diff --git a/drivers/pinctrl/pinctrl-rp1.c b/drivers/pinctrl/pinctrl-rp1.c +new file mode 100644 +index 000000000000..b2729c5e6a92 +--- /dev/null ++++ b/drivers/pinctrl/pinctrl-rp1.c +@@ -0,0 +1,1600 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Driver for Raspberry Pi RP1 GPIO unit (pinctrl + GPIO) ++ * ++ * Copyright (C) 2023 Raspberry Pi Ltd. ++ * ++ * This driver is inspired by: ++ * pinctrl-bcm2835.c, please see original file for copyright information ++ */ ++ ++#include <linux/bitmap.h> ++#include <linux/bitops.h> ++#include <linux/bug.h> ++#include <linux/delay.h> ++#include <linux/device.h> ++#include <linux/err.h> ++#include <linux/gpio/driver.h> ++#include <linux/io.h> ++#include <linux/irq.h> ++#include <linux/irqdesc.h> ++#include <linux/init.h> ++#include <linux/of_address.h> ++#include <linux/of.h> ++#include <linux/of_irq.h> ++#include <linux/pinctrl/consumer.h> ++#include <linux/pinctrl/machine.h> ++#include <linux/pinctrl/pinconf.h> ++#include <linux/pinctrl/pinctrl.h> ++#include <linux/pinctrl/pinmux.h> ++#include <linux/pinctrl/pinconf-generic.h> ++#include <linux/platform_device.h> ++#include <linux/seq_file.h> ++#include <linux/spinlock.h> ++#include <linux/types.h> ++#include "core.h" ++#include "pinconf.h" ++#include "pinctrl-utils.h" ++ ++#define MODULE_NAME "pinctrl-rp1" ++#define RP1_NUM_GPIOS 54 ++#define RP1_NUM_BANKS 3 ++ ++#define RP1_RW_OFFSET 0x0000 ++#define RP1_XOR_OFFSET 0x1000 ++#define RP1_SET_OFFSET 0x2000 ++#define RP1_CLR_OFFSET 0x3000 ++ ++#define RP1_GPIO_STATUS 0x0000 ++#define RP1_GPIO_CTRL 0x0004 ++ ++#define RP1_GPIO_PCIE_INTE 0x011c ++#define RP1_GPIO_PCIE_INTS 0x0124 ++ ++#define RP1_GPIO_EVENTS_SHIFT_RAW 20 ++#define RP1_GPIO_STATUS_FALLING BIT(20) ++#define RP1_GPIO_STATUS_RISING BIT(21) ++#define RP1_GPIO_STATUS_LOW BIT(22) ++#define RP1_GPIO_STATUS_HIGH BIT(23) ++ ++#define RP1_GPIO_EVENTS_SHIFT_FILTERED 24 ++#define RP1_GPIO_STATUS_F_FALLING BIT(24) ++#define RP1_GPIO_STATUS_F_RISING BIT(25) ++#define RP1_GPIO_STATUS_F_LOW BIT(26) ++#define RP1_GPIO_STATUS_F_HIGH BIT(27) ++ ++#define RP1_GPIO_CTRL_FUNCSEL_LSB 0 ++#define RP1_GPIO_CTRL_FUNCSEL_MASK 0x0000001f ++#define RP1_GPIO_CTRL_OUTOVER_LSB 12 ++#define RP1_GPIO_CTRL_OUTOVER_MASK 0x00003000 ++#define RP1_GPIO_CTRL_OEOVER_LSB 14 ++#define RP1_GPIO_CTRL_OEOVER_MASK 0x0000c000 ++#define RP1_GPIO_CTRL_INOVER_LSB 16 ++#define RP1_GPIO_CTRL_INOVER_MASK 0x00030000 ++#define RP1_GPIO_CTRL_IRQEN_FALLING BIT(20) ++#define RP1_GPIO_CTRL_IRQEN_RISING BIT(21) ++#define RP1_GPIO_CTRL_IRQEN_LOW BIT(22) ++#define RP1_GPIO_CTRL_IRQEN_HIGH BIT(23) ++#define RP1_GPIO_CTRL_IRQEN_F_FALLING BIT(24) ++#define RP1_GPIO_CTRL_IRQEN_F_RISING BIT(25) ++#define RP1_GPIO_CTRL_IRQEN_F_LOW BIT(26) ++#define RP1_GPIO_CTRL_IRQEN_F_HIGH BIT(27) ++#define RP1_GPIO_CTRL_IRQRESET BIT(28) ++#define RP1_GPIO_CTRL_IRQOVER_LSB 30 ++#define RP1_GPIO_CTRL_IRQOVER_MASK 0xc0000000 ++ ++#define RP1_INT_EDGE_FALLING BIT(0) ++#define RP1_INT_EDGE_RISING BIT(1) ++#define RP1_INT_LEVEL_LOW BIT(2) ++#define RP1_INT_LEVEL_HIGH BIT(3) ++#define RP1_INT_MASK 0xf ++ ++#define RP1_INT_EDGE_BOTH (RP1_INT_EDGE_FALLING | \ ++ RP1_INT_EDGE_RISING) ++#define RP1_PUD_OFF 0 ++#define RP1_PUD_DOWN 1 ++#define RP1_PUD_UP 2 ++ ++#define RP1_FSEL_COUNT 9 ++ ++#define RP1_FSEL_ALT0 0x00 ++#define RP1_FSEL_GPIO 0x05 ++#define RP1_FSEL_NONE 0x09 ++#define RP1_FSEL_NONE_HW 0x1f ++ ++#define RP1_DIR_OUTPUT 0 ++#define RP1_DIR_INPUT 1 ++ ++#define RP1_OUTOVER_PERI 0 ++#define RP1_OUTOVER_INVPERI 1 ++#define RP1_OUTOVER_LOW 2 ++#define RP1_OUTOVER_HIGH 3 ++ ++#define RP1_OEOVER_PERI 0 ++#define RP1_OEOVER_INVPERI 1 ++#define RP1_OEOVER_DISABLE 2 ++#define RP1_OEOVER_ENABLE 3 ++ ++#define RP1_INOVER_PERI 0 ++#define RP1_INOVER_INVPERI 1 ++#define RP1_INOVER_LOW 2 ++#define RP1_INOVER_HIGH 3 ++ ++#define RP1_RIO_OUT 0x00 ++#define RP1_RIO_OE 0x04 ++#define RP1_RIO_IN 0x08 ++ ++#define RP1_PAD_SLEWFAST_MASK 0x00000001 ++#define RP1_PAD_SLEWFAST_LSB 0 ++#define RP1_PAD_SCHMITT_MASK 0x00000002 ++#define RP1_PAD_SCHMITT_LSB 1 ++#define RP1_PAD_PULL_MASK 0x0000000c ++#define RP1_PAD_PULL_LSB 2 ++#define RP1_PAD_DRIVE_MASK 0x00000030 ++#define RP1_PAD_DRIVE_LSB 4 ++#define RP1_PAD_IN_ENABLE_MASK 0x00000040 ++#define RP1_PAD_IN_ENABLE_LSB 6 ++#define RP1_PAD_OUT_DISABLE_MASK 0x00000080 ++#define RP1_PAD_OUT_DISABLE_LSB 7 ++ ++#define RP1_PAD_DRIVE_2MA 0x00000000 ++#define RP1_PAD_DRIVE_4MA 0x00000010 ++#define RP1_PAD_DRIVE_8MA 0x00000020 ++#define RP1_PAD_DRIVE_12MA 0x00000030 ++ ++#define FLD_GET(r, f) (((r) & (f ## _MASK)) >> (f ## _LSB)) ++#define FLD_SET(r, f, v) r = (((r) & ~(f ## _MASK)) | ((v) << (f ## _LSB))) ++ ++#define FUNC(f) \ ++ func_##f = #f ++#define RP1_MAX_FSEL 8 ++#define PIN(i, f0, f1, f2, f3, f4, f5, f6, f7, f8) \ ++ i = { \ ++ .funcs = { \ ++ func_##f0, \ ++ func_##f1, \ ++ func_##f2, \ ++ func_##f3, \ ++ func_##f4, \ ++ func_##f5, \ ++ func_##f6, \ ++ func_##f7, \ ++ func_##f8, \ ++ }, \ ++ } ++ ++#define LEGACY_MAP(n, f0, f1, f2, f3, f4, f5) \ ++ n = { \ ++ func_gpio, \ ++ func_gpio, \ ++ func_##f5, \ ++ func_##f4, \ ++ func_##f0, \ ++ func_##f1, \ ++ func_##f2, \ ++ func_##f3, \ ++ } ++ ++struct rp1_iobank_desc { ++ int min_gpio; ++ int num_gpios; ++ int gpio_offset; ++ int inte_offset; ++ int ints_offset; ++ int rio_offset; ++ int pads_offset; ++}; ++ ++struct rp1_pin_info { ++ u8 num; ++ u8 bank; ++ u8 offset; ++ u8 fsel; ++ u8 irq_type; ++ ++ void __iomem *gpio; ++ void __iomem *rio; ++ void __iomem *inte; ++ void __iomem *ints; ++ void __iomem *pad; ++}; ++ ++enum funcs { ++ func_alt0, ++ func_alt1, ++ func_alt2, ++ func_alt3, ++ func_alt4, ++ func_gpio, ++ func_alt6, ++ func_alt7, ++ func_alt8, ++ func_none, ++ func_aaud, ++ func_dcd0, ++ func_dpi, ++ func_dsi0_te_ext, ++ func_dsi1_te_ext, ++ func_dsr0, ++ func_dtr0, ++ func_gpclk0, ++ func_gpclk1, ++ func_gpclk2, ++ func_gpclk3, ++ func_gpclk4, ++ func_gpclk5, ++ func_i2c0, ++ func_i2c1, ++ func_i2c2, ++ func_i2c3, ++ func_i2c4, ++ func_i2c5, ++ func_i2c6, ++ func_i2s0, ++ func_i2s1, ++ func_i2s2, ++ func_ir, ++ func_mic, ++ func_pcie_clkreq_n, ++ func_pio, ++ func_proc_rio, ++ func_pwm0, ++ func_pwm1, ++ func_ri0, ++ func_sd0, ++ func_sd1, ++ func_spi0, ++ func_spi1, ++ func_spi2, ++ func_spi3, ++ func_spi4, ++ func_spi5, ++ func_spi6, ++ func_spi7, ++ func_spi8, ++ func_uart0, ++ func_uart1, ++ func_uart2, ++ func_uart3, ++ func_uart4, ++ func_uart5, ++ func_vbus0, ++ func_vbus1, ++ func_vbus2, ++ func_vbus3, ++ func__, ++ func_count = func__, ++ func_invalid = func__, ++}; ++ ++struct rp1_pin_funcs { ++ u8 funcsRP1_FSEL_COUNT; ++}; ++ ++struct rp1_pinctrl { ++ struct device *dev; ++ void __iomem *gpio_base; ++ void __iomem *rio_base; ++ void __iomem *pads_base; ++ int irqRP1_NUM_BANKS; ++ struct rp1_pin_info pinsRP1_NUM_GPIOS; ++ ++ struct pinctrl_dev *pctl_dev; ++ struct gpio_chip gpio_chip; ++ struct pinctrl_gpio_range gpio_range; ++ ++ raw_spinlock_t irq_lockRP1_NUM_BANKS; ++}; ++ ++const struct rp1_iobank_desc rp1_iobanksRP1_NUM_BANKS = { ++ /* gpio inte ints rio pads */ ++ { 0, 28, 0x0000, 0x011c, 0x0124, 0x0000, 0x0004 }, ++ { 28, 6, 0x4000, 0x411c, 0x4124, 0x4000, 0x4004 }, ++ { 34, 20, 0x8000, 0x811c, 0x8124, 0x8000, 0x8004 }, ++}; ++ ++/* pins are just named GPIO0..GPIO53 */ ++#define RP1_GPIO_PIN(a) PINCTRL_PIN(a, "gpio" #a) ++static struct pinctrl_pin_desc rp1_gpio_pins = { ++ RP1_GPIO_PIN(0), ++ RP1_GPIO_PIN(1), ++ RP1_GPIO_PIN(2), ++ RP1_GPIO_PIN(3), ++ RP1_GPIO_PIN(4), ++ RP1_GPIO_PIN(5), ++ RP1_GPIO_PIN(6), ++ RP1_GPIO_PIN(7), ++ RP1_GPIO_PIN(8), ++ RP1_GPIO_PIN(9), ++ RP1_GPIO_PIN(10), ++ RP1_GPIO_PIN(11), ++ RP1_GPIO_PIN(12), ++ RP1_GPIO_PIN(13), ++ RP1_GPIO_PIN(14), ++ RP1_GPIO_PIN(15), ++ RP1_GPIO_PIN(16), ++ RP1_GPIO_PIN(17), ++ RP1_GPIO_PIN(18), ++ RP1_GPIO_PIN(19), ++ RP1_GPIO_PIN(20), ++ RP1_GPIO_PIN(21), ++ RP1_GPIO_PIN(22), ++ RP1_GPIO_PIN(23), ++ RP1_GPIO_PIN(24), ++ RP1_GPIO_PIN(25), ++ RP1_GPIO_PIN(26), ++ RP1_GPIO_PIN(27), ++ RP1_GPIO_PIN(28), ++ RP1_GPIO_PIN(29), ++ RP1_GPIO_PIN(30), ++ RP1_GPIO_PIN(31), ++ RP1_GPIO_PIN(32), ++ RP1_GPIO_PIN(33), ++ RP1_GPIO_PIN(34), ++ RP1_GPIO_PIN(35), ++ RP1_GPIO_PIN(36), ++ RP1_GPIO_PIN(37), ++ RP1_GPIO_PIN(38), ++ RP1_GPIO_PIN(39), ++ RP1_GPIO_PIN(40), ++ RP1_GPIO_PIN(41), ++ RP1_GPIO_PIN(42), ++ RP1_GPIO_PIN(43), ++ RP1_GPIO_PIN(44), ++ RP1_GPIO_PIN(45), ++ RP1_GPIO_PIN(46), ++ RP1_GPIO_PIN(47), ++ RP1_GPIO_PIN(48), ++ RP1_GPIO_PIN(49), ++ RP1_GPIO_PIN(50), ++ RP1_GPIO_PIN(51), ++ RP1_GPIO_PIN(52), ++ RP1_GPIO_PIN(53), ++}; ++ ++/* one pin per group */ ++static const char * const rp1_gpio_groups = { ++ "gpio0", ++ "gpio1", ++ "gpio2", ++ "gpio3", ++ "gpio4", ++ "gpio5", ++ "gpio6", ++ "gpio7", ++ "gpio8", ++ "gpio9", ++ "gpio10", ++ "gpio11", ++ "gpio12", ++ "gpio13", ++ "gpio14", ++ "gpio15", ++ "gpio16", ++ "gpio17", ++ "gpio18", ++ "gpio19", ++ "gpio20", ++ "gpio21", ++ "gpio22", ++ "gpio23", ++ "gpio24", ++ "gpio25", ++ "gpio26", ++ "gpio27", ++ "gpio28", ++ "gpio29", ++ "gpio30", ++ "gpio31", ++ "gpio32", ++ "gpio33", ++ "gpio34", ++ "gpio35", ++ "gpio36", ++ "gpio37", ++ "gpio38", ++ "gpio39", ++ "gpio40", ++ "gpio41", ++ "gpio42", ++ "gpio43", ++ "gpio44", ++ "gpio45", ++ "gpio46", ++ "gpio47", ++ "gpio48", ++ "gpio49", ++ "gpio50", ++ "gpio51", ++ "gpio52", ++ "gpio53", ++}; ++ ++static const char * const rp1_func_names = { ++ FUNC(alt0), ++ FUNC(alt1), ++ FUNC(alt2), ++ FUNC(alt3), ++ FUNC(alt4), ++ FUNC(gpio), ++ FUNC(alt6), ++ FUNC(alt7), ++ FUNC(alt8), ++ FUNC(none), ++ FUNC(aaud), ++ FUNC(dcd0), ++ FUNC(dpi), ++ FUNC(dsi0_te_ext), ++ FUNC(dsi1_te_ext), ++ FUNC(dsr0), ++ FUNC(dtr0), ++ FUNC(gpclk0), ++ FUNC(gpclk1), ++ FUNC(gpclk2), ++ FUNC(gpclk3), ++ FUNC(gpclk4), ++ FUNC(gpclk5), ++ FUNC(i2c0), ++ FUNC(i2c1), ++ FUNC(i2c2), ++ FUNC(i2c3), ++ FUNC(i2c4), ++ FUNC(i2c5), ++ FUNC(i2c6), ++ FUNC(i2s0), ++ FUNC(i2s1), ++ FUNC(i2s2), ++ FUNC(ir), ++ FUNC(mic), ++ FUNC(pcie_clkreq_n), ++ FUNC(pio), ++ FUNC(proc_rio), ++ FUNC(pwm0), ++ FUNC(pwm1), ++ FUNC(ri0), ++ FUNC(sd0), ++ FUNC(sd1), ++ FUNC(spi0), ++ FUNC(spi1), ++ FUNC(spi2), ++ FUNC(spi3), ++ FUNC(spi4), ++ FUNC(spi5), ++ FUNC(spi6), ++ FUNC(spi7), ++ FUNC(spi8), ++ FUNC(uart0), ++ FUNC(uart1), ++ FUNC(uart2), ++ FUNC(uart3), ++ FUNC(uart4), ++ FUNC(uart5), ++ FUNC(vbus0), ++ FUNC(vbus1), ++ FUNC(vbus2), ++ FUNC(vbus3), ++ func_invalid = "?" ++}; ++ ++static const struct rp1_pin_funcs rp1_gpio_pin_funcs = { ++ PIN(0, spi0, dpi, uart1, i2c0, _, gpio, proc_rio, pio, spi2), ++ PIN(1, spi0, dpi, uart1, i2c0, _, gpio, proc_rio, pio, spi2), ++ PIN(2, spi0, dpi, uart1, i2c1, ir, gpio, proc_rio, pio, spi2), ++ PIN(3, spi0, dpi, uart1, i2c1, ir, gpio, proc_rio, pio, spi2), ++ PIN(4, gpclk0, dpi, uart2, i2c2, ri0, gpio, proc_rio, pio, spi3), ++ PIN(5, gpclk1, dpi, uart2, i2c2, dtr0, gpio, proc_rio, pio, spi3), ++ PIN(6, gpclk2, dpi, uart2, i2c3, dcd0, gpio, proc_rio, pio, spi3), ++ PIN(7, spi0, dpi, uart2, i2c3, dsr0, gpio, proc_rio, pio, spi3), ++ PIN(8, spi0, dpi, uart3, i2c0, _, gpio, proc_rio, pio, spi4), ++ PIN(9, spi0, dpi, uart3, i2c0, _, gpio, proc_rio, pio, spi4), ++ PIN(10, spi0, dpi, uart3, i2c1, _, gpio, proc_rio, pio, spi4), ++ PIN(11, spi0, dpi, uart3, i2c1, _, gpio, proc_rio, pio, spi4), ++ PIN(12, pwm0, dpi, uart4, i2c2, aaud, gpio, proc_rio, pio, spi5), ++ PIN(13, pwm0, dpi, uart4, i2c2, aaud, gpio, proc_rio, pio, spi5), ++ PIN(14, pwm0, dpi, uart4, i2c3, uart0, gpio, proc_rio, pio, spi5), ++ PIN(15, pwm0, dpi, uart4, i2c3, uart0, gpio, proc_rio, pio, spi5), ++ PIN(16, spi1, dpi, dsi0_te_ext, _, uart0, gpio, proc_rio, pio, _), ++ PIN(17, spi1, dpi, dsi1_te_ext, _, uart0, gpio, proc_rio, pio, _), ++ PIN(18, spi1, dpi, i2s0, pwm0, i2s1, gpio, proc_rio, pio, gpclk1), ++ PIN(19, spi1, dpi, i2s0, pwm0, i2s1, gpio, proc_rio, pio, _), ++ PIN(20, spi1, dpi, i2s0, gpclk0, i2s1, gpio, proc_rio, pio, _), ++ PIN(21, spi1, dpi, i2s0, gpclk1, i2s1, gpio, proc_rio, pio, _), ++ PIN(22, sd0, dpi, i2s0, i2c3, i2s1, gpio, proc_rio, pio, _), ++ PIN(23, sd0, dpi, i2s0, i2c3, i2s1, gpio, proc_rio, pio, _), ++ PIN(24, sd0, dpi, i2s0, _, i2s1, gpio, proc_rio, pio, spi2), ++ PIN(25, sd0, dpi, i2s0, mic, i2s1, gpio, proc_rio, pio, spi3), ++ PIN(26, sd0, dpi, i2s0, mic, i2s1, gpio, proc_rio, pio, spi5), ++ PIN(27, sd0, dpi, i2s0, mic, i2s1, gpio, proc_rio, pio, spi1), ++ PIN(28, sd1, i2c4, i2s2, spi6, vbus0, gpio, proc_rio, _, _), ++ PIN(29, sd1, i2c4, i2s2, spi6, vbus0, gpio, proc_rio, _, _), ++ PIN(30, sd1, i2c5, i2s2, spi6, uart5, gpio, proc_rio, _, _), ++ PIN(31, sd1, i2c5, i2s2, spi6, uart5, gpio, proc_rio, _, _), ++ PIN(32, sd1, gpclk3, i2s2, spi6, uart5, gpio, proc_rio, _, _), ++ PIN(33, sd1, gpclk4, i2s2, spi6, uart5, gpio, proc_rio, _, _), ++ PIN(34, pwm1, gpclk3, vbus0, i2c4, mic, gpio, proc_rio, _, _), ++ PIN(35, spi8, pwm1, vbus0, i2c4, mic, gpio, proc_rio, _, _), ++ PIN(36, spi8, uart5, pcie_clkreq_n, i2c5, mic, gpio, proc_rio, _, _), ++ PIN(37, spi8, uart5, mic, i2c5, pcie_clkreq_n, gpio, proc_rio, _, _), ++ PIN(38, spi8, uart5, mic, i2c6, aaud, gpio, proc_rio, dsi0_te_ext, _), ++ PIN(39, spi8, uart5, mic, i2c6, aaud, gpio, proc_rio, dsi1_te_ext, _), ++ PIN(40, pwm1, uart5, i2c4, spi6, aaud, gpio, proc_rio, _, _), ++ PIN(41, pwm1, uart5, i2c4, spi6, aaud, gpio, proc_rio, _, _), ++ PIN(42, gpclk5, uart5, vbus1, spi6, i2s2, gpio, proc_rio, _, _), ++ PIN(43, gpclk4, uart5, vbus1, spi6, i2s2, gpio, proc_rio, _, _), ++ PIN(44, gpclk5, i2c5, pwm1, spi6, i2s2, gpio, proc_rio, _, _), ++ PIN(45, pwm1, i2c5, spi7, spi6, i2s2, gpio, proc_rio, _, _), ++ PIN(46, gpclk3, i2c4, spi7, mic, i2s2, gpio, proc_rio, dsi0_te_ext, _), ++ PIN(47, gpclk5, i2c4, spi7, mic, i2s2, gpio, proc_rio, dsi1_te_ext, _), ++ PIN(48, pwm1, pcie_clkreq_n, spi7, mic, uart5, gpio, proc_rio, _, _), ++ PIN(49, spi8, spi7, i2c5, aaud, uart5, gpio, proc_rio, _, _), ++ PIN(50, spi8, spi7, i2c5, aaud, vbus2, gpio, proc_rio, _, _), ++ PIN(51, spi8, spi7, i2c6, aaud, vbus2, gpio, proc_rio, _, _), ++ PIN(52, spi8, _, i2c6, aaud, vbus3, gpio, proc_rio, _, _), ++ PIN(53, spi8, spi7, _, pcie_clkreq_n, vbus3, gpio, proc_rio, _, _), ++}; ++ ++static const u8 legacy_fsel_map8 = { ++ LEGACY_MAP(0, i2c0, _, dpi, spi2, uart1, _), ++ LEGACY_MAP(1, i2c0, _, dpi, spi2, uart1, _), ++ LEGACY_MAP(2, i2c1, _, dpi, spi2, uart1, _), ++ LEGACY_MAP(3, i2c1, _, dpi, spi2, uart1, _), ++ LEGACY_MAP(4, gpclk0, _, dpi, spi3, uart2, i2c2), ++ LEGACY_MAP(5, gpclk1, _, dpi, spi3, uart2, i2c2), ++ LEGACY_MAP(6, gpclk2, _, dpi, spi3, uart2, i2c3), ++ LEGACY_MAP(7, spi0, _, dpi, spi3, uart2, i2c3), ++ LEGACY_MAP(8, spi0, _, dpi, _, uart3, i2c0), ++ LEGACY_MAP(9, spi0, _, dpi, _, uart3, i2c0), ++ LEGACY_MAP(10, spi0, _, dpi, _, uart3, i2c1), ++ LEGACY_MAP(11, spi0, _, dpi, _, uart3, i2c1), ++ LEGACY_MAP(12, pwm0, _, dpi, spi5, uart4, i2c2), ++ LEGACY_MAP(13, pwm0, _, dpi, spi5, uart4, i2c2), ++ LEGACY_MAP(14, uart0, _, dpi, spi5, uart4, _), ++ LEGACY_MAP(15, uart0, _, dpi, spi5, uart4, _), ++ LEGACY_MAP(16, _, _, dpi, uart0, spi1, _), ++ LEGACY_MAP(17, _, _, dpi, uart0, spi1, _), ++ LEGACY_MAP(18, i2s0, _, dpi, _, spi1, pwm0), ++ LEGACY_MAP(19, i2s0, _, dpi, _, spi1, pwm0), ++ LEGACY_MAP(20, i2s0, _, dpi, _, spi1, gpclk0), ++ LEGACY_MAP(21, i2s0, _, dpi, _, spi1, gpclk1), ++ LEGACY_MAP(22, sd0, _, dpi, _, _, i2c3), ++ LEGACY_MAP(23, sd0, _, dpi, _, _, i2c3), ++ LEGACY_MAP(24, sd0, _, dpi, _, _, spi2), ++ LEGACY_MAP(25, sd0, _, dpi, _, _, spi3), ++ LEGACY_MAP(26, sd0, _, dpi, _, _, spi5), ++ LEGACY_MAP(27, sd0, _, dpi, _, _, _), ++}; ++ ++static const char * const irq_type_names = { ++ IRQ_TYPE_NONE = "none", ++ IRQ_TYPE_EDGE_RISING = "edge-rising", ++ IRQ_TYPE_EDGE_FALLING = "edge-falling", ++ IRQ_TYPE_EDGE_BOTH = "edge-both", ++ IRQ_TYPE_LEVEL_HIGH = "level-high", ++ IRQ_TYPE_LEVEL_LOW = "level-low", ++}; ++ ++static int rp1_pinconf_set(struct pinctrl_dev *pctldev, ++ unsigned int offset, unsigned long *configs, ++ unsigned int num_configs); ++ ++static struct rp1_pin_info *rp1_get_pin(struct gpio_chip *chip, ++ unsigned int offset) ++{ ++ struct rp1_pinctrl *pc = gpiochip_get_data(chip); ++ ++ if (pc && offset < RP1_NUM_GPIOS) ++ return &pc->pinsoffset; ++ return NULL; ++} ++ ++static struct rp1_pin_info *rp1_get_pin_pctl(struct pinctrl_dev *pctldev, ++ unsigned int offset) ++{ ++ struct rp1_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ ++ if (pc && offset < RP1_NUM_GPIOS) ++ return &pc->pinsoffset; ++ return NULL; ++} ++ ++static void rp1_pad_update(struct rp1_pin_info *pin, u32 clr, u32 set) ++{ ++ u32 padctrl = readl(pin->pad); ++ ++ padctrl &= ~clr; ++ padctrl |= set; ++ ++ writel(padctrl, pin->pad); ++} ++ ++static void rp1_input_enable(struct rp1_pin_info *pin, int value) ++{ ++ rp1_pad_update(pin, RP1_PAD_IN_ENABLE_MASK, ++ value ? RP1_PAD_IN_ENABLE_MASK : 0); ++} ++ ++static void rp1_output_enable(struct rp1_pin_info *pin, int value) ++{ ++ rp1_pad_update(pin, RP1_PAD_OUT_DISABLE_MASK, ++ value ? 0 : RP1_PAD_OUT_DISABLE_MASK); ++} ++ ++static u32 rp1_get_fsel(struct rp1_pin_info *pin) ++{ ++ u32 ctrl = readl(pin->gpio + RP1_GPIO_CTRL); ++ u32 oeover = FLD_GET(ctrl, RP1_GPIO_CTRL_OEOVER); ++ u32 fsel = FLD_GET(ctrl, RP1_GPIO_CTRL_FUNCSEL); ++ ++ if (oeover != RP1_OEOVER_PERI || fsel >= RP1_FSEL_COUNT) ++ fsel = RP1_FSEL_NONE; ++ ++ return fsel; ++} ++ ++static void rp1_set_fsel(struct rp1_pin_info *pin, u32 fsel) ++{ ++ u32 ctrl = readl(pin->gpio + RP1_GPIO_CTRL); ++ ++ if (fsel >= RP1_FSEL_COUNT) ++ fsel = RP1_FSEL_NONE_HW; ++ ++ rp1_input_enable(pin, 1); ++ rp1_output_enable(pin, 1); ++ ++ if (fsel == RP1_FSEL_NONE) { ++ FLD_SET(ctrl, RP1_GPIO_CTRL_OEOVER, RP1_OEOVER_DISABLE); ++ } else { ++ FLD_SET(ctrl, RP1_GPIO_CTRL_OUTOVER, RP1_OUTOVER_PERI); ++ FLD_SET(ctrl, RP1_GPIO_CTRL_OEOVER, RP1_OEOVER_PERI); ++ } ++ FLD_SET(ctrl, RP1_GPIO_CTRL_FUNCSEL, fsel); ++ writel(ctrl, pin->gpio + RP1_GPIO_CTRL); ++} ++ ++static int rp1_get_dir(struct rp1_pin_info *pin) ++{ ++ return !(readl(pin->rio + RP1_RIO_OE) & (1 << pin->offset)) ? ++ RP1_DIR_INPUT : RP1_DIR_OUTPUT; ++} ++ ++static void rp1_set_dir(struct rp1_pin_info *pin, bool is_input) ++{ ++ int offset = is_input ? RP1_CLR_OFFSET : RP1_SET_OFFSET; ++ ++ writel(1 << pin->offset, pin->rio + RP1_RIO_OE + offset); ++} ++ ++static int rp1_get_value(struct rp1_pin_info *pin) ++{ ++ return !!(readl(pin->rio + RP1_RIO_IN) & (1 << pin->offset)); ++} ++ ++static void rp1_set_value(struct rp1_pin_info *pin, int value) ++{ ++ /* Assume the pin is already an output */ ++ writel(1 << pin->offset, ++ pin->rio + RP1_RIO_OUT + (value ? RP1_SET_OFFSET : RP1_CLR_OFFSET)); ++} ++ ++static int rp1_gpio_get(struct gpio_chip *chip, unsigned offset) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin(chip, offset); ++ int ret; ++ ++ if (!pin) ++ return -EINVAL; ++ ret = rp1_get_value(pin); ++ return ret; ++} ++ ++static void rp1_gpio_set(struct gpio_chip *chip, unsigned offset, int value) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin(chip, offset); ++ ++ if (pin) ++ rp1_set_value(pin, value); ++} ++ ++static int rp1_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin(chip, offset); ++ u32 fsel; ++ ++ if (!pin) ++ return -EINVAL; ++ fsel = rp1_get_fsel(pin); ++ if (fsel != RP1_FSEL_GPIO) ++ return -EINVAL; ++ return (rp1_get_dir(pin) == RP1_DIR_OUTPUT) ? ++ GPIO_LINE_DIRECTION_OUT : ++ GPIO_LINE_DIRECTION_IN; ++} ++ ++static int rp1_gpio_direction_input(struct gpio_chip *chip, unsigned offset) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin(chip, offset); ++ ++ if (!pin) ++ return -EINVAL; ++ rp1_set_dir(pin, RP1_DIR_INPUT); ++ rp1_set_fsel(pin, RP1_FSEL_GPIO); ++ return 0; ++} ++ ++static int rp1_gpio_direction_output(struct gpio_chip *chip, unsigned offset, ++ int value) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin(chip, offset); ++ ++ if (!pin) ++ return -EINVAL; ++ rp1_set_value(pin, value); ++ rp1_set_dir(pin, RP1_DIR_OUTPUT); ++ rp1_set_fsel(pin, RP1_FSEL_GPIO); ++ return 0; ++} ++ ++static int rp1_gpio_set_config(struct gpio_chip *gc, unsigned offset, ++ unsigned long config) ++{ ++ struct rp1_pinctrl *pc = gpiochip_get_data(gc); ++ unsigned long configs = { config }; ++ ++ return rp1_pinconf_set(pc->pctl_dev, offset, configs, ++ ARRAY_SIZE(configs)); ++} ++ ++static const struct gpio_chip rp1_gpio_chip = { ++ .label = MODULE_NAME, ++ .owner = THIS_MODULE, ++ .request = gpiochip_generic_request, ++ .free = gpiochip_generic_free, ++ .direction_input = rp1_gpio_direction_input, ++ .direction_output = rp1_gpio_direction_output, ++ .get_direction = rp1_gpio_get_direction, ++ .get = rp1_gpio_get, ++ .set = rp1_gpio_set, ++ .base = -1, ++ .set_config = rp1_gpio_set_config, ++ .ngpio = RP1_NUM_GPIOS, ++ .can_sleep = false, ++}; ++ ++static void rp1_gpio_irq_handler(struct irq_desc *desc) ++{ ++ struct gpio_chip *chip = irq_desc_get_handler_data(desc); ++ struct rp1_pinctrl *pc = gpiochip_get_data(chip); ++ struct irq_chip *host_chip = irq_desc_get_chip(desc); ++ const struct rp1_iobank_desc *bank; ++ int irq = irq_desc_get_irq(desc); ++ unsigned long ints; ++ int b; ++ ++ if (pc->irq0 == irq) ++ bank = &rp1_iobanks0; ++ else if (pc->irq1 == irq) ++ bank = &rp1_iobanks1; ++ else ++ bank = &rp1_iobanks2; ++ ++ chained_irq_enter(host_chip, desc); ++ ++ ints = readl(pc->gpio_base + bank->ints_offset); ++ for_each_set_bit(b, &ints, 32) { ++ struct rp1_pin_info *pin = rp1_get_pin(chip, bank->min_gpio + b); ++ ++ writel(RP1_GPIO_CTRL_IRQRESET, ++ pin->gpio + RP1_SET_OFFSET + RP1_GPIO_CTRL); ++ generic_handle_irq(irq_linear_revmap(pc->gpio_chip.irq.domain, ++ bank->min_gpio + b)); ++ } ++ ++ chained_irq_exit(host_chip, desc); ++} ++ ++static void rp1_gpio_irq_config(struct rp1_pin_info *pin, bool enable) ++{ ++ writel(1 << pin->offset, ++ pin->inte + (enable ? RP1_SET_OFFSET : RP1_CLR_OFFSET)); ++ if (!enable) ++ /* Clear any latched events */ ++ writel(RP1_GPIO_CTRL_IRQRESET, ++ pin->gpio + RP1_SET_OFFSET + RP1_GPIO_CTRL); ++} ++ ++static void rp1_gpio_irq_enable(struct irq_data *data) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(data); ++ unsigned gpio = irqd_to_hwirq(data); ++ struct rp1_pin_info *pin = rp1_get_pin(chip, gpio); ++ ++ rp1_gpio_irq_config(pin, true); ++} ++ ++static void rp1_gpio_irq_disable(struct irq_data *data) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(data); ++ unsigned gpio = irqd_to_hwirq(data); ++ struct rp1_pin_info *pin = rp1_get_pin(chip, gpio); ++ ++ rp1_gpio_irq_config(pin, false); ++} ++ ++static int rp1_irq_set_type(struct rp1_pin_info *pin, unsigned int type) ++{ ++ u32 irq_flags; ++ ++ switch (type) { ++ case IRQ_TYPE_NONE: ++ irq_flags = 0; ++ break; ++ case IRQ_TYPE_EDGE_RISING: ++ irq_flags = RP1_INT_EDGE_RISING; ++ break; ++ case IRQ_TYPE_EDGE_FALLING: ++ irq_flags = RP1_INT_EDGE_FALLING; ++ break; ++ case IRQ_TYPE_EDGE_BOTH: ++ irq_flags = RP1_INT_EDGE_RISING | RP1_INT_EDGE_FALLING; ++ break; ++ case IRQ_TYPE_LEVEL_HIGH: ++ irq_flags = RP1_INT_LEVEL_HIGH; ++ break; ++ case IRQ_TYPE_LEVEL_LOW: ++ irq_flags = RP1_INT_LEVEL_LOW; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ /* Clear the event enables */ ++ writel(RP1_INT_MASK << RP1_GPIO_EVENTS_SHIFT_RAW, ++ pin->gpio + RP1_CLR_OFFSET + RP1_GPIO_CTRL); ++ /* Clear any latched events */ ++ writel(RP1_GPIO_CTRL_IRQRESET, ++ pin->gpio + RP1_SET_OFFSET + RP1_GPIO_CTRL); ++ /* Enable the events that are needed */ ++ writel(irq_flags << RP1_GPIO_EVENTS_SHIFT_RAW, ++ pin->gpio + RP1_SET_OFFSET + RP1_GPIO_CTRL); ++ pin->irq_type = type; ++ ++ return 0; ++} ++ ++static int rp1_gpio_irq_set_type(struct irq_data *data, unsigned int type) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(data); ++ struct rp1_pinctrl *pc = gpiochip_get_data(chip); ++ unsigned gpio = irqd_to_hwirq(data); ++ struct rp1_pin_info *pin = rp1_get_pin(chip, gpio); ++ int bank = pin->bank; ++ unsigned long flags; ++ int ret; ++ ++ raw_spin_lock_irqsave(&pc->irq_lockbank, flags); ++ ++ ret = rp1_irq_set_type(pin, type); ++ if (!ret) { ++ if (type & IRQ_TYPE_EDGE_BOTH) ++ irq_set_handler_locked(data, handle_edge_irq); ++ else ++ irq_set_handler_locked(data, handle_level_irq); ++ } ++ ++ raw_spin_unlock_irqrestore(&pc->irq_lockbank, flags); ++ ++ return ret; ++} ++ ++static void rp1_gpio_irq_ack(struct irq_data *data) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(data); ++ unsigned gpio = irqd_to_hwirq(data); ++ struct rp1_pin_info *pin = rp1_get_pin(chip, gpio); ++ ++ /* Clear any latched events */ ++ writel(RP1_GPIO_CTRL_IRQRESET, pin->gpio + RP1_SET_OFFSET + RP1_GPIO_CTRL); ++} ++ ++static int rp1_gpio_irq_set_affinity(struct irq_data *data, const struct cpumask *dest, bool force) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(data); ++ struct rp1_pinctrl *pc = gpiochip_get_data(chip); ++ const struct rp1_iobank_desc *bank; ++ struct irq_data *parent_data = NULL; ++ int i; ++ ++ for (i = 0; i < 3; i++) { ++ bank = &rp1_iobanksi; ++ if (data->hwirq >= bank->min_gpio && ++ data->hwirq < bank->min_gpio + bank->num_gpios) { ++ parent_data = irq_get_irq_data(pc->irqi); ++ break; ++ } ++ } ++ ++ if (parent_data && parent_data->chip->irq_set_affinity) ++ return parent_data->chip->irq_set_affinity(parent_data, dest, force); ++ ++ return -EINVAL; ++} ++ ++static struct irq_chip rp1_gpio_irq_chip = { ++ .name = MODULE_NAME, ++ .irq_enable = rp1_gpio_irq_enable, ++ .irq_disable = rp1_gpio_irq_disable, ++ .irq_set_type = rp1_gpio_irq_set_type, ++ .irq_ack = rp1_gpio_irq_ack, ++ .irq_mask = rp1_gpio_irq_disable, ++ .irq_unmask = rp1_gpio_irq_enable, ++ .irq_set_affinity = rp1_gpio_irq_set_affinity, ++ .flags = IRQCHIP_IMMUTABLE, ++}; ++ ++static int rp1_pctl_get_groups_count(struct pinctrl_dev *pctldev) ++{ ++ return ARRAY_SIZE(rp1_gpio_groups); ++} ++ ++static const char *rp1_pctl_get_group_name(struct pinctrl_dev *pctldev, ++ unsigned selector) ++{ ++ return rp1_gpio_groupsselector; ++} ++ ++static enum funcs rp1_get_fsel_func(unsigned pin, unsigned fsel) ++{ ++ if (pin < RP1_NUM_GPIOS) { ++ if (fsel < RP1_FSEL_COUNT) ++ return rp1_gpio_pin_funcspin.funcsfsel; ++ else if (fsel == RP1_FSEL_NONE) ++ return func_none; ++ } ++ return func_invalid; ++} ++ ++static int rp1_pctl_get_group_pins(struct pinctrl_dev *pctldev, ++ unsigned selector, ++ const unsigned **pins, ++ unsigned *num_pins) ++{ ++ *pins = &rp1_gpio_pinsselector.number; ++ *num_pins = 1; ++ ++ return 0; ++} ++ ++static void rp1_pctl_pin_dbg_show(struct pinctrl_dev *pctldev, ++ struct seq_file *s, ++ unsigned offset) ++{ ++ struct rp1_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ struct gpio_chip *chip = &pc->gpio_chip; ++ struct rp1_pin_info *pin = rp1_get_pin_pctl(pctldev, offset); ++ u32 fsel = rp1_get_fsel(pin); ++ enum funcs func = rp1_get_fsel_func(offset, fsel); ++ int value = rp1_get_value(pin); ++ int irq = irq_find_mapping(chip->irq.domain, offset); ++ ++ seq_printf(s, "function %s (%s) in %s; irq %d (%s)", ++ rp1_func_namesfsel, rp1_func_namesfunc, ++ value ? "hi" : "lo", ++ irq, irq_type_namespin->irq_type); ++} ++ ++static void rp1_pctl_dt_free_map(struct pinctrl_dev *pctldev, ++ struct pinctrl_map *maps, unsigned num_maps) ++{ ++ int i; ++ ++ for (i = 0; i < num_maps; i++) ++ if (mapsi.type == PIN_MAP_TYPE_CONFIGS_PIN) ++ kfree(mapsi.data.configs.configs); ++ ++ kfree(maps); ++} ++ ++static int rp1_pctl_legacy_map_func(struct rp1_pinctrl *pc, ++ struct device_node *np, u32 pin, u32 fnum, ++ struct pinctrl_map *maps, ++ unsigned int *num_maps) ++{ ++ struct pinctrl_map *map = &maps*num_maps; ++ enum funcs func; ++ ++ if (fnum >= ARRAY_SIZE(legacy_fsel_map0)) { ++ dev_err(pc->dev, "%pOF: invalid brcm,function %d\n", np, fnum); ++ return -EINVAL; ++ } ++ ++ if (pin < ARRAY_SIZE(legacy_fsel_map)) { ++ func = legacy_fsel_mappinfnum; ++ } else if (fnum < 2) { ++ func = func_gpio; ++ } else { ++ dev_err(pc->dev, "%pOF: invalid brcm,pins value %d\n", ++ np, pin); ++ return -EINVAL; ++ } ++ ++ if (func == func_invalid) { ++ dev_err(pc->dev, "%pOF: brcm,function %d not supported on pin %d\n", ++ np, fnum, pin); ++ } ++ ++ map->type = PIN_MAP_TYPE_MUX_GROUP; ++ map->data.mux.group = rp1_gpio_groupspin; ++ map->data.mux.function = rp1_func_namesfunc; ++ (*num_maps)++; ++ ++ return 0; ++} ++ ++static int rp1_pctl_legacy_map_pull(struct rp1_pinctrl *pc, ++ struct device_node *np, u32 pin, u32 pull, ++ struct pinctrl_map *maps, ++ unsigned int *num_maps) ++{ ++ struct pinctrl_map *map = &maps*num_maps; ++ enum pin_config_param param; ++ unsigned long *configs; ++ ++ switch (pull) { ++ case RP1_PUD_OFF: ++ param = PIN_CONFIG_BIAS_DISABLE; ++ break; ++ case RP1_PUD_DOWN: ++ param = PIN_CONFIG_BIAS_PULL_DOWN; ++ break; ++ case RP1_PUD_UP: ++ param = PIN_CONFIG_BIAS_PULL_UP; ++ break; ++ default: ++ dev_err(pc->dev, "%pOF: invalid brcm,pull %d\n", np, pull); ++ return -EINVAL; ++ } ++ ++ configs = kzalloc(sizeof(*configs), GFP_KERNEL); ++ if (!configs) ++ return -ENOMEM; ++ ++ configs0 = pinconf_to_config_packed(param, 0); ++ map->type = PIN_MAP_TYPE_CONFIGS_PIN; ++ map->data.configs.group_or_pin = rp1_gpio_pinspin.name; ++ map->data.configs.configs = configs; ++ map->data.configs.num_configs = 1; ++ (*num_maps)++; ++ ++ return 0; ++} ++ ++static int rp1_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, ++ struct device_node *np, ++ struct pinctrl_map **map, ++ unsigned int *num_maps) ++{ ++ struct rp1_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ struct property *pins, *funcs, *pulls; ++ int num_pins, num_funcs, num_pulls, maps_per_pin; ++ struct pinctrl_map *maps; ++ unsigned long *configs = NULL; ++ const char *function = NULL; ++ unsigned int reserved_maps; ++ int num_configs = 0; ++ int i, err; ++ u32 pin, func, pull; ++ ++ /* Check for legacy pin declaration */ ++ pins = of_find_property(np, "brcm,pins", NULL); ++ ++ if (!pins) /* Assume generic bindings in this node */ ++ return pinconf_generic_dt_node_to_map_all(pctldev, np, map, num_maps); ++ ++ funcs = of_find_property(np, "brcm,function", NULL); ++ if (!funcs) ++ of_property_read_string(np, "function", &function); ++ ++ pulls = of_find_property(np, "brcm,pull", NULL); ++ if (!pulls) ++ pinconf_generic_parse_dt_config(np, pctldev, &configs, &num_configs); ++ ++ if (!function && !funcs && !num_configs && !pulls) { ++ dev_err(pc->dev, ++ "%pOF: no function, brcm,function, brcm,pull, etc.\n", ++ np); ++ return -EINVAL; ++ } ++ ++ num_pins = pins->length / 4; ++ num_funcs = funcs ? (funcs->length / 4) : 0; ++ num_pulls = pulls ? (pulls->length / 4) : 0; ++ ++ if (num_funcs > 1 && num_funcs != num_pins) { ++ dev_err(pc->dev, ++ "%pOF: brcm,function must have 1 or %d entries\n", ++ np, num_pins); ++ return -EINVAL; ++ } ++ ++ if (num_pulls > 1 && num_pulls != num_pins) { ++ dev_err(pc->dev, ++ "%pOF: brcm,pull must have 1 or %d entries\n", ++ np, num_pins); ++ return -EINVAL; ++ } ++ ++ maps_per_pin = 0; ++ if (function || num_funcs) ++ maps_per_pin++; ++ if (num_configs || num_pulls) ++ maps_per_pin++; ++ reserved_maps = num_pins * maps_per_pin; ++ maps = kcalloc(reserved_maps, sizeof(*maps), GFP_KERNEL); ++ if (!maps) ++ return -ENOMEM; ++ ++ *num_maps = 0; ++ ++ for (i = 0; i < num_pins; i++) { ++ err = of_property_read_u32_index(np, "brcm,pins", i, &pin); ++ if (err) ++ goto out; ++ if (num_funcs) { ++ err = of_property_read_u32_index(np, "brcm,function", ++ (num_funcs > 1) ? i : 0, ++ &func); ++ if (err) ++ goto out; ++ err = rp1_pctl_legacy_map_func(pc, np, pin, func, ++ maps, num_maps); ++ } else if (function) { ++ err = pinctrl_utils_add_map_mux(pctldev, &maps, ++ &reserved_maps, num_maps, ++ rp1_gpio_groupspin, ++ function); ++ } ++ ++ if (err) ++ goto out; ++ ++ if (num_pulls) { ++ err = of_property_read_u32_index(np, "brcm,pull", ++ (num_pulls > 1) ? i : 0, ++ &pull); ++ if (err) ++ goto out; ++ err = rp1_pctl_legacy_map_pull(pc, np, pin, pull, ++ maps, num_maps); ++ } else if (num_configs) { ++ err = pinctrl_utils_add_map_configs(pctldev, &maps, ++ &reserved_maps, num_maps, ++ rp1_gpio_groupspin, ++ configs, num_configs, ++ PIN_MAP_TYPE_CONFIGS_PIN); ++ } ++ ++ if (err) ++ goto out; ++ } ++ ++ *map = maps; ++ ++ return 0; ++ ++out: ++ rp1_pctl_dt_free_map(pctldev, maps, reserved_maps); ++ return err; ++} ++ ++static const struct pinctrl_ops rp1_pctl_ops = { ++ .get_groups_count = rp1_pctl_get_groups_count, ++ .get_group_name = rp1_pctl_get_group_name, ++ .get_group_pins = rp1_pctl_get_group_pins, ++ .pin_dbg_show = rp1_pctl_pin_dbg_show, ++ .dt_node_to_map = rp1_pctl_dt_node_to_map, ++ .dt_free_map = rp1_pctl_dt_free_map, ++}; ++ ++static int rp1_pmx_free(struct pinctrl_dev *pctldev, unsigned offset) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin_pctl(pctldev, offset); ++ u32 fsel = rp1_get_fsel(pin); ++ ++ /* Return non-GPIOs to GPIO_IN */ ++ if (fsel != RP1_FSEL_GPIO) { ++ rp1_set_dir(pin, RP1_DIR_INPUT); ++ rp1_set_fsel(pin, RP1_FSEL_GPIO); ++ } ++ ++ return 0; ++} ++ ++static int rp1_pmx_get_functions_count(struct pinctrl_dev *pctldev) ++{ ++ return func_count; ++} ++ ++static const char *rp1_pmx_get_function_name(struct pinctrl_dev *pctldev, ++ unsigned selector) ++{ ++ return (selector < func_count) ? rp1_func_namesselector : NULL; ++} ++ ++static int rp1_pmx_get_function_groups(struct pinctrl_dev *pctldev, ++ unsigned selector, ++ const char * const **groups, ++ unsigned * const num_groups) ++{ ++ /* every pin can do every function */ ++ *groups = rp1_gpio_groups; ++ *num_groups = ARRAY_SIZE(rp1_gpio_groups); ++ ++ return 0; ++} ++ ++static int rp1_pmx_set(struct pinctrl_dev *pctldev, unsigned func_selector, ++ unsigned group_selector) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin_pctl(pctldev, group_selector); ++ const u8 *pin_funcs; ++ int fsel; ++ ++ /* func_selector is an enum funcs, so needs translation */ ++ ++ if (func_selector >= RP1_FSEL_COUNT) { ++ /* Convert to an fsel number */ ++ pin_funcs = rp1_gpio_pin_funcspin->num.funcs; ++ for (fsel = 0; fsel < RP1_FSEL_COUNT; fsel++) { ++ if (pin_funcsfsel == func_selector) ++ break; ++ } ++ } else { ++ fsel = (int)func_selector; ++ } ++ ++ if (fsel >= RP1_FSEL_COUNT && fsel != RP1_FSEL_NONE) ++ return -EINVAL; ++ ++ rp1_set_fsel(pin, fsel); ++ ++ return 0; ++} ++ ++static void rp1_pmx_gpio_disable_free(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned offset) ++{ ++ (void)rp1_pmx_free(pctldev, offset); ++} ++ ++static int rp1_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned offset, ++ bool input) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin_pctl(pctldev, offset); ++ ++ rp1_set_dir(pin, input); ++ rp1_set_fsel(pin, RP1_FSEL_GPIO); ++ ++ return 0; ++} ++ ++static const struct pinmux_ops rp1_pmx_ops = { ++ .free = rp1_pmx_free, ++ .get_functions_count = rp1_pmx_get_functions_count, ++ .get_function_name = rp1_pmx_get_function_name, ++ .get_function_groups = rp1_pmx_get_function_groups, ++ .set_mux = rp1_pmx_set, ++ .gpio_disable_free = rp1_pmx_gpio_disable_free, ++ .gpio_set_direction = rp1_pmx_gpio_set_direction, ++}; ++ ++static void rp1_pull_config_set(struct rp1_pin_info *pin, unsigned int arg) ++{ ++ u32 padctrl = readl(pin->pad); ++ ++ FLD_SET(padctrl, RP1_PAD_PULL, arg & 0x3); ++ ++ writel(padctrl, pin->pad); ++} ++ ++/* Generic pinconf methods */ ++ ++static int rp1_pinconf_set(struct pinctrl_dev *pctldev, unsigned int offset, ++ unsigned long *configs, unsigned int num_configs) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin_pctl(pctldev, offset); ++ u32 param, arg; ++ int i; ++ ++ if (!pin) ++ return -EINVAL; ++ ++ for (i = 0; i < num_configs; i++) { ++ param = pinconf_to_config_param(configsi); ++ arg = pinconf_to_config_argument(configsi); ++ ++ switch (param) { ++ case PIN_CONFIG_BIAS_DISABLE: ++ rp1_pull_config_set(pin, RP1_PUD_OFF); ++ break; ++ ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ rp1_pull_config_set(pin, RP1_PUD_DOWN); ++ break; ++ ++ case PIN_CONFIG_BIAS_PULL_UP: ++ rp1_pull_config_set(pin, RP1_PUD_UP); ++ break; ++ ++ case PIN_CONFIG_INPUT_ENABLE: ++ rp1_input_enable(pin, arg); ++ break; ++ ++ case PIN_CONFIG_OUTPUT_ENABLE: ++ rp1_output_enable(pin, arg); ++ break; ++ ++ case PIN_CONFIG_OUTPUT: ++ rp1_set_value(pin, arg); ++ rp1_set_dir(pin, RP1_DIR_OUTPUT); ++ rp1_set_fsel(pin, RP1_FSEL_GPIO); ++ break; ++ ++ case PIN_CONFIG_INPUT_SCHMITT_ENABLE: ++ rp1_pad_update(pin, RP1_PAD_SCHMITT_MASK, ++ arg ? RP1_PAD_SCHMITT_MASK : 0); ++ break; ++ ++ case PIN_CONFIG_SLEW_RATE: ++ rp1_pad_update(pin, RP1_PAD_SLEWFAST_MASK, ++ arg ? RP1_PAD_SLEWFAST_MASK : 0); ++ break; ++ ++ case PIN_CONFIG_DRIVE_STRENGTH: ++ switch (arg) { ++ case 2: ++ arg = RP1_PAD_DRIVE_2MA; ++ break; ++ case 4: ++ arg = RP1_PAD_DRIVE_4MA; ++ break; ++ case 8: ++ arg = RP1_PAD_DRIVE_8MA; ++ break; ++ case 12: ++ arg = RP1_PAD_DRIVE_12MA; ++ break; ++ default: ++ return -ENOTSUPP; ++ } ++ rp1_pad_update(pin, RP1_PAD_DRIVE_MASK, arg); ++ break; ++ ++ default: ++ return -ENOTSUPP; ++ ++ } /* switch param type */ ++ } /* for each config */ ++ ++ return 0; ++} ++ ++static int rp1_pinconf_get(struct pinctrl_dev *pctldev, unsigned offset, ++ unsigned long *config) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin_pctl(pctldev, offset); ++ enum pin_config_param param = pinconf_to_config_param(*config); ++ u32 padctrl; ++ u32 arg; ++ ++ if (!pin) ++ return -EINVAL; ++ ++ padctrl = readl(pin->pad); ++ ++ switch (param) { ++ case PIN_CONFIG_INPUT_ENABLE: ++ arg = !!(padctrl & RP1_PAD_IN_ENABLE_MASK); ++ break; ++ case PIN_CONFIG_OUTPUT_ENABLE: ++ arg = !(padctrl & RP1_PAD_OUT_DISABLE_MASK); ++ break; ++ case PIN_CONFIG_INPUT_SCHMITT_ENABLE: ++ arg = !!(padctrl & RP1_PAD_SCHMITT_MASK); ++ break; ++ case PIN_CONFIG_SLEW_RATE: ++ arg = !!(padctrl & RP1_PAD_SLEWFAST_MASK); ++ break; ++ case PIN_CONFIG_DRIVE_STRENGTH: ++ switch (padctrl & RP1_PAD_DRIVE_MASK) { ++ case RP1_PAD_DRIVE_2MA: ++ arg = 2; ++ break; ++ case RP1_PAD_DRIVE_4MA: ++ arg = 4; ++ break; ++ case RP1_PAD_DRIVE_8MA: ++ arg = 8; ++ break; ++ case RP1_PAD_DRIVE_12MA: ++ arg = 12; ++ break; ++ } ++ break; ++ case PIN_CONFIG_BIAS_DISABLE: ++ arg = ((padctrl & RP1_PAD_PULL_MASK) == (RP1_PUD_OFF << RP1_PAD_PULL_LSB)); ++ break; ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ arg = ((padctrl & RP1_PAD_PULL_MASK) == (RP1_PUD_DOWN << RP1_PAD_PULL_LSB)); ++ break; ++ ++ case PIN_CONFIG_BIAS_PULL_UP: ++ arg = ((padctrl & RP1_PAD_PULL_MASK) == (RP1_PUD_UP << RP1_PAD_PULL_LSB)); ++ break; ++ default: ++ return -ENOTSUPP; ++ } ++ ++ *config = pinconf_to_config_packed(param, arg); ++ ++ return 0; ++} ++ ++static const struct pinconf_ops rp1_pinconf_ops = { ++ .is_generic = true, ++ .pin_config_get = rp1_pinconf_get, ++ .pin_config_set = rp1_pinconf_set, ++}; ++ ++static struct pinctrl_desc rp1_pinctrl_desc = { ++ .name = MODULE_NAME, ++ .pins = rp1_gpio_pins, ++ .npins = ARRAY_SIZE(rp1_gpio_pins), ++ .pctlops = &rp1_pctl_ops, ++ .pmxops = &rp1_pmx_ops, ++ .confops = &rp1_pinconf_ops, ++ .owner = THIS_MODULE, ++}; ++ ++static struct pinctrl_gpio_range rp1_pinctrl_gpio_range = { ++ .name = MODULE_NAME, ++ .npins = RP1_NUM_GPIOS, ++}; ++ ++static const struct of_device_id rp1_pinctrl_match = { ++ { ++ .compatible = "raspberrypi,rp1-gpio", ++ .data = &rp1_pinconf_ops, ++ }, ++ {} ++}; ++ ++static inline void __iomem *devm_auto_iomap(struct platform_device *pdev, ++ unsigned int index) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ ++ if (np) ++ return devm_of_iomap(dev, np, (int)index, NULL); ++ else ++ return devm_platform_ioremap_resource(pdev, index); ++} ++ ++static int rp1_pinctrl_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct rp1_pinctrl *pc; ++ struct gpio_irq_chip *girq; ++ int err, i; ++ ++ BUILD_BUG_ON(ARRAY_SIZE(rp1_gpio_pins) != RP1_NUM_GPIOS); ++ BUILD_BUG_ON(ARRAY_SIZE(rp1_gpio_groups) != RP1_NUM_GPIOS); ++ ++ pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL); ++ if (!pc) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, pc); ++ pc->dev = dev; ++ ++ pc->gpio_base = devm_auto_iomap(pdev, 0); ++ if (IS_ERR(pc->gpio_base)) { ++ dev_err(dev, "could not get GPIO IO memory\n"); ++ return PTR_ERR(pc->gpio_base); ++ } ++ ++ pc->rio_base = devm_auto_iomap(pdev, 1); ++ if (IS_ERR(pc->rio_base)) { ++ dev_err(dev, "could not get RIO IO memory\n"); ++ return PTR_ERR(pc->rio_base); ++ } ++ ++ pc->pads_base = devm_auto_iomap(pdev, 2); ++ if (IS_ERR(pc->pads_base)) { ++ dev_err(dev, "could not get PADS IO memory\n"); ++ return PTR_ERR(pc->pads_base); ++ } ++ ++ pc->gpio_chip = rp1_gpio_chip; ++ pc->gpio_chip.parent = dev; ++ ++ for (i = 0; i < RP1_NUM_BANKS; i++) { ++ const struct rp1_iobank_desc *bank = &rp1_iobanksi; ++ int j; ++ ++ for (j = 0; j < bank->num_gpios; j++) { ++ struct rp1_pin_info *pin = ++ &pc->pinsbank->min_gpio + j; ++ ++ pin->num = bank->min_gpio + j; ++ pin->bank = i; ++ pin->offset = j; ++ ++ pin->gpio = pc->gpio_base + bank->gpio_offset + ++ j * sizeof(u32) * 2; ++ pin->inte = pc->gpio_base + bank->inte_offset; ++ pin->ints = pc->gpio_base + bank->ints_offset; ++ pin->rio = pc->rio_base + bank->rio_offset; ++ pin->pad = pc->pads_base + bank->pads_offset + ++ j * sizeof(u32); ++ } ++ ++ raw_spin_lock_init(&pc->irq_locki); ++ } ++ ++ pc->pctl_dev = devm_pinctrl_register(dev, &rp1_pinctrl_desc, pc); ++ if (IS_ERR(pc->pctl_dev)) ++ return PTR_ERR(pc->pctl_dev); ++ ++ girq = &pc->gpio_chip.irq; ++ girq->chip = &rp1_gpio_irq_chip; ++ girq->parent_handler = rp1_gpio_irq_handler; ++ girq->num_parents = RP1_NUM_BANKS; ++ girq->parents = pc->irq; ++ ++ /* ++ * Use the same handler for all groups: this is necessary ++ * since we use one gpiochip to cover all lines - the ++ * irq handler then needs to figure out which group and ++ * bank that was firing the IRQ and look up the per-group ++ * and bank data. ++ */ ++ for (i = 0; i < RP1_NUM_BANKS; i++) { ++ pc->irqi = irq_of_parse_and_map(np, i); ++ if (!pc->irqi) { ++ girq->num_parents = i; ++ break; ++ } ++ } ++ ++ girq->default_type = IRQ_TYPE_NONE; ++ girq->handler = handle_level_irq; ++ ++ err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc); ++ if (err) { ++ dev_err(dev, "could not add GPIO chip\n"); ++ return err; ++ } ++ ++ pc->gpio_range = rp1_pinctrl_gpio_range; ++ pc->gpio_range.base = pc->gpio_chip.base; ++ pc->gpio_range.gc = &pc->gpio_chip; ++ pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range); ++ ++ return 0; ++} ++ ++static struct platform_driver rp1_pinctrl_driver = { ++ .probe = rp1_pinctrl_probe, ++ .driver = { ++ .name = MODULE_NAME, ++ .of_match_table = rp1_pinctrl_match, ++ .suppress_bind_attrs = true, ++ }, ++}; ++builtin_platform_driver(rp1_pinctrl_driver); +diff --git a/drivers/platform/x86/lenovo-yogabook.c b/drivers/platform/x86/lenovo-yogabook.c +index b8d0239192cb..fd62bf746ebd 100644 +--- a/drivers/platform/x86/lenovo-yogabook.c ++++ b/drivers/platform/x86/lenovo-yogabook.c +@@ -435,7 +435,7 @@ static int yogabook_pdev_set_kbd_backlight(struct yogabook_data *data, u8 level) + .enabled = level, + }; + +- pwm_apply_state(data->kbd_bl_pwm, &state); ++ pwm_apply_might_sleep(data->kbd_bl_pwm, &state); + gpiod_set_value(data->kbd_bl_led_enable, level ? 1 : 0); + return 0; + } +diff --git a/drivers/pmdomain/bcm/bcm2835-power.c b/drivers/pmdomain/bcm/bcm2835-power.c +index d2f0233cb620..5812f2a355d4 100644 +--- a/drivers/pmdomain/bcm/bcm2835-power.c ++++ b/drivers/pmdomain/bcm/bcm2835-power.c +@@ -79,6 +79,7 @@ + #define PM_IMAGE 0x108 + #define PM_GRAFX 0x10c + #define PM_PROC 0x110 ++#define PM_GRAFX_2712 0x304 + #define PM_ENAB BIT(12) + #define PM_ISPRSTN BIT(8) + #define PM_H264RSTN BIT(7) +@@ -381,6 +382,9 @@ static int bcm2835_power_pd_power_on(struct generic_pm_domain *domain) + return bcm2835_power_power_on(pd, PM_GRAFX); + + case BCM2835_POWER_DOMAIN_GRAFX_V3D: ++ if (!power->asb) ++ return bcm2835_asb_power_on(pd, PM_GRAFX_2712, ++ 0, 0, PM_V3DRSTN); + return bcm2835_asb_power_on(pd, PM_GRAFX, + ASB_V3D_M_CTRL, ASB_V3D_S_CTRL, + PM_V3DRSTN); +@@ -447,6 +451,9 @@ static int bcm2835_power_pd_power_off(struct generic_pm_domain *domain) + return bcm2835_power_power_off(pd, PM_GRAFX); + + case BCM2835_POWER_DOMAIN_GRAFX_V3D: ++ if (!power->asb) ++ return bcm2835_asb_power_off(pd, PM_GRAFX_2712, ++ 0, 0, PM_V3DRSTN); + return bcm2835_asb_power_off(pd, PM_GRAFX, + ASB_V3D_M_CTRL, ASB_V3D_S_CTRL, + PM_V3DRSTN); +@@ -642,19 +649,21 @@ static int bcm2835_power_probe(struct platform_device *pdev) + power->asb = pm->asb; + power->rpivid_asb = pm->rpivid_asb; + +- id = readl(power->asb + ASB_AXI_BRDG_ID); +- if (id != BCM2835_BRDG_ID /* "BRDG" */) { +- dev_err(dev, "ASB register ID returned 0x%08x\n", id); +- return -ENODEV; +- } +- +- if (power->rpivid_asb) { +- id = readl(power->rpivid_asb + ASB_AXI_BRDG_ID); ++ if (power->asb) { ++ id = readl(power->asb + ASB_AXI_BRDG_ID); + if (id != BCM2835_BRDG_ID /* "BRDG" */) { +- dev_err(dev, "RPiVid ASB register ID returned 0x%08x\n", +- id); ++ dev_err(dev, "ASB register ID returned 0x%08x\n", id); + return -ENODEV; + } ++ ++ if (power->rpivid_asb) { ++ id = readl(power->rpivid_asb + ASB_AXI_BRDG_ID); ++ if (id != BCM2835_BRDG_ID /* "BRDG" */) { ++ dev_err(dev, "RPiVid ASB register ID returned 0x%08x\n", ++ id); ++ return -ENODEV; ++ } ++ } + } + + power->pd_xlate.domains = devm_kcalloc(dev, diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c -index 1c5af2fef142..81e7acb8acb5 100644 +index b28f24da1b3c..1c900cd97671 100644 --- a/drivers/power/reset/gpio-poweroff.c +++ b/drivers/power/reset/gpio-poweroff.c -@@ -24,6 +24,7 @@ static struct gpio_desc *reset_gpio; +@@ -11,6 +11,7 @@ + #include <linux/init.h> + #include <linux/delay.h> + #include <linux/platform_device.h> ++#include <linux/of.h> + #include <linux/property.h> + #include <linux/gpio/consumer.h> + #include <linux/mod_devicetable.h> +@@ -25,6 +26,7 @@ static struct gpio_desc *reset_gpio; static u32 timeout = DEFAULT_TIMEOUT_MS; static u32 active_delay = 100; static u32 inactive_delay = 100; @@ -98306,7 +151444,7 @@ static void gpio_poweroff_do_poweroff(void) { -@@ -43,6 +44,9 @@ static void gpio_poweroff_do_poweroff(void) +@@ -44,6 +46,9 @@ static void gpio_poweroff_do_poweroff(void) /* give it some time */ mdelay(timeout); @@ -98316,7 +151454,7 @@ WARN_ON(1); } -@@ -50,9 +54,12 @@ static int gpio_poweroff_probe(struct platform_device *pdev) +@@ -51,9 +56,12 @@ static int gpio_poweroff_probe(struct platform_device *pdev) { bool input = false; enum gpiod_flags flags; @@ -98330,7 +151468,7 @@ dev_err(&pdev->dev, "%s: pm_power_off function already registered\n", __func__); -@@ -74,6 +81,13 @@ static int gpio_poweroff_probe(struct platform_device *pdev) +@@ -75,6 +83,13 @@ static int gpio_poweroff_probe(struct platform_device *pdev) if (IS_ERR(reset_gpio)) return PTR_ERR(reset_gpio); @@ -98344,7 +151482,7 @@ pm_power_off = &gpio_poweroff_do_poweroff; return 0; } -@@ -81,7 +95,9 @@ static int gpio_poweroff_probe(struct platform_device *pdev) +@@ -82,7 +97,9 @@ static int gpio_poweroff_probe(struct platform_device *pdev) static int gpio_poweroff_remove(struct platform_device *pdev) { if (pm_power_off == &gpio_poweroff_do_poweroff) @@ -98356,10 +151494,10 @@ return 0; } diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig -index 0aa46b451017..dadc86687054 100644 +index a61bb1283e19..641e1c0d6029 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig -@@ -28,6 +28,12 @@ config POWER_SUPPLY_HWMON +@@ -28,6 +28,13 @@ config POWER_SUPPLY_HWMON Say 'Y' here if you want power supplies to have hwmon sysfs interface too. @@ -98369,11 +151507,12 @@ + 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" ++ + config APM_POWER + tristate "APM emulation for class batteries" + depends on APM_EMULATION diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile -index dd4b86318cd9..f881637da4f7 100644 +index a8a9fa6de1e9..d7d78b7a19a2 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_POWER_SUPPLY) += power_supply.o @@ -98381,15 +151520,15 @@ 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 + obj-$(CONFIG_IP5XXX_POWER) += ip5xxx_power.o diff --git a/drivers/power/supply/rpi_poe_power.c b/drivers/power/supply/rpi_poe_power.c new file mode 100644 -index 000000000000..0c96b2c1e8ab +index 000000000000..e96f98c39f0e --- /dev/null +++ b/drivers/power/supply/rpi_poe_power.c -@@ -0,0 +1,227 @@ +@@ -0,0 +1,243 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rpi-poe-power.c - Raspberry Pi PoE+ HAT power supply driver. @@ -98404,10 +151543,13 @@ +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/power_supply.h> ++#include <linux/regmap.h> +#include <soc/bcm2835/raspberrypi-firmware.h> + -+#define RPI_POE_ADC_REG 0x2 -+#define RPI_POE_FLAG_REG 0x4 ++#define RPI_POE_FW_BASE_REG 0x2 ++ ++#define RPI_POE_ADC_REG 0x0 ++#define RPI_POE_FLAG_REG 0x2 + +#define RPI_POE_FLAG_AT BIT(0) +#define RPI_POE_FLAG_OC BIT(1) @@ -98418,8 +151560,12 @@ +#define DRVNAME "rpi-poe-power-supply" + +struct rpi_poe_power_supply_ctx { -+ struct power_supply *supply; + struct rpi_firmware *fw; ++ ++ struct regmap *regmap; ++ u32 offset; ++ ++ struct power_supply *supply; +}; + +struct fw_tag_data_s { @@ -98428,40 +151574,51 @@ + u32 ret; +}; + -+static int write_reg(struct rpi_firmware *fw, u32 reg, u32 *val) ++static int write_reg(struct rpi_poe_power_supply_ctx *ctx, u32 reg, u32 *val) +{ + struct fw_tag_data_s fw_tag_data = { -+ .reg = reg, ++ .reg = reg + RPI_POE_FW_BASE_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; ++ if (ctx->fw) { ++ ret = rpi_firmware_property(ctx->fw, RPI_FIRMWARE_SET_POE_HAT_VAL, ++ &fw_tag_data, sizeof(fw_tag_data)); ++ if (!ret && fw_tag_data.ret) ++ ret = -EIO; ++ } else { ++ ret = regmap_write(ctx->regmap, ctx->offset + reg, *val); ++ } ++ ++ return ret; +} + -+static int read_reg(struct rpi_firmware *fw, u32 reg, u32 *val) ++static int read_reg(struct rpi_poe_power_supply_ctx *ctx, u32 reg, u32 *val) +{ + struct fw_tag_data_s fw_tag_data = { -+ .reg = reg, ++ .reg = reg + RPI_POE_FW_BASE_REG, + .val = *val + }; ++ u32 value; + 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; ++ if (ctx->fw) { ++ ret = rpi_firmware_property(ctx->fw, RPI_FIRMWARE_GET_POE_HAT_VAL, ++ &fw_tag_data, sizeof(fw_tag_data)); ++ if (!ret && fw_tag_data.ret) ++ ret = -EIO; ++ *val = fw_tag_data.val; ++ } else { ++ ret = regmap_read(ctx->regmap, ctx->offset + reg, &value); ++ if (!ret) { ++ *val = value; ++ ret = regmap_read(ctx->regmap, ctx->offset + reg + 1, &value); ++ *val |= value << 8; ++ } ++ } + -+ *val = fw_tag_data.val; -+ return 0; ++ return ret; +} + +static int rpi_poe_power_supply_get_property(struct power_supply *psy, @@ -98474,14 +151631,14 @@ + + switch (psp) { + case POWER_SUPPLY_PROP_HEALTH: -+ ret = read_reg(ctx->fw, RPI_POE_FLAG_REG, &val); ++ ret = read_reg(ctx, 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); ++ ret = write_reg(ctx, RPI_POE_FLAG_REG, &val); + if (ret) + return ret; + return 0; @@ -98491,24 +151648,15 @@ + return 0; + + case POWER_SUPPLY_PROP_ONLINE: -+ ret = read_reg(ctx->fw, RPI_POE_ADC_REG, &val); ++ ret = read_reg(ctx, 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); ++ ret = read_reg(ctx, RPI_POE_ADC_REG, &val); + if (ret) + return ret; + val = (val * 3300)/9821; @@ -98516,15 +151664,14 @@ + return 0; + + case POWER_SUPPLY_PROP_CURRENT_MAX: -+ ret = read_reg(ctx->fw, RPI_POE_FLAG_REG, &val); ++ ret = read_reg(ctx, RPI_POE_FLAG_REG, &val); + if (ret) + return ret; + -+ if (val & RPI_POE_FLAG_AT) { ++ if (val & RPI_POE_FLAG_AT) + r_val->intval = RPI_POE_CURRENT_AT_MAX; -+ return 0; -+ } -+ r_val->intval = RPI_POE_CURRENT_AF_MAX; ++ else ++ r_val->intval = RPI_POE_CURRENT_AF_MAX; + return 0; + + default: @@ -98537,7 +151684,6 @@ +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, +}; @@ -98560,29 +151706,38 @@ + 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; ++ if (pdev->dev.parent) ++ ctx->regmap = dev_get_regmap(pdev->dev.parent, NULL); ++ ++ if (ctx->regmap) { ++ if (device_property_read_u32(&pdev->dev, "reg", &ctx->offset)) ++ return -EINVAL; ++ } else { ++ 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->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; @@ -98618,237 +151773,931 @@ +MODULE_DESCRIPTION("Raspberry Pi PoE+ HAT power supply driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c -index e0de1df2ede0..ee7d8f4e7f2e 100644 +index 2f4b11b4dfcd..b10b43538542 100644 --- a/drivers/pps/clients/pps-gpio.c +++ b/drivers/pps/clients/pps-gpio.c -@@ -145,6 +145,8 @@ static int pps_gpio_setup(struct platform_device *pdev) +@@ -113,6 +113,9 @@ static int pps_gpio_setup(struct device *dev) + data->assert_falling_edge = + device_property_read_bool(dev, "assert-falling-edge"); + ++ data->capture_clear = ++ device_property_read_bool(dev, "capture-clear"); ++ + data->echo_pin = devm_gpiod_get_optional(dev, "echo", GPIOD_OUT_LOW); + if (IS_ERR(data->echo_pin)) + return dev_err_probe(dev, PTR_ERR(data->echo_pin), +diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c +index 5d19baae6a38..0675c8a2e560 100644 +--- a/drivers/pps/pps.c ++++ b/drivers/pps/pps.c +@@ -249,12 +249,13 @@ static long pps_cdev_ioctl(struct file *file, + static long pps_cdev_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) + { +- struct pps_device *pps = file->private_data; +- void __user *uarg = (void __user *) arg; + + cmd = _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(void *)); + ++#ifdef CONFIG_X86_64 + if (cmd == PPS_FETCH) { ++ struct pps_device *pps = file->private_data; ++ void __user *uarg = (void __user *) arg; + struct pps_fdata_compat compat; + struct pps_fdata fdata; + int err; +@@ -289,6 +290,7 @@ static long pps_cdev_compat_ioctl(struct file *file, + return copy_to_user(uarg, &compat, + sizeof(struct pps_fdata_compat)) ? -EFAULT : 0; + } ++#endif - 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; + return pps_cdev_ioctl(file, cmd, arg); + } +diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig +index 8ebcddf91f7b..1a6cecfa9ee3 100644 +--- a/drivers/pwm/Kconfig ++++ b/drivers/pwm/Kconfig +@@ -473,6 +473,15 @@ config PWM_RASPBERRYPI_POE + Enable Raspberry Pi firmware controller PWM bus used to control the + official RPI PoE hat + ++config PWM_RP1 ++ tristate "RP1 PWM support" ++ depends on ARCH_BCM2835 || COMPILE_TEST ++ help ++ PWM framework driver for Raspberry Pi RP1 controller ++ ++ To compile this driver as a module, choose M here: the module ++ will be called pwm-rp1. ++ + config PWM_RCAR + tristate "Renesas R-Car PWM support" + depends on ARCH_RENESAS || COMPILE_TEST +diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile +index c822389c2a24..920797b3ba8f 100644 +--- a/drivers/pwm/Makefile ++++ b/drivers/pwm/Makefile +@@ -43,6 +43,7 @@ obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o + obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o + obj-$(CONFIG_PWM_PXA) += pwm-pxa.o + obj-$(CONFIG_PWM_RASPBERRYPI_POE) += pwm-raspberrypi-poe.o ++obj-$(CONFIG_PWM_RP1) += pwm-rp1.o + obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o + obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o + obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o +diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c +index 0c8c63239adb..65331cd64da1 100644 +--- a/drivers/pwm/core.c ++++ b/drivers/pwm/core.c +@@ -382,8 +382,8 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, + } + EXPORT_SYMBOL_GPL(pwm_request_from_chip); + +-static void pwm_apply_state_debug(struct pwm_device *pwm, +- const struct pwm_state *state) ++static void pwm_apply_debug(struct pwm_device *pwm, ++ const struct pwm_state *state) + { + struct pwm_state *last = &pwm->last; + struct pwm_chip *chip = pwm->chip; +@@ -489,24 +489,15 @@ static void pwm_apply_state_debug(struct pwm_device *pwm, } -diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c -index ee46bfbf5eee..e3decc419814 100644 ---- a/drivers/regulator/rpi-panel-attiny-regulator.c -+++ b/drivers/regulator/rpi-panel-attiny-regulator.c -@@ -8,6 +8,7 @@ - #include <linux/backlight.h> - #include <linux/err.h> - #include <linux/gpio.h> -+#include <linux/gpio/driver.h> - #include <linux/i2c.h> - #include <linux/init.h> - #include <linux/interrupt.h> -@@ -21,63 +22,130 @@ - /* I2C registers of the Atmel microcontroller. */ - #define REG_ID 0x80 - #define REG_PORTA 0x81 --#define REG_PORTA_HF BIT(2) --#define REG_PORTA_VF BIT(3) - #define REG_PORTB 0x82 -+#define REG_PORTC 0x83 - #define REG_POWERON 0x85 - #define REG_PWM 0x86 -+#define REG_ADDR_L 0x8c -+#define REG_ADDR_H 0x8d -+#define REG_WRITE_DATA_H 0x90 -+#define REG_WRITE_DATA_L 0x91 -+ -+#define PA_LCD_DITHB BIT(0) -+#define PA_LCD_MODE BIT(1) -+#define PA_LCD_LR BIT(2) -+#define PA_LCD_UD BIT(3) -+ -+#define PB_BRIDGE_PWRDNX_N BIT(0) -+#define PB_LCD_VCC_N BIT(1) -+#define PB_LCD_MAIN BIT(7) -+ -+#define PC_LED_EN BIT(0) -+#define PC_RST_TP_N BIT(1) -+#define PC_RST_LCD_N BIT(2) -+#define PC_RST_BRIDGE_N BIT(3) -+ -+enum gpio_signals { -+ RST_BRIDGE_N, /* TC358762 bridge reset */ -+ RST_TP_N, /* Touch controller reset */ -+ NUM_GPIO -+}; + /** +- * pwm_apply_state() - atomically apply a new state to a PWM device ++ * __pwm_apply() - atomically apply a new state to a PWM device + * @pwm: PWM device + * @state: new state to apply + */ +-int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state) ++static int __pwm_apply(struct pwm_device *pwm, const struct pwm_state *state) + { + struct pwm_chip *chip; + int err; + +- /* +- * Some lowlevel driver's implementations of .apply() make use of +- * mutexes, also with some drivers only returning when the new +- * configuration is active calling pwm_apply_state() from atomic context +- * is a bad idea. So make it explicit that calling this function might +- * sleep. +- */ +- might_sleep(); +- + if (!pwm || !state || !state->period || + state->duty_cycle > state->period) + return -EINVAL; +@@ -531,11 +522,60 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state) + * only do this after pwm->state was applied as some + * implementations of .get_state depend on this + */ +- pwm_apply_state_debug(pwm, state); ++ pwm_apply_debug(pwm, state); + + return 0; + } +-EXPORT_SYMBOL_GPL(pwm_apply_state); + -+struct gpio_signal_mappings { -+ unsigned int reg; -+ unsigned int mask; -+}; ++/** ++ * pwm_apply_might_sleep() - atomically apply a new state to a PWM device ++ * Cannot be used in atomic context. ++ * @pwm: PWM device ++ * @state: new state to apply ++ */ ++int pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state) ++{ ++ int err; + -+static const struct gpio_signal_mappings mappingsNUM_GPIO = { -+ RST_BRIDGE_N = { REG_PORTC, PC_RST_BRIDGE_N | PC_RST_LCD_N }, -+ RST_TP_N = { REG_PORTC, PC_RST_TP_N }, -+}; ++ /* ++ * Some lowlevel driver's implementations of .apply() make use of ++ * mutexes, also with some drivers only returning when the new ++ * configuration is active calling pwm_apply_might_sleep() from atomic context ++ * is a bad idea. So make it explicit that calling this function might ++ * sleep. ++ */ ++ might_sleep(); + -+struct attiny_lcd { -+ /* lock to serialise overall accesses to the Atmel */ -+ struct mutex lock; -+ struct regmap *regmap; -+ bool gpio_statesNUM_GPIO; -+ u8 port_states3; ++ if (IS_ENABLED(CONFIG_PWM_DEBUG) && pwm->chip->atomic) { ++ /* ++ * Catch any drivers that have been marked as atomic but ++ * that will sleep anyway. ++ */ ++ non_block_start(); ++ err = __pwm_apply(pwm, state); ++ non_block_end(); ++ } else { ++ err = __pwm_apply(pwm, state); ++ } + -+ struct gpio_chip gc; -+}; ++ return err; ++} ++EXPORT_SYMBOL_GPL(pwm_apply_might_sleep); ++ ++/** ++ * pwm_apply_atomic() - apply a new state to a PWM device from atomic context ++ * Not all PWM devices support this function, check with pwm_might_sleep(). ++ * @pwm: PWM device ++ * @state: new state to apply ++ */ ++int pwm_apply_atomic(struct pwm_device *pwm, const struct pwm_state *state) ++{ ++ WARN_ONCE(!pwm->chip->atomic, ++ "sleeping PWM driver used in atomic context\n"); ++ ++ return __pwm_apply(pwm, state); ++} ++EXPORT_SYMBOL_GPL(pwm_apply_atomic); - static const struct regmap_config attiny_regmap_config = { - .reg_bits = 8, - .val_bits = 8, -- .max_register = REG_PWM, -+ .disable_locking = 1, -+ .max_register = REG_WRITE_DATA_L, - .cache_type = REGCACHE_NONE, + /** + * pwm_capture() - capture and report a PWM signal +@@ -593,7 +633,7 @@ int pwm_adjust_config(struct pwm_device *pwm) + state.period = pargs.period; + state.polarity = pargs.polarity; + +- return pwm_apply_state(pwm, &state); ++ return pwm_apply_might_sleep(pwm, &state); + } + + /* +@@ -616,7 +656,7 @@ int pwm_adjust_config(struct pwm_device *pwm) + state.duty_cycle = state.period - state.duty_cycle; + } + +- return pwm_apply_state(pwm, &state); ++ return pwm_apply_might_sleep(pwm, &state); + } + EXPORT_SYMBOL_GPL(pwm_adjust_config); + +diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c +index bdfc2a5ec0d6..70e05ccd40ba 100644 +--- a/drivers/pwm/pwm-bcm2835.c ++++ b/drivers/pwm/pwm-bcm2835.c +@@ -28,6 +28,7 @@ struct bcm2835_pwm { + struct device *dev; + void __iomem *base; + struct clk *clk; ++ unsigned long rate; + }; + + static inline struct bcm2835_pwm *to_bcm2835_pwm(struct pwm_chip *chip) +@@ -63,17 +64,11 @@ static int bcm2835_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + { + + struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); +- unsigned long rate = clk_get_rate(pc->clk); + unsigned long long period_cycles; + u64 max_period; + + u32 val; + +- if (!rate) { +- dev_err(pc->dev, "failed to get clock rate\n"); +- return -EINVAL; +- } +- + /* + * period_cycles must be a 32 bit value, so period * rate / NSEC_PER_SEC + * must be <= U32_MAX. As U32_MAX * NSEC_PER_SEC < U64_MAX the +@@ -88,13 +83,13 @@ static int bcm2835_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + * <=> period < ((U32_MAX * NSEC_PER_SEC + NSEC_PER_SEC/2) / rate + * <=> period <= ceil((U32_MAX * NSEC_PER_SEC + NSEC_PER_SEC/2) / rate) - 1 + */ +- max_period = DIV_ROUND_UP_ULL((u64)U32_MAX * NSEC_PER_SEC + NSEC_PER_SEC / 2, rate) - 1; ++ max_period = DIV_ROUND_UP_ULL((u64)U32_MAX * NSEC_PER_SEC + NSEC_PER_SEC / 2, pc->rate) - 1; + + if (state->period > max_period) + return -EINVAL; + + /* set period */ +- period_cycles = DIV_ROUND_CLOSEST_ULL(state->period * rate, NSEC_PER_SEC); ++ period_cycles = DIV_ROUND_CLOSEST_ULL(state->period * pc->rate, NSEC_PER_SEC); + + /* don't accept a period that is too small */ + if (period_cycles < PERIOD_MIN) +@@ -103,7 +98,7 @@ static int bcm2835_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + writel(period_cycles, pc->base + PERIOD(pwm->hwpwm)); + + /* set duty cycle */ +- val = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * rate, NSEC_PER_SEC); ++ val = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * pc->rate, NSEC_PER_SEC); + writel(val, pc->base + DUTY(pwm->hwpwm)); + + /* set polarity */ +@@ -132,6 +127,13 @@ static const struct pwm_ops bcm2835_pwm_ops = { + .owner = THIS_MODULE, }; -+static int attiny_set_port_state(struct attiny_lcd *state, int reg, u8 val) ++static void devm_clk_rate_exclusive_put(void *data) +{ -+ state->port_statesreg - REG_PORTA = val; -+ return regmap_write(state->regmap, reg, val); -+}; ++ struct clk *clk = data; + -+static u8 attiny_get_port_state(struct attiny_lcd *state, int reg) -+{ -+ return state->port_statesreg - REG_PORTA; -+}; ++ clk_rate_exclusive_put(clk); ++} + - static int attiny_lcd_power_enable(struct regulator_dev *rdev) + static int bcm2835_pwm_probe(struct platform_device *pdev) { -- unsigned int data; -+ struct attiny_lcd *state = rdev_get_drvdata(rdev); + struct bcm2835_pwm *pc; +@@ -147,39 +149,39 @@ static int bcm2835_pwm_probe(struct platform_device *pdev) + if (IS_ERR(pc->base)) + return PTR_ERR(pc->base); -- regmap_write(rdev->regmap, REG_POWERON, 1); -- /* Wait for nPWRDWN to go low to indicate poweron is done. */ -- regmap_read_poll_timeout(rdev->regmap, REG_PORTB, data, -- data & BIT(0), 10, 1000000); -+ mutex_lock(&state->lock); -+ -+ /* Ensure bridge, and tp stay in reset */ -+ attiny_set_port_state(state, REG_PORTC, 0); -+ usleep_range(5000, 10000); - - /* Default to the same orientation as the closed source - * firmware used for the panel. Runtime rotation - * configuration will be supported using VC4's plane - * orientation bits. - */ -- regmap_write(rdev->regmap, REG_PORTA, BIT(2)); -+ attiny_set_port_state(state, REG_PORTA, PA_LCD_LR); -+ usleep_range(5000, 10000); -+ /* Main regulator on, and power to the panel (LCD_VCC_N) */ -+ attiny_set_port_state(state, REG_PORTB, PB_LCD_MAIN); -+ usleep_range(5000, 10000); -+ /* Bring controllers out of reset */ -+ attiny_set_port_state(state, REG_PORTC, PC_LED_EN); +- pc->clk = devm_clk_get(&pdev->dev, NULL); ++ pc->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(pc->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk), + "clock not found\n"); + +- ret = clk_prepare_enable(pc->clk); ++ ret = clk_rate_exclusive_get(pc->clk); + if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "fail to get exclusive rate\n"); + -+ msleep(80); ++ ret = devm_add_action_or_reset(&pdev->dev, devm_clk_rate_exclusive_put, ++ pc->clk); ++ if (ret) { ++ clk_rate_exclusive_put(pc->clk); + return ret; ++ } + -+ mutex_unlock(&state->lock); ++ pc->rate = clk_get_rate(pc->clk); ++ if (!pc->rate) ++ return dev_err_probe(&pdev->dev, -EINVAL, ++ "failed to get clock rate\n"); + + pc->chip.dev = &pdev->dev; + pc->chip.ops = &bcm2835_pwm_ops; ++ pc->chip.atomic = true; + pc->chip.npwm = 2; + +- platform_set_drvdata(pdev, pc); +- +- ret = pwmchip_add(&pc->chip); ++ ret = devm_pwmchip_add(&pdev->dev, &pc->chip); + if (ret < 0) +- goto add_fail; ++ return dev_err_probe(&pdev->dev, ret, ++ "failed to add pwmchip\n"); return 0; +- +-add_fail: +- clk_disable_unprepare(pc->clk); +- return ret; +-} +- +-static void bcm2835_pwm_remove(struct platform_device *pdev) +-{ +- struct bcm2835_pwm *pc = platform_get_drvdata(pdev); +- +- pwmchip_remove(&pc->chip); +- +- clk_disable_unprepare(pc->clk); } - static int attiny_lcd_power_disable(struct regulator_dev *rdev) - { -+ struct attiny_lcd *state = rdev_get_drvdata(rdev); -+ -+ mutex_lock(&state->lock); -+ - regmap_write(rdev->regmap, REG_PWM, 0); -- regmap_write(rdev->regmap, REG_POWERON, 0); -- udelay(1); -+ usleep_range(5000, 10000); -+ -+ attiny_set_port_state(state, REG_PORTA, 0); -+ usleep_range(5000, 10000); -+ attiny_set_port_state(state, REG_PORTB, PB_LCD_VCC_N); -+ usleep_range(5000, 10000); -+ attiny_set_port_state(state, REG_PORTC, 0); -+ msleep(30); + static const struct of_device_id bcm2835_pwm_of_match = { +@@ -194,7 +196,6 @@ static struct platform_driver bcm2835_pwm_driver = { + .of_match_table = bcm2835_pwm_of_match, + }, + .probe = bcm2835_pwm_probe, +- .remove_new = bcm2835_pwm_remove, + }; + module_platform_driver(bcm2835_pwm_driver); + +diff --git a/drivers/pwm/pwm-raspberrypi-poe.c b/drivers/pwm/pwm-raspberrypi-poe.c +index 2939b71a7ba7..4cf3d6fd5011 100644 +--- a/drivers/pwm/pwm-raspberrypi-poe.c ++++ b/drivers/pwm/pwm-raspberrypi-poe.c +@@ -16,6 +16,7 @@ + #include <linux/of.h> + #include <linux/platform_device.h> + #include <linux/pwm.h> ++#include <linux/regmap.h> + + #include <soc/bcm2835/raspberrypi-firmware.h> + #include <dt-bindings/pwm/raspberrypi,firmware-poe-pwm.h> +@@ -27,6 +28,10 @@ + + struct raspberrypi_pwm { + struct rpi_firmware *firmware; + -+ mutex_unlock(&state->lock); ++ struct regmap *regmap; ++ u32 offset; + - return 0; + struct pwm_chip chip; + unsigned int duty_cycle; + }; +@@ -43,7 +48,7 @@ struct raspberrypi_pwm *raspberrypi_pwm_from_chip(struct pwm_chip *chip) + return container_of(chip, struct raspberrypi_pwm, chip); } - static int attiny_lcd_power_is_enabled(struct regulator_dev *rdev) +-static int raspberrypi_pwm_set_property(struct rpi_firmware *firmware, ++static int raspberrypi_pwm_set_property(struct raspberrypi_pwm *pwm, + u32 reg, u32 val) { -- unsigned int data; -- int ret; -- -- ret = regmap_read(rdev->regmap, REG_POWERON, &data); -- if (ret < 0) + struct raspberrypi_pwm_prop msg = { +@@ -52,17 +57,19 @@ static int raspberrypi_pwm_set_property(struct rpi_firmware *firmware, + }; + int ret; + +- ret = rpi_firmware_property(firmware, RPI_FIRMWARE_SET_POE_HAT_VAL, +- &msg, sizeof(msg)); +- if (ret) - return ret; -- -- if (!(data & BIT(0))) -- return 0; -- -- ret = regmap_read(rdev->regmap, REG_PORTB, &data); -- if (ret < 0) +- if (msg.ret) +- return -EIO; ++ if (pwm->firmware) { ++ ret = rpi_firmware_property(pwm->firmware, RPI_FIRMWARE_SET_POE_HAT_VAL, ++ &msg, sizeof(msg)); ++ if (!ret && msg.ret) ++ ret = -EIO; ++ } else { ++ ret = regmap_write(pwm->regmap, pwm->offset + reg, val); ++ } + +- return 0; ++ return ret; + } + +-static int raspberrypi_pwm_get_property(struct rpi_firmware *firmware, ++static int raspberrypi_pwm_get_property(struct raspberrypi_pwm *pwm, + u32 reg, u32 *val) + { + struct raspberrypi_pwm_prop msg = { +@@ -70,16 +77,17 @@ static int raspberrypi_pwm_get_property(struct rpi_firmware *firmware, + }; + int ret; + +- ret = rpi_firmware_property(firmware, RPI_FIRMWARE_GET_POE_HAT_VAL, +- &msg, sizeof(msg)); +- if (ret) - return ret; -+ struct attiny_lcd *state = rdev_get_drvdata(rdev); +- if (msg.ret) +- return -EIO; +- +- *val = le32_to_cpu(msg.val); ++ if (pwm->firmware) { ++ ret = rpi_firmware_property(pwm->firmware, RPI_FIRMWARE_GET_POE_HAT_VAL, ++ &msg, sizeof(msg)); ++ if (!ret && msg.ret) ++ ret = -EIO; ++ *val = le32_to_cpu(msg.val); ++ } else { ++ ret = regmap_read(pwm->regmap, pwm->offset + reg, val); ++ } -- return data & BIT(0); -+ return state->port_statesREG_PORTC - REG_PORTA & PC_RST_BRIDGE_N; +- return 0; ++ return ret; } - static const struct regulator_init_data attiny_regulator_default = { -@@ -101,33 +169,104 @@ static const struct regulator_desc attiny_regulator = { + static int raspberrypi_pwm_get_state(struct pwm_chip *chip, +@@ -119,7 +127,7 @@ static int raspberrypi_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + if (duty_cycle == rpipwm->duty_cycle) + return 0; - static int attiny_update_status(struct backlight_device *bl) - { -- struct regmap *regmap = bl_get_data(bl); -+ struct attiny_lcd *state = bl_get_data(bl); -+ struct regmap *regmap = state->regmap; - int brightness = bl->props.brightness; -+ int ret, i; +- ret = raspberrypi_pwm_set_property(rpipwm->firmware, RPI_PWM_CUR_DUTY_REG, ++ ret = raspberrypi_pwm_set_property(rpipwm, RPI_PWM_CUR_DUTY_REG, + duty_cycle); + if (ret) { + dev_err(chip->dev, "Failed to set duty cycle: %pe\n", +@@ -146,28 +154,34 @@ static int raspberrypi_pwm_probe(struct platform_device *pdev) + struct raspberrypi_pwm *rpipwm; + int ret; + +- firmware_node = of_get_parent(dev->of_node); +- if (!firmware_node) { +- dev_err(dev, "Missing firmware node\n"); +- return -ENOENT; +- } +- +- firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node); +- of_node_put(firmware_node); +- if (!firmware) +- return dev_err_probe(dev, -EPROBE_DEFER, +- "Failed to get firmware handle\n"); +- + rpipwm = devm_kzalloc(&pdev->dev, sizeof(*rpipwm), GFP_KERNEL); + if (!rpipwm) + return -ENOMEM; + +- rpipwm->firmware = firmware; ++ if (pdev->dev.parent) ++ rpipwm->regmap = dev_get_regmap(pdev->dev.parent, NULL); + -+ mutex_lock(&state->lock); ++ if (rpipwm->regmap) { ++ ret = device_property_read_u32(&pdev->dev, "reg", &rpipwm->offset); ++ if (ret) ++ return -EINVAL; ++ } else { ++ firmware_node = of_get_parent(dev->of_node); ++ ++ firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node); ++ of_node_put(firmware_node); ++ if (!firmware) ++ return dev_err_probe(dev, -EPROBE_DEFER, ++ "Failed to get firmware handle\n"); ++ ++ rpipwm->firmware = firmware; ++ } ++ + rpipwm->chip.dev = dev; + rpipwm->chip.ops = &raspberrypi_pwm_ops; + rpipwm->chip.npwm = RASPBERRYPI_FIRMWARE_PWM_NUM; - if (bl->props.power != FB_BLANK_UNBLANK || - bl->props.fb_blank != FB_BLANK_UNBLANK) - brightness = 0; +- ret = raspberrypi_pwm_get_property(rpipwm->firmware, RPI_PWM_CUR_DUTY_REG, ++ ret = raspberrypi_pwm_get_property(rpipwm, RPI_PWM_CUR_DUTY_REG, + &rpipwm->duty_cycle); + if (ret) { + dev_err(dev, "Failed to get duty cycle: %pe\n", ERR_PTR(ret)); +@@ -179,6 +193,7 @@ static int raspberrypi_pwm_probe(struct platform_device *pdev) -- return regmap_write(regmap, REG_PWM, brightness); --} -- --static int attiny_get_brightness(struct backlight_device *bl) --{ -- struct regmap *regmap = bl_get_data(bl); -- int ret, brightness; -+ for (i = 0; i < 10; i++) { -+ ret = regmap_write(regmap, REG_PWM, brightness); -+ if (!ret) -+ break; + static const struct of_device_id raspberrypi_pwm_of_match = { + { .compatible = "raspberrypi,firmware-poe-pwm", }, ++ { .compatible = "raspberrypi,poe-pwm", }, + { } + }; + MODULE_DEVICE_TABLE(of, raspberrypi_pwm_of_match); +diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c +index d7311614c846..96797a33d8c6 100644 +--- a/drivers/pwm/pwm-renesas-tpu.c ++++ b/drivers/pwm/pwm-renesas-tpu.c +@@ -11,7 +11,6 @@ + #include <linux/init.h> + #include <linux/ioport.h> + #include <linux/module.h> +-#include <linux/mutex.h> + #include <linux/of.h> + #include <linux/platform_device.h> + #include <linux/pm_runtime.h> +diff --git a/drivers/pwm/pwm-rp1.c b/drivers/pwm/pwm-rp1.c +new file mode 100644 +index 000000000000..40ce14412817 +--- /dev/null ++++ b/drivers/pwm/pwm-rp1.c +@@ -0,0 +1,203 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * pwm-rp1.c ++ * ++ * Raspberry Pi RP1 PWM. ++ * ++ * Copyright © 2023 Raspberry Pi Ltd. ++ * ++ * Author: Naushir Patuck (naush@raspberrypi.com) ++ * ++ * Based on the pwm-bcm2835 driver by: ++ * Bart Tanghe <bart.tanghe@thomasmore.be> ++ */ ++ ++#include <linux/bitops.h> ++#include <linux/clk.h> ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/platform_device.h> ++#include <linux/pwm.h> ++ ++#define PWM_GLOBAL_CTRL 0x000 ++#define PWM_CHANNEL_CTRL(x) (0x014 + ((x) * 16)) ++#define PWM_RANGE(x) (0x018 + ((x) * 16)) ++#define PWM_DUTY(x) (0x020 + ((x) * 16)) ++ ++/* 8:FIFO_POP_MASK + 0:Trailing edge M/S modulation */ ++#define PWM_CHANNEL_DEFAULT (BIT(8) + BIT(0)) ++#define PWM_CHANNEL_ENABLE(x) BIT(x) ++#define PWM_POLARITY BIT(3) ++#define SET_UPDATE BIT(31) ++#define PWM_MODE_MASK GENMASK(1, 0) ++ ++struct rp1_pwm { ++ struct pwm_chip chip; ++ struct device *dev; ++ void __iomem *base; ++ struct clk *clk; ++}; ++ ++static inline struct rp1_pwm *to_rp1_pwm(struct pwm_chip *chip) ++{ ++ return container_of(chip, struct rp1_pwm, chip); ++} ++ ++static void rp1_pwm_apply_config(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct rp1_pwm *pc = to_rp1_pwm(chip); ++ u32 value; ++ ++ value = readl(pc->base + PWM_GLOBAL_CTRL); ++ value |= SET_UPDATE; ++ writel(value, pc->base + PWM_GLOBAL_CTRL); ++} ++ ++static int rp1_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct rp1_pwm *pc = to_rp1_pwm(chip); ++ ++ writel(PWM_CHANNEL_DEFAULT, pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm)); ++ return 0; ++} ++ ++static void rp1_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct rp1_pwm *pc = to_rp1_pwm(chip); ++ u32 value; ++ ++ value = readl(pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm)); ++ value &= ~PWM_MODE_MASK; ++ writel(value, pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm)); ++ rp1_pwm_apply_config(chip, pwm); ++} ++ ++static int rp1_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ++ const struct pwm_state *state) ++{ ++ struct rp1_pwm *pc = to_rp1_pwm(chip); ++ unsigned long clk_rate = clk_get_rate(pc->clk); ++ unsigned long clk_period; ++ u32 value; ++ ++ if (!clk_rate) { ++ dev_err(pc->dev, "failed to get clock rate\n"); ++ return -EINVAL; + } ++ ++ /* set period */ ++ clk_period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, clk_rate); ++ ++ writel(DIV_ROUND_CLOSEST(state->duty_cycle, clk_period), ++ pc->base + PWM_DUTY(pwm->hwpwm)); ++ ++ /* set duty cycle */ ++ writel(DIV_ROUND_CLOSEST(state->period, clk_period), ++ pc->base + PWM_RANGE(pwm->hwpwm)); ++ ++ /* set polarity */ ++ value = readl(pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm)); ++ if (state->polarity == PWM_POLARITY_NORMAL) ++ value &= ~PWM_POLARITY; ++ else ++ value |= PWM_POLARITY; ++ writel(value, pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm)); ++ ++ /* enable/disable */ ++ value = readl(pc->base + PWM_GLOBAL_CTRL); ++ if (state->enabled) ++ value |= PWM_CHANNEL_ENABLE(pwm->hwpwm); ++ else ++ value &= ~PWM_CHANNEL_ENABLE(pwm->hwpwm); ++ writel(value, pc->base + PWM_GLOBAL_CTRL); ++ ++ rp1_pwm_apply_config(chip, pwm); ++ ++ return 0; ++} ++ ++static const struct pwm_ops rp1_pwm_ops = { ++ .request = rp1_pwm_request, ++ .free = rp1_pwm_free, ++ .apply = rp1_pwm_apply, ++ .owner = THIS_MODULE, ++}; ++ ++static int rp1_pwm_probe(struct platform_device *pdev) ++{ ++ struct rp1_pwm *pc; ++ struct resource *res; ++ int ret; ++ ++ pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); ++ if (!pc) ++ return -ENOMEM; ++ ++ pc->dev = &pdev->dev; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ pc->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(pc->base)) ++ return PTR_ERR(pc->base); ++ ++ pc->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(pc->clk)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk), ++ "clock not found\n"); ++ ++ ret = clk_prepare_enable(pc->clk); ++ if (ret) ++ return ret; ++ ++ pc->chip.dev = &pdev->dev; ++ pc->chip.ops = &rp1_pwm_ops; ++ pc->chip.base = -1; ++ pc->chip.npwm = 4; ++ pc->chip.of_xlate = of_pwm_xlate_with_flags; ++ pc->chip.of_pwm_n_cells = 3; ++ ++ platform_set_drvdata(pdev, pc); ++ ++ ret = pwmchip_add(&pc->chip); ++ if (ret < 0) ++ goto add_fail; ++ ++ return 0; ++ ++add_fail: ++ clk_disable_unprepare(pc->clk); ++ return ret; ++} ++ ++static int rp1_pwm_remove(struct platform_device *pdev) ++{ ++ struct rp1_pwm *pc = platform_get_drvdata(pdev); ++ ++ clk_disable_unprepare(pc->clk); ++ ++ pwmchip_remove(&pc->chip); ++ ++ return 0; ++} ++ ++static const struct of_device_id rp1_pwm_of_match = { ++ { .compatible = "raspberrypi,rp1-pwm" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, rp1_pwm_of_match); ++ ++static struct platform_driver rp1_pwm_driver = { ++ .driver = { ++ .name = "rpi-pwm", ++ .of_match_table = rp1_pwm_of_match, ++ }, ++ .probe = rp1_pwm_probe, ++ .remove = rp1_pwm_remove, ++}; ++module_platform_driver(rp1_pwm_driver); ++ ++MODULE_AUTHOR("Naushir Patuck <naush@raspberrypi.com"); ++MODULE_DESCRIPTION("RP1 PWM driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/pwm/pwm-twl-led.c b/drivers/pwm/pwm-twl-led.c +index 8fb84b441853..65205449ed79 100644 +--- a/drivers/pwm/pwm-twl-led.c ++++ b/drivers/pwm/pwm-twl-led.c +@@ -172,7 +172,7 @@ static int twl4030_pwmled_apply(struct pwm_chip *chip, struct pwm_device *pwm, + * We cannot skip calling ->config even if state->period == + * pwm->state.period && state->duty_cycle == pwm->state.duty_cycle + * because we might have exited early in the last call to +- * pwm_apply_state because of !state->enabled and so the two values in ++ * pwm_apply_might_sleep because of !state->enabled and so the two values in + * pwm->state might not be configured in hardware. + */ + ret = twl4030_pwmled_config(pwm->chip, pwm, +diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c +index 6d46db51daac..ba1204e18afb 100644 +--- a/drivers/pwm/pwm-vt8500.c ++++ b/drivers/pwm/pwm-vt8500.c +@@ -206,7 +206,7 @@ static int vt8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + * We cannot skip calling ->config even if state->period == + * pwm->state.period && state->duty_cycle == pwm->state.duty_cycle + * because we might have exited early in the last call to +- * pwm_apply_state because of !state->enabled and so the two values in ++ * pwm_apply_might_sleep because of !state->enabled and so the two values in + * pwm->state might not be configured in hardware. + */ + err = vt8500_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period); +diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c +index 8d1254761e4d..052ccadbdabf 100644 +--- a/drivers/pwm/sysfs.c ++++ b/drivers/pwm/sysfs.c +@@ -62,7 +62,7 @@ static ssize_t period_store(struct device *child, + mutex_lock(&export->lock); + pwm_get_state(pwm, &state); + state.period = val; +- ret = pwm_apply_state(pwm, &state); ++ ret = pwm_apply_might_sleep(pwm, &state); + mutex_unlock(&export->lock); + + return ret ? : size; +@@ -97,7 +97,7 @@ static ssize_t duty_cycle_store(struct device *child, + mutex_lock(&export->lock); + pwm_get_state(pwm, &state); + state.duty_cycle = val; +- ret = pwm_apply_state(pwm, &state); ++ ret = pwm_apply_might_sleep(pwm, &state); + mutex_unlock(&export->lock); + + return ret ? : size; +@@ -144,7 +144,7 @@ static ssize_t enable_store(struct device *child, + goto unlock; + } -- ret = regmap_read(regmap, REG_PWM, &brightness); -- if (ret) +- ret = pwm_apply_state(pwm, &state); ++ ret = pwm_apply_might_sleep(pwm, &state); + + unlock: + mutex_unlock(&export->lock); +@@ -194,7 +194,7 @@ static ssize_t polarity_store(struct device *child, + mutex_lock(&export->lock); + pwm_get_state(pwm, &state); + state.polarity = polarity; +- ret = pwm_apply_state(pwm, &state); ++ ret = pwm_apply_might_sleep(pwm, &state); + mutex_unlock(&export->lock); + + return ret ? : size; +@@ -401,7 +401,7 @@ static int pwm_class_apply_state(struct pwm_export *export, + struct pwm_device *pwm, + struct pwm_state *state) + { +- int ret = pwm_apply_state(pwm, state); ++ int ret = pwm_apply_might_sleep(pwm, state); + + /* release lock taken in pwm_class_get_state */ + mutex_unlock(&export->lock); +diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig +index 965d4f0c18a6..d6210b0c3bc5 100644 +--- a/drivers/regulator/Kconfig ++++ b/drivers/regulator/Kconfig +@@ -1097,6 +1097,16 @@ config REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY + touchscreen unit. The regulator is used to enable power to the + TC358762, display and to control backlight. + ++config REGULATOR_RASPBERRYPI_TOUCHSCREEN_V2 ++ tristate "Raspberry Pi 7-inch touchscreen panel V2 regulator" ++ depends on BACKLIGHT_CLASS_DEVICE ++ depends on I2C ++ select REGMAP_I2C ++ help ++ This driver supports regulator on the V2 Raspberry Pi ++ touchscreen unit. The regulator is used to enable power to the ++ display and to control backlight. ++ + config REGULATOR_RC5T583 + tristate "RICOH RC5T583 Power regulators" + depends on MFD_RC5T583 +diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile +index 23074714a81a..6a1cfb31fa43 100644 +--- a/drivers/regulator/Makefile ++++ b/drivers/regulator/Makefile +@@ -130,6 +130,7 @@ obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o + obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o + obj-$(CONFIG_REGULATOR_RAA215300) += raa215300.o + obj-$(CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY) += rpi-panel-attiny-regulator.o ++obj-$(CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_V2) += rpi-panel-v2-regulator.o + obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o + obj-$(CONFIG_REGULATOR_RK808) += rk808-regulator.o + obj-$(CONFIG_REGULATOR_RN5T618) += rn5t618-regulator.o +diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c +index e33d10df7a76..226ca4c62673 100644 +--- a/drivers/regulator/pwm-regulator.c ++++ b/drivers/regulator/pwm-regulator.c +@@ -90,7 +90,7 @@ static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev, + pwm_set_relative_duty_cycle(&pstate, + drvdata->duty_cycle_tableselector.dutycycle, 100); + +- ret = pwm_apply_state(drvdata->pwm, &pstate); ++ ret = pwm_apply_might_sleep(drvdata->pwm, &pstate); + if (ret) { + dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret); + return ret; +@@ -219,7 +219,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, + + pwm_set_relative_duty_cycle(&pstate, dutycycle, duty_unit); + +- ret = pwm_apply_state(drvdata->pwm, &pstate); ++ ret = pwm_apply_might_sleep(drvdata->pwm, &pstate); + if (ret) { + dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret); + return ret; +diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c +index f52c3d47ecea..477bd96312e5 100644 +--- a/drivers/regulator/rpi-panel-attiny-regulator.c ++++ b/drivers/regulator/rpi-panel-attiny-regulator.c +@@ -143,24 +143,8 @@ static int attiny_lcd_power_disable(struct regulator_dev *rdev) + static int attiny_lcd_power_is_enabled(struct regulator_dev *rdev) + { + struct attiny_lcd *state = rdev_get_drvdata(rdev); +- unsigned int data; +- int ret, i; +- +- mutex_lock(&state->lock); +- +- for (i = 0; i < 10; i++) { +- ret = regmap_read(rdev->regmap, REG_PORTC, &data); +- if (!ret) +- break; +- usleep_range(10000, 12000); +- } +- +- mutex_unlock(&state->lock); +- +- if (ret < 0) - return ret; -+ mutex_unlock(&state->lock); -- return brightness; -+ return ret; +- return data & PC_RST_BRIDGE_N; ++ return state->port_statesREG_PORTC - REG_PORTA & PC_RST_BRIDGE_N; } - static const struct backlight_ops attiny_bl = { - .update_status = attiny_update_status, -- .get_brightness = attiny_get_brightness, - }; - -+static int attiny_gpio_get_direction(struct gpio_chip *gc, unsigned int off) + static const struct regulator_init_data attiny_regulator_default = { +diff --git a/drivers/regulator/rpi-panel-v2-regulator.c b/drivers/regulator/rpi-panel-v2-regulator.c +new file mode 100644 +index 000000000000..2a885f94e6b7 +--- /dev/null ++++ b/drivers/regulator/rpi-panel-v2-regulator.c +@@ -0,0 +1,189 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2022 Raspberry Pi Ltd. ++ * ++ * Based on rpi-panel-attiny-regulator.c by Marek Vasut <marex@denx.de> ++ */ ++ ++#include <linux/backlight.h> ++#include <linux/err.h> ++#include <linux/gpio.h> ++#include <linux/gpio/driver.h> ++#include <linux/module.h> ++#include <linux/regmap.h> ++#include <linux/regulator/driver.h> ++ ++/* I2C registers of the microcontroller. */ ++#define REG_ID 0x01 ++#define REG_POWERON 0x02 ++#define REG_PWM 0x03 ++ ++// bits for poweron register ++#define LCD_RESET_BIT BIT(0) ++#define CTP_RESET_BIT BIT(1) ++ ++//bits for the PWM register ++#define PWM_BL_ENABLE BIT(7) ++#define PWM_VALUE GENMASK(4, 0) ++ ++#define NUM_GPIO 2 /* Treat LCD_RESET and CTP_RESET as GPIOs */ ++ ++struct rpi_panel_v2_lcd { ++ /* lock to serialise overall accesses to the Atmel */ ++ struct mutex lock; ++ struct regmap *regmap; ++ u8 poweron_state; ++ ++ struct gpio_chip gc; ++}; ++ ++static const struct regmap_config rpi_panel_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .max_register = REG_PWM, ++}; ++ ++static int rpi_panel_v2_gpio_get_direction(struct gpio_chip *gc, unsigned int off) +{ + return GPIO_LINE_DIRECTION_OUT; +} + -+static void attiny_gpio_set(struct gpio_chip *gc, unsigned int off, int val) ++static void rpi_panel_v2_gpio_set(struct gpio_chip *gc, unsigned int off, int val) +{ -+ struct attiny_lcd *state = gpiochip_get_data(gc); ++ struct rpi_panel_v2_lcd *state = gpiochip_get_data(gc); + u8 last_val; + + if (off >= NUM_GPIO) @@ -98856,157 +152705,91 @@ + + mutex_lock(&state->lock); + -+ last_val = attiny_get_port_state(state, mappingsoff.reg); ++ last_val = state->poweron_state; + if (val) -+ last_val |= mappingsoff.mask; ++ last_val |= (1 << off); + else -+ last_val &= ~mappingsoff.mask; -+ -+ attiny_set_port_state(state, mappingsoff.reg, last_val); ++ last_val &= ~(1 << off); + -+ if (off == RST_BRIDGE_N && val) { -+ usleep_range(5000, 8000); -+ regmap_write(state->regmap, REG_ADDR_H, 0x04); -+ usleep_range(5000, 8000); -+ regmap_write(state->regmap, REG_ADDR_L, 0x7c); -+ usleep_range(5000, 8000); -+ regmap_write(state->regmap, REG_WRITE_DATA_H, 0x00); -+ usleep_range(5000, 8000); -+ regmap_write(state->regmap, REG_WRITE_DATA_L, 0x00); ++ state->poweron_state = last_val; + -+ msleep(100); -+ } ++ regmap_write(state->regmap, REG_POWERON, last_val); + + mutex_unlock(&state->lock); +} + -+static int attiny_i2c_read(struct i2c_client *client, u8 reg, unsigned int *buf) ++static int rpi_panel_v2_update_status(struct backlight_device *bl) +{ -+ struct i2c_msg msgs1; -+ u8 addr_buf1 = { reg }; -+ u8 data_buf1 = { 0, }; -+ int ret; -+ -+ /* Write register address */ -+ msgs0.addr = client->addr; -+ msgs0.flags = 0; -+ msgs0.len = ARRAY_SIZE(addr_buf); -+ msgs0.buf = addr_buf; -+ -+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); -+ if (ret != ARRAY_SIZE(msgs)) -+ return -EIO; ++ struct regmap *regmap = bl_get_data(bl); ++ int brightness = bl->props.brightness; + -+ usleep_range(5000, 10000); ++ if (bl->props.power != FB_BLANK_UNBLANK || ++ bl->props.fb_blank != FB_BLANK_UNBLANK) ++ brightness = 0; + -+ /* Read data from register */ -+ msgs0.addr = client->addr; -+ msgs0.flags = I2C_M_RD; -+ msgs0.len = 1; -+ msgs0.buf = data_buf; ++ return regmap_write(regmap, REG_PWM, brightness | PWM_BL_ENABLE); ++} + -+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); -+ if (ret != ARRAY_SIZE(msgs)) -+ return -EIO; ++static const struct backlight_ops rpi_panel_v2_bl = { ++ .update_status = rpi_panel_v2_update_status, ++}; + -+ *buf = data_buf0; -+ return 0; -+} ++/* ++ * I2C driver interface functions ++ */ ++static int rpi_panel_v2_i2c_probe(struct i2c_client *i2c) ++{ ++ struct backlight_properties props = { }; ++ struct backlight_device *bl; ++ struct rpi_panel_v2_lcd *state; ++ struct regmap *regmap; ++ unsigned int data; ++ int ret; + - /* - * I2C driver interface functions - */ -@@ -138,22 +277,30 @@ static int attiny_i2c_probe(struct i2c_client *i2c, - struct regulator_config config = { }; - struct backlight_device *bl; - struct regulator_dev *rdev; -+ struct attiny_lcd *state; - struct regmap *regmap; - unsigned int data; - int ret; - + state = devm_kzalloc(&i2c->dev, sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + mutex_init(&state->lock); -+ i2c_set_clientdata(i2c, state); + - regmap = devm_regmap_init_i2c(i2c, &attiny_regmap_config); - if (IS_ERR(regmap)) { - ret = PTR_ERR(regmap); - dev_err(&i2c->dev, "Failed to allocate register map: %d\n", - ret); -- return ret; ++ regmap = devm_regmap_init_i2c(i2c, &rpi_panel_regmap_config); ++ if (IS_ERR(regmap)) { ++ ret = PTR_ERR(regmap); ++ dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ++ ret); + goto error; - } - -- ret = regmap_read(regmap, REG_ID, &data); -+ ret = attiny_i2c_read(i2c, REG_ID, &data); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to read REG_ID reg: %d\n", ret); -- return ret; ++ } ++ ++ ret = regmap_read(regmap, REG_ID, &data); ++ if (ret < 0) { ++ dev_err(&i2c->dev, "Failed to read REG_ID reg: %d\n", ret); + goto error; - } - - switch (data) { -@@ -162,34 +309,73 @@ static int attiny_i2c_probe(struct i2c_client *i2c, - break; - default: - dev_err(&i2c->dev, "Unknown Atmel firmware revision: 0x%02x\n", data); -- return -ENODEV; ++ } ++ ++ switch (data & 0x0f) { ++ case 0x01: /* 7 inch */ ++ case 0x04: /* 7 inch - old */ ++ case 0x08: /* 5 inch - old */ ++ case 0x09: /* 5 inch */ ++ break; ++ default: ++ dev_err(&i2c->dev, "Unknown revision: 0x%02x\n", ++ data & 0x0f); + ret = -ENODEV; + goto error; - } - - regmap_write(regmap, REG_POWERON, 0); -- mdelay(1); -+ msleep(30); -+ regmap_write(regmap, REG_PWM, 0); - - config.dev = &i2c->dev; - config.regmap = regmap; - config.of_node = i2c->dev.of_node; - config.init_data = &attiny_regulator_default; -+ config.driver_data = state; - - rdev = devm_regulator_register(&i2c->dev, &attiny_regulator, &config); - if (IS_ERR(rdev)) { - dev_err(&i2c->dev, "Failed to register ATTINY regulator\n"); -- return PTR_ERR(rdev); -+ ret = PTR_ERR(rdev); -+ goto error; - } - - props.type = BACKLIGHT_RAW; - props.max_brightness = 0xff; -- bl = devm_backlight_device_register(&i2c->dev, -- "7inch-touchscreen-panel-bl", -- &i2c->dev, regmap, &attiny_bl, ++ } + -+ state->regmap = regmap; ++ regmap_write(regmap, REG_POWERON, 0); + -+ bl = devm_backlight_device_register(&i2c->dev, dev_name(&i2c->dev), -+ &i2c->dev, state, &attiny_bl, - &props); -- if (IS_ERR(bl)) -- return PTR_ERR(bl); -+ if (IS_ERR(bl)) { -+ ret = PTR_ERR(bl); -+ goto error; -+ } - - bl->props.brightness = 0xff; - ++ state->regmap = regmap; + state->gc.parent = &i2c->dev; + state->gc.label = i2c->name; + state->gc.owner = THIS_MODULE; -+ state->gc.of_node = i2c->dev.of_node; + state->gc.base = -1; + state->gc.ngpio = NUM_GPIO; + -+ state->gc.set = attiny_gpio_set; -+ state->gc.get_direction = attiny_gpio_get_direction; ++ state->gc.set = rpi_panel_v2_gpio_set; ++ state->gc.get_direction = rpi_panel_v2_gpio_get_direction; + state->gc.can_sleep = true; + + ret = devm_gpiochip_add_data(&i2c->dev, &state->gc, state); @@ -99015,71 +152798,171 @@ + goto error; + } + ++ props.type = BACKLIGHT_RAW; ++ props.max_brightness = PWM_VALUE; ++ bl = devm_backlight_device_register(&i2c->dev, dev_name(&i2c->dev), ++ &i2c->dev, regmap, &rpi_panel_v2_bl, ++ &props); ++ if (IS_ERR(bl)) ++ return PTR_ERR(bl); ++ ++ bl->props.brightness = PWM_VALUE; ++ + return 0; + +error: + mutex_destroy(&state->lock); -+ + return ret; +} + -+static int attiny_i2c_remove(struct i2c_client *client) -+{ -+ struct attiny_lcd *state = i2c_get_clientdata(client); ++static const struct of_device_id rpi_panel_v2_dt_ids = { ++ { .compatible = "raspberrypi,v2-touchscreen-panel-regulator" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rpi_panel_v2_dt_ids); + -+ mutex_destroy(&state->lock); ++static struct i2c_driver rpi_panel_v2_regulator_driver = { ++ .driver = { ++ .name = "rpi_touchscreen_v2", ++ .of_match_table = of_match_ptr(rpi_panel_v2_dt_ids), ++ }, ++ .probe = rpi_panel_v2_i2c_probe, ++}; ++ ++module_i2c_driver(rpi_panel_v2_regulator_driver); + ++MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com>"); ++MODULE_DESCRIPTION("Regulator device driver for Raspberry Pi 7-inch V2 touchscreen"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig +index ccd59ddd7610..c2db8d4c47f2 100644 +--- a/drivers/reset/Kconfig ++++ b/drivers/reset/Kconfig +@@ -51,7 +51,7 @@ config RESET_BERLIN + + config RESET_BRCMSTB + tristate "Broadcom STB reset controller" +- depends on ARCH_BRCMSTB || COMPILE_TEST ++ depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST + default ARCH_BRCMSTB + help + This enables the reset controller driver for Broadcom STB SoCs using +diff --git a/drivers/reset/reset-brcmstb-rescal.c b/drivers/reset/reset-brcmstb-rescal.c +index 823317772bac..89c1cae675a0 100644 +--- a/drivers/reset/reset-brcmstb-rescal.c ++++ b/drivers/reset/reset-brcmstb-rescal.c +@@ -20,6 +20,7 @@ struct brcm_rescal_reset { + struct reset_controller_dev rcdev; + }; + ++/* Also doubles a deassert */ + static int brcm_rescal_reset_set(struct reset_controller_dev *rcdev, + unsigned long id) + { +@@ -52,6 +53,13 @@ static int brcm_rescal_reset_set(struct reset_controller_dev *rcdev, return 0; } -@@ -205,6 +391,7 @@ static struct i2c_driver attiny_regulator_driver = { - .of_match_table = of_match_ptr(attiny_dt_ids), - }, - .probe = attiny_i2c_probe, -+ .remove = attiny_i2c_remove, ++/* A dummy function - deassert/reset does all the work */ ++static int brcm_rescal_reset_assert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ return 0; ++} ++ + static int brcm_rescal_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) + { +@@ -61,6 +69,8 @@ static int brcm_rescal_reset_xlate(struct reset_controller_dev *rcdev, + + static const struct reset_control_ops brcm_rescal_reset_ops = { + .reset = brcm_rescal_reset_set, ++ .deassert = brcm_rescal_reset_set, ++ .assert = brcm_rescal_reset_assert, }; - module_i2c_driver(attiny_regulator_driver); + static int brcm_rescal_reset_probe(struct platform_device *pdev) +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index 179c99a0e706..7e423b2876ac 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -223,6 +223,17 @@ config RTC_DRV_AC100 + This driver can also be built as a module. If so, the module + will be called rtc-ac100. + ++config RTC_DRV_RPI ++ tristate "Raspberry Pi RTC" ++ depends on ARCH_BRCMSTB || COMPILE_TEST ++ default ARCH_BRCMSTB ++ help ++ If you say yes here you get support for the RTC found on ++ Raspberry Pi devices. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-rpi. ++ + config RTC_DRV_BRCMSTB + tristate "Broadcom STB wake-timer" + depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 7711f79787ac..3d0cbf4432a6 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -143,6 +143,7 @@ obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5t583.o + obj-$(CONFIG_RTC_DRV_RC5T619) += rtc-rc5t619.o + obj-$(CONFIG_RTC_DRV_RK808) += rtc-rk808.o + obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o ++obj-$(CONFIG_RTC_DRV_RPI) += rtc-rpi.o + obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o + obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o + obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o +diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c +index 89d7b085f721..3ebddced2c54 100644 +--- a/drivers/rtc/rtc-ds3232.c ++++ b/drivers/rtc/rtc-ds3232.c +@@ -701,9 +701,16 @@ static int ds3234_probe(struct spi_device *spi) + return ds3232_probe(&spi->dev, regmap, spi->irq, "ds3234"); + } + ++static const __maybe_unused struct of_device_id ds3234_of_match = { ++ { .compatible = "dallas,ds3234" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ds3234_of_match); ++ + static struct spi_driver ds3234_driver = { + .driver = { + .name = "ds3234", ++ .of_match_table = of_match_ptr(ds3234_of_match), + }, + .probe = ds3234_probe, + }; diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c -index c3691fa4210e..ead1fd376d2d 100644 +index e714661e61a9..89cda4dea7f8 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c -@@ -465,3 +465,4 @@ module_spi_driver(pcf2123_driver); +@@ -479,3 +479,4 @@ module_spi_driver(pcf2123_driver); MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>"); MODULE_DESCRIPTION("NXP PCF2123 RTC driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:rtc-pcf2123"); -diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c -index 62684ca3a665..fc293d4d8901 100644 ---- a/drivers/rtc/rtc-pcf85063.c -+++ b/drivers/rtc/rtc-pcf85063.c -@@ -34,6 +34,7 @@ - #define PCF85063_REG_CTRL1 0x00 /* status */ - #define PCF85063_REG_CTRL1_CAP_SEL BIT(0) - #define PCF85063_REG_CTRL1_STOP BIT(5) -+#define PCF85063_REG_CTRL1_EXT_TEST BIT(7) - - #define PCF85063_REG_CTRL2 0x01 - #define PCF85063_CTRL2_AF BIT(6) -@@ -117,6 +118,7 @@ static int pcf85063_rtc_set_time(struct device *dev, struct rtc_time *tm) - * reset state until all time/date registers are written - */ - rc = regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL1, -+ PCF85063_REG_CTRL1_EXT_TEST | - PCF85063_REG_CTRL1_STOP, - PCF85063_REG_CTRL1_STOP); - if (rc) diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c -index 57d351dfe272..0aa1e8f9ee75 100644 +index d1efde3e7a80..6f95c7cd8afb 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c -@@ -205,8 +205,28 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) - if (err < 0) - return err; +@@ -100,6 +100,7 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) + { + struct pcf8523 *pcf8523 = dev_get_drvdata(dev); + u8 regs10; ++ u32 value; + int err; -- if (regs0 & REG_SECONDS_OS) -- return -EINVAL; -+ if (regs0 & REG_SECONDS_OS) { + err = regmap_bulk_read(pcf8523->regmap, PCF8523_REG_CONTROL1, regs, +@@ -110,6 +111,33 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) + if ((regs0 & PCF8523_CONTROL1_STOP) || (regs3 & PCF8523_SECONDS_OS)) + return -EINVAL; + ++ if (regs0 & PCF8523_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 @@ -99088,74 +152971,362 @@ + * that the clock cannot be assumed to be correct. + */ + -+ regs0 &= ~REG_SECONDS_OS; ++ regs0 &= ~PCF8523_SECONDS_OS; + -+ err = pcf8523_write(client, REG_SECONDS, regs0); ++ err = regmap_write(pcf8523->regmap, PCF8523_REG_SECONDS, ++ regs0); + if (err < 0) + return err; + -+ err = pcf8523_read(client, REG_SECONDS, ®s0); ++ err = regmap_read(pcf8523->regmap, PCF8523_REG_SECONDS, ++ &value); + if (err < 0) + return err; + -+ if (regs0 & REG_SECONDS_OS) ++ if (value & PCF8523_SECONDS_OS) + return -EAGAIN; ++ ++ regs0 = value; + } - - tm->tm_sec = bcd2bin(regs0 & 0x7f); - tm->tm_min = bcd2bin(regs1 & 0x7f); -@@ -242,7 +262,6 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm) - return err; - - regs0 = REG_SECONDS; -- /* This will purposely overwrite REG_SECONDS_OS */ - regs1 = bin2bcd(tm->tm_sec); - regs2 = bin2bcd(tm->tm_min); - regs3 = bin2bcd(tm->tm_hour); ++ + tm->tm_sec = bcd2bin(regs3 & 0x7f); + tm->tm_min = bcd2bin(regs4 & 0x7f); + tm->tm_hour = bcd2bin(regs5 & 0x3f); +diff --git a/drivers/rtc/rtc-rpi.c b/drivers/rtc/rtc-rpi.c +new file mode 100644 +index 000000000000..006012333e78 +--- /dev/null ++++ b/drivers/rtc/rtc-rpi.c +@@ -0,0 +1,277 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/** ++ * rtc-rpi.c ++ * ++ * RTC driver using firmware mailbox ++ * Supports battery backed RTC and wake alarms ++ * ++ * Based on rtc-meson-vrtc by Neil Armstrong ++ * ++ * Copyright (c) 2023, Raspberry Pi Ltd. ++ */ ++ ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/rtc.h> ++#include <linux/of.h> ++#include <soc/bcm2835/raspberrypi-firmware.h> ++ ++struct rpi_rtc_data { ++ struct rtc_device *rtc; ++ struct rpi_firmware *fw; ++ u32 bbat_vchg_microvolts; ++}; ++ ++#define RPI_FIRMWARE_GET_RTC_REG 0x00030087 ++#define RPI_FIRMWARE_SET_RTC_REG 0x00038087 ++ ++enum { ++ RTC_TIME, ++ RTC_ALARM, ++ RTC_ALARM_PENDING, ++ RTC_ALARM_ENABLE, ++ RTC_BBAT_CHG_VOLTS, ++ RTC_BBAT_CHG_VOLTS_MIN, ++ RTC_BBAT_CHG_VOLTS_MAX, ++ RTC_BBAT_VOLTS ++}; ++ ++static int rpi_rtc_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); ++ u32 data2 = {RTC_TIME}; ++ int err; ++ ++ err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG, ++ &data, sizeof(data)); ++ rtc_time64_to_tm(data1, tm); ++ return err; ++} ++ ++static int rpi_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); ++ u32 data2 = {RTC_TIME, rtc_tm_to_time64(tm)}; ++ ++ return rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG, ++ &data, sizeof(data)); ++} ++ ++static int rpi_rtc_alarm_irq_is_enabled(struct device *dev, unsigned char *enabled) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); ++ u32 data2 = {RTC_ALARM_ENABLE}; ++ s32 err = 0; ++ ++ err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG, ++ &data, sizeof(data)); ++ *enabled = data1 & 0x1; ++ return err; ++} ++ ++static int rpi_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); ++ u32 data2 = {RTC_ALARM_ENABLE, enabled}; ++ ++ return rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG, ++ &data, sizeof(data)); ++} ++ ++static int rpi_rtc_alarm_clear_pending(struct device *dev) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); ++ u32 data2 = {RTC_ALARM_PENDING, 1}; ++ ++ return rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG, ++ &data, sizeof(data)); ++} ++ ++static int rpi_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); ++ u32 data2 = {RTC_ALARM}; ++ s32 err = 0; ++ ++ err = rpi_rtc_alarm_irq_is_enabled(dev, &alarm->enabled); ++ if (!err) ++ err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG, ++ &data, sizeof(data)); ++ rtc_time64_to_tm(data1, &alarm->time); ++ ++ return err; ++} ++ ++static int rpi_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); ++ u32 data2 = {RTC_ALARM, rtc_tm_to_time64(&alarm->time)}; ++ int err; ++ ++ err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG, ++ &data, sizeof(data)); ++ ++ if (err == 0) ++ err = rpi_rtc_alarm_irq_enable(dev, alarm->enabled); ++ ++ return err; ++} ++ ++static const struct rtc_class_ops rpi_rtc_ops = { ++ .read_time = rpi_rtc_read_time, ++ .set_time = rpi_rtc_set_time, ++ .read_alarm = rpi_rtc_read_alarm, ++ .set_alarm = rpi_rtc_set_alarm, ++ .alarm_irq_enable = rpi_rtc_alarm_irq_enable, ++}; ++ ++static int rpi_rtc_set_charge_voltage(struct device *dev) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); ++ u32 data2 = {RTC_BBAT_CHG_VOLTS, vrtc->bbat_vchg_microvolts}; ++ int err; ++ ++ err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG, ++ &data, sizeof(data)); ++ ++ if (err) ++ dev_err(dev, "failed to set trickle charge voltage to %uuV: %d\n", ++ vrtc->bbat_vchg_microvolts, err); ++ else if (vrtc->bbat_vchg_microvolts) ++ dev_info(dev, "trickle charging enabled at %uuV\n", ++ vrtc->bbat_vchg_microvolts); ++ ++ return err; ++} ++ ++static ssize_t rpi_rtc_print_uint_reg(struct device *dev, char *buf, u32 reg) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev->parent); ++ u32 data2 = {reg, 0}; ++ int ret = 0; ++ ++ ret = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG, ++ &data, sizeof(data)); ++ if (ret < 0) ++ return ret; ++ ++ return sprintf(buf, "%u\n", data1); ++} ++ ++static ssize_t charging_voltage_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_CHG_VOLTS); ++} ++static DEVICE_ATTR_RO(charging_voltage); ++ ++static ssize_t charging_voltage_min_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_CHG_VOLTS_MIN); ++} ++static DEVICE_ATTR_RO(charging_voltage_min); ++ ++static ssize_t charging_voltage_max_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_CHG_VOLTS_MAX); ++} ++static DEVICE_ATTR_RO(charging_voltage_max); ++ ++static ssize_t battery_voltage_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_VOLTS); ++} ++static DEVICE_ATTR_RO(battery_voltage); ++ ++static struct attribute *rpi_rtc_attrs = { ++ &dev_attr_charging_voltage.attr, ++ &dev_attr_charging_voltage_min.attr, ++ &dev_attr_charging_voltage_max.attr, ++ &dev_attr_battery_voltage.attr, ++ NULL ++}; ++ ++static const struct attribute_group rpi_rtc_sysfs_files = { ++ .attrs = rpi_rtc_attrs, ++}; ++ ++static int rpi_rtc_probe(struct platform_device *pdev) ++{ ++ struct rpi_rtc_data *vrtc; ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct device_node *fw_node; ++ struct rpi_firmware *fw; ++ int ret; ++ ++ fw_node = of_parse_phandle(np, "firmware", 0); ++ if (!fw_node) { ++ dev_err(dev, "Missing firmware node\n"); ++ return -ENOENT; ++ } ++ ++ fw = rpi_firmware_get(fw_node); ++ if (!fw) ++ return -EPROBE_DEFER; ++ ++ vrtc = devm_kzalloc(&pdev->dev, sizeof(*vrtc), GFP_KERNEL); ++ if (!vrtc) ++ return -ENOMEM; ++ ++ vrtc->fw = fw; ++ ++ device_init_wakeup(&pdev->dev, 1); ++ ++ platform_set_drvdata(pdev, vrtc); ++ ++ vrtc->rtc = devm_rtc_allocate_device(&pdev->dev); ++ if (IS_ERR(vrtc->rtc)) ++ return PTR_ERR(vrtc->rtc); ++ ++ set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, vrtc->rtc->features); ++ clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, vrtc->rtc->features); ++ ++ vrtc->rtc->ops = &rpi_rtc_ops; ++ ret = rtc_add_group(vrtc->rtc, &rpi_rtc_sysfs_files); ++ if (ret) ++ return ret; ++ ++ rpi_rtc_alarm_clear_pending(dev); ++ ++ /* ++ * Optionally enable trickle charging - if the property isn't ++ * present (or set to zero), trickle charging is disabled. ++ */ ++ of_property_read_u32(np, "trickle-charge-microvolt", ++ &vrtc->bbat_vchg_microvolts); ++ ++ rpi_rtc_set_charge_voltage(dev); ++ ++ return devm_rtc_register_device(vrtc->rtc); ++} ++ ++static const struct of_device_id rpi_rtc_dt_match = { ++ { .compatible = "raspberrypi,rpi-rtc"}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rpi_rtc_dt_match); ++ ++static struct platform_driver rpi_rtc_driver = { ++ .probe = rpi_rtc_probe, ++ .driver = { ++ .name = "rpi-rtc", ++ .of_match_table = rpi_rtc_dt_match, ++ }, ++}; ++ ++module_platform_driver(rpi_rtc_driver); ++ ++MODULE_DESCRIPTION("Raspberry Pi RTC driver"); ++MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c -index fa226f0fe67d..20baf2257631 100644 +index 2f001c59c61d..51f542d82335 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c -@@ -80,6 +80,7 @@ +@@ -858,16 +858,17 @@ static const struct regmap_config regmap_config = { + static u8 rv3028_set_trickle_charger(struct rv3028_data *rv3028, + struct i2c_client *client) + { +- int ret, val_old, val; ++ int ret, val_old, val, val_mask; + u32 ohms, chargeable; ++ u32 bsm; - #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 - -@@ -789,6 +790,7 @@ static int rv3028_probe(struct i2c_client *client) - struct rv3028_data *rv3028; - int ret, status; - u32 ohms; -+ u8 bsm; - struct nvmem_config nvmem_cfg = { - .name = "rv3028_nvram", - .word_size = 1, -@@ -860,6 +862,21 @@ static int rv3028_probe(struct i2c_client *client) - if (ret) + ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &val_old); + if (ret < 0) return ret; + /* mask out only trickle charger bits */ +- val_old = val_old & (RV3028_BACKUP_TCE | RV3028_BACKUP_TCR_MASK); +- val = val_old; ++ val_mask = RV3028_BACKUP_TCE | RV3028_BACKUP_TCR_MASK; ++ val = val_old & val_mask; + + /* setup trickle charger */ + if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms", +@@ -902,10 +903,21 @@ static u8 rv3028_set_trickle_charger(struct rv3028_data *rv3028, + } + } + + /* setup backup switchover mode */ -+ if (!device_property_read_u8(&client->dev, "backup-switchover-mode", -+ &bsm)) { ++ if (!device_property_read_u32(&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; ++ val_mask |= RV3028_BACKUP_BSM; ++ val |= (u8)(bsm << 2); + } 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)) { + /* only update EEPROM if changes are necessary */ +- if (val_old != val) { +- ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_TCE | +- RV3028_BACKUP_TCR_MASK, val); ++ if ((val_old & val_mask) != val) { ++ ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, val_mask, val); + if (ret) + return ret; + } diff --git a/drivers/soc/bcm/Kconfig b/drivers/soc/bcm/Kconfig -index 24f92a6e882a..a6a705ec30c7 100644 +index f96906795fa6..3856477b14ff 100644 --- a/drivers/soc/bcm/Kconfig +++ b/drivers/soc/bcm/Kconfig @@ -17,6 +17,7 @@ config RASPBERRYPI_POWER @@ -99166,86 +153337,62 @@ select PM_GENERIC_DOMAINS if PM help This enables support for the RPi power domains which can be enabled -diff --git a/drivers/soc/bcm/bcm2835-power.c b/drivers/soc/bcm/bcm2835-power.c -index 1e0041ec8132..6059210170bc 100644 ---- a/drivers/soc/bcm/bcm2835-power.c -+++ b/drivers/soc/bcm/bcm2835-power.c -@@ -143,6 +143,8 @@ struct bcm2835_power { - /* AXI Async bridge registers. */ - void __iomem *asb; - -+ bool is_2711; -+ - struct genpd_onecell_data pd_xlate; - struct bcm2835_power_domain domainsBCM2835_POWER_DOMAIN_COUNT; - struct reset_controller_dev reset; -@@ -192,6 +194,10 @@ static int bcm2835_power_power_off(struct bcm2835_power_domain *pd, u32 pm_reg) - { - 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); - -@@ -213,6 +219,10 @@ static int bcm2835_power_power_on(struct bcm2835_power_domain *pd, u32 pm_reg) - 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; -@@ -627,6 +637,18 @@ static int bcm2835_power_probe(struct platform_device *pdev) - 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 --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c -index 33c32e931767..0f6a2f7c8b53 100644 +index e7bb2714678a..d3ad0f08d639 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c -@@ -28,6 +28,7 @@ - #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> +@@ -116,6 +116,7 @@ MODULE_PARM_DESC(polling_limit_us, + */ + struct bcm2835_spi { + void __iomem *regs; ++ phys_addr_t phys_addr; + struct clk *clk; + unsigned long clk_hz; + int irq; +@@ -887,19 +888,8 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev, + struct bcm2835_spi *bs) + { + struct dma_slave_config slave_config; +- const __be32 *addr; +- dma_addr_t dma_reg_base; + int ret; -@@ -379,6 +380,10 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) - if (bs->tx_len && cs & BCM2835_SPI_CS_DONE) - bcm2835_wr_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE); +- /* base address in dma-space */ +- addr = of_get_address(ctlr->dev.of_node, 0, NULL, NULL); +- if (!addr) { +- dev_err(dev, "could not get DMA-register address - not using dma mode\n"); +- /* Fall back to interrupt mode */ +- return 0; +- } +- dma_reg_base = be32_to_cpup(addr); +- + /* get tx/rx dma */ + ctlr->dma_tx = dma_request_chan(dev, "tx"); + if (IS_ERR(ctlr->dma_tx)) { +@@ -921,7 +911,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev, + * or, in case of an RX-only transfer, cyclically copies from the zero + * page to the FIFO using a preallocated, reusable descriptor. + */ +- slave_config.dst_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO); ++ slave_config.dst_addr = bs->phys_addr + BCM2835_SPI_FIFO; + slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + + ret = dmaengine_slave_config(ctlr->dma_tx, &slave_config); +@@ -960,9 +950,9 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev, + * RX FIFO or, in case of a TX-only transfer, cyclically writes a + * precalculated value to the CS register to clear the RX FIFO. + */ +- slave_config.src_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO); ++ slave_config.src_addr = bs->phys_addr + BCM2835_SPI_FIFO; + slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +- slave_config.dst_addr = (u32)(dma_reg_base + BCM2835_SPI_CS); ++ slave_config.dst_addr = bs->phys_addr + BCM2835_SPI_CS; + slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; -+ /* 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 */ -@@ -1088,6 +1093,16 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr, + ret = dmaengine_slave_config(ctlr->dma_rx, &slave_config); +@@ -1055,6 +1045,16 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr, unsigned long hz_per_byte, byte_limit; - u32 cs = bs->prepare_csspi->chip_select; + u32 cs = target->prepare_cs; + if (unlikely(!tfr->len)) { + static int warned; @@ -99260,41 +153407,334 @@ /* set clock */ spi_hz = tfr->speed_hz; -@@ -1285,6 +1300,11 @@ static int bcm2835_spi_probe(struct platform_device *pdev) +@@ -1222,6 +1222,7 @@ static int bcm2835_spi_setup(struct spi_device *spi) + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); + struct bcm2835_spidev *target = spi_get_ctldata(spi); + struct gpio_chip *chip; ++ int len; + int ret; + u32 cs; + +@@ -1287,6 +1288,10 @@ static int bcm2835_spi_setup(struct spi_device *spi) + goto err_cleanup; + } + ++ /* Skip forced CS conversion if controller has an empty cs-gpios property */ ++ if (of_find_property(ctlr->dev.of_node, "cs-gpios", &len) && len == 0) ++ return 0; ++ + /* + * Translate native CS to GPIO + * +@@ -1326,6 +1331,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) + { + struct spi_controller *ctlr; struct bcm2835_spi *bs; ++ struct resource *iomem; 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_host(&pdev->dev, sizeof(*bs)); +@@ -1348,10 +1354,11 @@ static int bcm2835_spi_probe(struct platform_device *pdev) + bs = spi_controller_get_devdata(ctlr); + bs->ctlr = ctlr; + +- bs->regs = devm_platform_ioremap_resource(pdev, 0); ++ bs->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &iomem); + if (IS_ERR(bs->regs)) + return PTR_ERR(bs->regs); + ++ bs->phys_addr = iomem->start; + bs->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(bs->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(bs->clk), +diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c +index 0274c9295514..86f33e6da447 100644 +--- a/drivers/spi/spi-dw-core.c ++++ b/drivers/spi/spi-dw-core.c +@@ -239,8 +239,11 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws) + */ + if (irq_status & DW_SPI_INT_TXEI) { + dw_writer(dws); +- if (!dws->tx_len) ++ if (!dws->tx_len) { + dw_spi_mask_intr(dws, DW_SPI_INT_TXEI); ++ if (!dws->rx_len) ++ spi_finalize_current_transfer(dws->host); ++ } + } + + return IRQ_HANDLED; +@@ -367,8 +370,11 @@ static void dw_spi_irq_setup(struct dw_spi *dws) + + dws->transfer_handler = dw_spi_transfer_handler; + +- imask = DW_SPI_INT_TXEI | DW_SPI_INT_TXOI | +- DW_SPI_INT_RXUI | DW_SPI_INT_RXOI | DW_SPI_INT_RXFI; ++ imask = 0; ++ if (dws->tx_len) ++ imask |= DW_SPI_INT_TXEI | DW_SPI_INT_TXOI; ++ if (dws->rx_len) ++ imask |= DW_SPI_INT_RXUI | DW_SPI_INT_RXOI | DW_SPI_INT_RXFI; + dw_spi_umask_intr(dws, imask); + } + +diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c +index 0ecbb6c36e23..252ee087fef4 100644 +--- a/drivers/spi/spi-dw-dma.c ++++ b/drivers/spi/spi-dw-dma.c +@@ -315,8 +315,10 @@ static void dw_spi_dma_tx_done(void *arg) + struct dw_spi *dws = arg; + + clear_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy); +- if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy)) ++ if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy)) { ++ dw_writel(dws, DW_SPI_DMARDLR, 0); + return; ++ } + + complete(&dws->dma_completion); + } +@@ -642,6 +644,8 @@ static int dw_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer) + + nents = max(xfer->tx_sg.nents, xfer->rx_sg.nents); + ++ dw_writel(dws, DW_SPI_DMARDLR, xfer->tx_buf ? (dws->rxburst - 1) : 0); + - ctlr = devm_spi_alloc_master(&pdev->dev, ALIGN(sizeof(*bs), - dma_get_cache_alignment())); - if (!ctlr) -@@ -1329,7 +1349,8 @@ static int bcm2835_spi_probe(struct platform_device *pdev) - 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); + /* + * Execute normal DMA-based transfer (which submits the Rx and Tx SG + * lists directly to the DMA engine at once) if either full hardware +diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c +index 805264c9c65c..50bad1c13c37 100644 +--- a/drivers/spi/spi-dw-mmio.c ++++ b/drivers/spi/spi-dw-mmio.c +@@ -20,6 +20,7 @@ + #include <linux/property.h> + #include <linux/regmap.h> + #include <linux/reset.h> ++#include <linux/interrupt.h> + + #include "spi-dw.h" + +@@ -337,8 +338,11 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) + dws->paddr = mem->start; + + dws->irq = platform_get_irq(pdev, 0); +- if (dws->irq < 0) +- return dws->irq; /* -ENXIO */ ++ if (dws->irq < 0) { ++ if (dws->irq != -ENXIO) ++ return dws->irq; /* -ENXIO */ ++ dws->irq = IRQ_NOTCONNECTED; ++ } + + dwsmmio->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(dwsmmio->clk)) +diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c +index d8db4564b406..c95e4e9c14e3 100644 +--- a/drivers/spi/spi-gpio.c ++++ b/drivers/spi/spi-gpio.c +@@ -10,12 +10,12 @@ + #include <linux/platform_device.h> + #include <linux/gpio/consumer.h> + #include <linux/of.h> ++#include <linux/delay.h> + + #include <linux/spi/spi.h> + #include <linux/spi/spi_bitbang.h> + #include <linux/spi/spi_gpio.h> + +- + /* + * This bitbanging SPI host driver should help make systems usable + * when a native hardware SPI engine is not available, perhaps because +@@ -35,6 +35,8 @@ struct spi_gpio { + struct gpio_desc *miso; + struct gpio_desc *mosi; + struct gpio_desc **cs_gpios; ++ bool sck_idle_input; ++ bool cs_dont_invert; + }; + + /*----------------------------------------------------------------------*/ +@@ -108,12 +110,18 @@ static inline int getmiso(const struct spi_device *spi) + } + + /* +- * NOTE: this clocks "as fast as we can". It "should" be a function of the +- * requested device clock. Software overhead means we usually have trouble +- * reaching even one Mbit/sec (except when we can inline bitops), so for now +- * we'll just assume we never need additional per-bit slowdowns. ++ * Generic bit-banged GPIO SPI might free-run at something in the range ++ * 1Mbps ~ 10Mbps (depending on the platform), and some SPI devices may ++ * need to be clocked at a lower rate. ndelay() is often implemented by ++ * udelay() with rounding up, so do the delay only for nsecs >= 500 ++ * (<= 1Mbps). The conditional test adds a small overhead. + */ +-#define spidelay(nsecs) do {} while (0) ++ ++static inline void spidelay(unsigned long nsecs) ++{ ++ if (nsecs >= 500) ++ ndelay(nsecs); ++} + + #include "spi-bitbang-txrx.h" + +@@ -224,16 +232,29 @@ static void spi_gpio_chipselect(struct spi_device *spi, int is_active) + struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); + + /* set initial clock line level */ +- if (is_active) +- gpiod_set_value_cansleep(spi_gpio->sck, spi->mode & SPI_CPOL); ++ if (is_active) { ++ if (spi_gpio->sck_idle_input) ++ gpiod_direction_output(spi_gpio->sck, spi->mode & SPI_CPOL); ++ else ++ gpiod_set_value_cansleep(spi_gpio->sck, spi->mode & SPI_CPOL); ++ } + +- /* Drive chip select line, if we have one */ ++ /* ++ * Drive chip select line, if we have one. ++ * SPI chip selects are normally active-low, but when ++ * cs_dont_invert is set, we assume their polarity is ++ * controlled by the GPIO, and write '1' to assert. ++ */ + if (spi_gpio->cs_gpios) { + struct gpio_desc *cs = spi_gpio->cs_gpiosspi_get_chipselect(spi, 0); ++ int val = ((spi->mode & SPI_CS_HIGH) || spi_gpio->cs_dont_invert) ? ++ is_active : !is_active; + +- /* SPI chip selects are normally active-low */ +- gpiod_set_value_cansleep(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active); ++ gpiod_set_value_cansleep(cs, val); + } ++ ++ if (spi_gpio->sck_idle_input && !is_active) ++ gpiod_direction_input(spi_gpio->sck); + } + + static int spi_gpio_setup(struct spi_device *spi) +@@ -245,12 +266,14 @@ static int spi_gpio_setup(struct spi_device *spi) + /* + * The CS GPIOs have already been + * initialized from the descriptor lookup. ++ * Here we set them to the non-asserted state. + */ + if (spi_gpio->cs_gpios) { + cs = spi_gpio->cs_gpiosspi_get_chipselect(spi, 0); + if (!spi->controller_state && cs) + status = gpiod_direction_output(cs, +- !(spi->mode & SPI_CS_HIGH)); ++ !((spi->mode & SPI_CS_HIGH) || ++ spi_gpio->cs_dont_invert)); + } + + if (!status) +@@ -322,10 +345,43 @@ static int spi_gpio_request(struct device *dev, struct spi_gpio *spi_gpio) + if (IS_ERR(spi_gpio->miso)) + return PTR_ERR(spi_gpio->miso); + ++ spi_gpio->sck_idle_input = device_property_read_bool(dev, "sck-idle-input"); + spi_gpio->sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW); + return PTR_ERR_OR_ZERO(spi_gpio->sck); + } + ++/* ++ * In order to implement "sck-idle-input" (which requires SCK ++ * direction and CS level to be switched in a particular order), ++ * we need to control GPIO chip selects from within this driver. ++ */ ++ ++static int spi_gpio_probe_get_cs_gpios(struct device *dev, ++ struct spi_master *master, ++ bool gpio_defines_polarity) ++{ ++ int i; ++ struct spi_gpio *spi_gpio = spi_master_get_devdata(master); ++ ++ spi_gpio->cs_dont_invert = gpio_defines_polarity; ++ spi_gpio->cs_gpios = devm_kcalloc(dev, master->num_chipselect, ++ sizeof(*spi_gpio->cs_gpios), ++ GFP_KERNEL); ++ if (!spi_gpio->cs_gpios) ++ return -ENOMEM; ++ ++ for (i = 0; i < master->num_chipselect; i++) { ++ spi_gpio->cs_gpiosi = ++ devm_gpiod_get_index(dev, "cs", i, ++ gpio_defines_polarity ? ++ GPIOD_OUT_LOW : GPIOD_OUT_HIGH); ++ if (IS_ERR(spi_gpio->cs_gpiosi)) ++ return PTR_ERR(spi_gpio->cs_gpiosi); ++ } ++ ++ return 0; ++} ++ + #ifdef CONFIG_OF + static const struct of_device_id spi_gpio_dt_ids = { + { .compatible = "spi-gpio" }, +@@ -336,10 +392,12 @@ MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids); + static int spi_gpio_probe_dt(struct platform_device *pdev, + struct spi_controller *host) + { +- host->dev.of_node = pdev->dev.of_node; +- host->use_gpio_descriptors = true; ++ struct device *dev = &pdev->dev; + +- return 0; ++ host->dev.of_node = dev->of_node; ++ host->num_chipselect = gpiod_count(dev, "cs"); ++ ++ return spi_gpio_probe_get_cs_gpios(dev, host, true); + } + #else + static inline int spi_gpio_probe_dt(struct platform_device *pdev, +@@ -354,8 +412,6 @@ static int spi_gpio_probe_pdata(struct platform_device *pdev, + { + struct device *dev = &pdev->dev; + struct spi_gpio_platform_data *pdata = dev_get_platdata(dev); +- struct spi_gpio *spi_gpio = spi_controller_get_devdata(host); +- int i; + + #ifdef GENERIC_BITBANG + if (!pdata || !pdata->num_chipselect) +@@ -367,20 +423,7 @@ static int spi_gpio_probe_pdata(struct platform_device *pdev, + */ + host->num_chipselect = pdata->num_chipselect ?: 1; + +- spi_gpio->cs_gpios = devm_kcalloc(dev, host->num_chipselect, +- sizeof(*spi_gpio->cs_gpios), +- GFP_KERNEL); +- if (!spi_gpio->cs_gpios) +- return -ENOMEM; +- +- for (i = 0; i < host->num_chipselect; i++) { +- spi_gpio->cs_gpiosi = devm_gpiod_get_index(dev, "cs", i, +- GPIOD_OUT_HIGH); +- if (IS_ERR(spi_gpio->cs_gpiosi)) +- return PTR_ERR(spi_gpio->cs_gpiosi); +- } +- +- return 0; ++ return spi_gpio_probe_get_cs_gpios(dev, host, false); + } + + static int spi_gpio_probe(struct platform_device *pdev) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c -index 8c261eac2cee..4436fd319df3 100644 +index 1e08cd571d21..15d95f7172e2 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c -@@ -3338,6 +3338,7 @@ static int __spi_validate_bits_per_word(struct spi_controller *ctlr, +@@ -3736,6 +3736,7 @@ static int spi_set_cs_timing(struct spi_device *spi) */ int spi_setup(struct spi_device *spi) { + struct spi_controller *ctlr = spi->controller; unsigned bad_bits, ugly_bits; - int status; + int status = 0; -@@ -3355,6 +3356,14 @@ int spi_setup(struct spi_device *spi) +@@ -3756,6 +3757,14 @@ int spi_setup(struct spi_device *spi) (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL))) return -EINVAL; @@ -99306,14 +153746,14 @@ + 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, + /* + * Help drivers fail *cleanly* when they need options + * that aren't supported with their current controller. diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c -index 859910ec8d9f..a262479f0a92 100644 +index d13dc15cc191..6fae5510b58f 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c -@@ -402,7 +402,6 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +@@ -424,7 +424,6 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) else retval = get_user(tmp, (u32 __user *)arg); if (retval == 0) { @@ -99321,26 +153761,34 @@ u32 save = spi->mode; if (tmp & ~SPI_MODE_MASK) { -@@ -410,10 +409,6 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +@@ -432,10 +431,6 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) break; } - if (ctlr->use_gpio_descriptors && ctlr->cs_gpiods && -- ctlr->cs_gpiodsspi->chip_select) +- ctlr->cs_gpiodsspi_get_chipselect(spi, 0)) - tmp |= SPI_CS_HIGH; - tmp |= spi->mode & ~SPI_MODE_MASK; - spi->mode = (u16)tmp; + spi->mode = tmp & SPI_MODE_USER_MASK; retval = spi_setup(spi); -@@ -737,7 +732,7 @@ static int spidev_probe(struct spi_device *spi) - * 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); +@@ -704,6 +699,7 @@ static const struct file_operations spidev_fops = { + static struct class *spidev_class; + static const struct spi_device_id spidev_spi_ids = { ++ { .name = "spidev" }, + { .name = "dh2228fv" }, + { .name = "ltc2488" }, + { .name = "sx1301" }, +@@ -724,7 +720,7 @@ MODULE_DEVICE_TABLE(spi, spidev_spi_ids); + */ + static int spidev_of_check(struct device *dev) + { +- if (device_property_match_string(dev, "compatible", "spidev") < 0) ++ if (1 || device_property_match_string(dev, "compatible", "spidev") < 0) + return 0; + + dev_err(dev, "spidev listed directly in DT is not supported\n"); diff --git a/drivers/staging/fbtft/fb_st7735r.c b/drivers/staging/fbtft/fb_st7735r.c index 9670a8989b91..1a3219657cbb 100644 --- a/drivers/staging/fbtft/fb_st7735r.c @@ -99410,24 +153858,23 @@ MODULE_DESCRIPTION("FB driver for the ST7735R LCD Controller"); MODULE_AUTHOR("Noralf Tronnes"); diff --git a/drivers/staging/fbtft/fb_st7789v.c b/drivers/staging/fbtft/fb_st7789v.c -index 3a280cc1892c..af4e975e7b30 100644 +index 861a154144e6..3bcd9ee17b6c 100644 --- a/drivers/staging/fbtft/fb_st7789v.c +++ b/drivers/staging/fbtft/fb_st7789v.c -@@ -66,6 +66,12 @@ enum st7789v_command { - #define MADCTL_MX BIT(6) /* bitmask for column address order */ - #define MADCTL_MY BIT(7) /* bitmask for page address order */ +@@ -75,6 +75,11 @@ enum st7789v_command { + static struct completion panel_te; /* completion for panel TE line */ + static int irq_te; /* Linux IRQ for LCD TE line */ +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 - * -@@ -145,6 +151,22 @@ static int init_display(struct fbtft_par *par) - return 0; + + static irqreturn_t panel_te_handler(int irq, void *data) + { +@@ -261,6 +266,22 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) + return ret; } +static void minipitft13_set_addr_win(struct fbtft_par *par, int xs, int ys, @@ -99449,7 +153896,7 @@ /** * set_var() - apply LCD properties like rotation and BGR mode * -@@ -155,20 +177,32 @@ static int init_display(struct fbtft_par *par) +@@ -271,20 +292,32 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) static int set_var(struct fbtft_par *par) { u8 madctl_par = 0; @@ -99482,7 +153929,7 @@ break; default: return -EINVAL; -@@ -265,7 +299,16 @@ static struct fbtft_display display = { +@@ -382,7 +415,16 @@ static struct fbtft_display display = { }, }; @@ -99501,7 +153948,7 @@ MODULE_ALIAS("spi:" DRVNAME); MODULE_ALIAS("platform:" DRVNAME); diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c -index d0c8d85f3db0..39ecd7c7ec61 100644 +index eac1d570f437..de53031bee64 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -24,6 +24,8 @@ @@ -99513,7 +153960,7 @@ #include <video/mipi_display.h> -@@ -1187,6 +1189,7 @@ static struct fbtft_platform_data *fbtft_properties_read(struct device *dev) +@@ -1183,6 +1185,7 @@ static struct fbtft_platform_data *fbtft_properties_read(struct device *dev) * @display: Display properties * @sdev: SPI device * @pdev: Platform device @@ -99521,7 +153968,7 @@ * * Allocates, initializes and registers a framebuffer * -@@ -1196,12 +1199,15 @@ static struct fbtft_platform_data *fbtft_properties_read(struct device *dev) +@@ -1192,12 +1195,15 @@ static struct fbtft_platform_data *fbtft_properties_read(struct device *dev) */ int fbtft_probe_common(struct fbtft_display *display, struct spi_device *sdev, @@ -99538,7 +153985,7 @@ int ret; if (sdev) -@@ -1217,6 +1223,14 @@ int fbtft_probe_common(struct fbtft_display *display, +@@ -1213,6 +1219,14 @@ int fbtft_probe_common(struct fbtft_display *display, pdata = fbtft_properties_read(dev); if (IS_ERR(pdata)) return PTR_ERR(pdata); @@ -99554,7 +154001,7 @@ info = fbtft_framebuffer_alloc(display, dev, pdata); diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h -index 06afaa9d505b..c6ec045a447c 100644 +index 2c2b5f1c1df3..7492c1abfdec 100644 --- a/drivers/staging/fbtft/fbtft.h +++ b/drivers/staging/fbtft/fbtft.h @@ -251,7 +251,8 @@ void fbtft_register_backlight(struct fbtft_par *par); @@ -99564,26 +154011,60 @@ - 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); + void fbtft_remove_common(struct device *dev, struct fb_info *info); /* fbtft-io.c */ -@@ -272,11 +273,13 @@ void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...); +@@ -272,42 +273,25 @@ void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...); void fbtft_write_reg16_bus8(struct fbtft_par *par, int len, ...); void fbtft_write_reg16_bus16(struct fbtft_par *par, int len, ...); +-#define FBTFT_DT_TABLE(_compatible) \ +-static const struct of_device_id dt_ids = { \ +- { .compatible = _compatible }, \ +- {}, \ +-}; \ +-MODULE_DEVICE_TABLE(of, dt_ids); +- +-#define FBTFT_SPI_DRIVER(_name, _compatible, _display, _spi_ids) \ +- \ +-static int fbtft_driver_probe_spi(struct spi_device *spi) \ +-{ \ +- return fbtft_probe_common(_display, spi, NULL); \ +-} \ +- \ +-static void fbtft_driver_remove_spi(struct spi_device *spi) \ +-{ \ +- struct fb_info *info = spi_get_drvdata(spi); \ +- \ +- fbtft_remove_common(&spi->dev, info); \ +-} \ +- \ +-static struct spi_driver fbtft_driver_spi_driver = { \ +- .driver = { \ +- .name = _name, \ +- .of_match_table = dt_ids, \ +- }, \ +- .id_table = _spi_ids, \ +- .probe = fbtft_driver_probe_spi, \ +- .remove = fbtft_driver_remove_spi, \ +-}; +- -#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); \ ++ \ ++static int fbtft_driver_probe_spi(struct spi_device *spi) \ ++{ \ + return fbtft_probe_common(_display, spi, NULL, dt_ids); \ - } \ - \ - static int fbtft_driver_remove_spi(struct spi_device *spi) \ -@@ -288,7 +291,7 @@ static int fbtft_driver_remove_spi(struct spi_device *spi) \ ++} \ ++ \ ++static void fbtft_driver_remove_spi(struct spi_device *spi) \ ++{ \ ++ struct fb_info *info = spi_get_drvdata(spi); \ ++ \ ++ fbtft_remove_common(&spi->dev, info); \ ++} \ \ static int fbtft_driver_probe_pdev(struct platform_device *pdev) \ { \ @@ -99592,12 +154073,11 @@ } \ \ static int fbtft_driver_remove_pdev(struct platform_device *pdev) \ -@@ -298,8 +301,16 @@ static int fbtft_driver_remove_pdev(struct platform_device *pdev) \ - return fbtft_remove_common(&pdev->dev, info); \ +@@ -318,9 +302,30 @@ static int fbtft_driver_remove_pdev(struct platform_device *pdev) \ + return 0; \ } \ \ --static const struct of_device_id dt_ids = { \ -- { .compatible = _compatible }, \ +-FBTFT_DT_TABLE(_compatible) \ +static const struct of_device_id dt_ids = { + +#define FBTFT_COMPATIBLE(_compatible) \ @@ -99608,12 +154088,67 @@ + +#define FBTFT_REGISTER_DRIVER_END(_name, _display) \ + \ - {}, \ - }; \ ++ {}, \ ++}; \ + \ +-FBTFT_SPI_DRIVER(_name, _compatible, _display, NULL) \ ++MODULE_DEVICE_TABLE(of, dt_ids); \ ++ \ ++ \ ++static struct spi_driver fbtft_driver_spi_driver = { \ ++ .driver = { \ ++ .name = _name, \ ++ .of_match_table = dt_ids, \ ++ }, \ ++ .probe = fbtft_driver_probe_spi, \ ++ .remove = fbtft_driver_remove_spi, \ ++}; \ \ -@@ -347,6 +358,11 @@ static void __exit fbtft_driver_module_exit(void) \ - module_init(fbtft_driver_module_init); \ - module_exit(fbtft_driver_module_exit); + static struct platform_driver fbtft_driver_platform_driver = { \ + .driver = { \ +@@ -356,18 +361,49 @@ module_exit(fbtft_driver_module_exit); + + #define FBTFT_REGISTER_SPI_DRIVER(_name, _comp_vend, _comp_dev, _display) \ + \ +-FBTFT_DT_TABLE(_comp_vend "," _comp_dev) \ ++static const struct of_device_id dt_ids = { \ ++ { .compatible = _comp_vend "," _comp_dev }, \ ++ {}, \ ++}; \ ++ \ ++static int fbtft_driver_probe_spi(struct spi_device *spi) \ ++{ \ ++ return fbtft_probe_common(_display, spi, NULL, dt_ids); \ ++} \ ++ \ ++static void fbtft_driver_remove_spi(struct spi_device *spi) \ ++{ \ ++ struct fb_info *info = spi_get_drvdata(spi); \ ++ \ ++ fbtft_remove_common(&spi->dev, info); \ ++} \ ++ \ ++MODULE_DEVICE_TABLE(of, dt_ids); \ + \ + static const struct spi_device_id spi_ids = { \ + { .name = _comp_dev }, \ + {}, \ + }; \ ++ \ + MODULE_DEVICE_TABLE(spi, spi_ids); \ + \ +-FBTFT_SPI_DRIVER(_name, _comp_vend "," _comp_dev, _display, spi_ids) \ ++static struct spi_driver fbtft_driver_spi_driver = { \ ++ .driver = { \ ++ .name = _name, \ ++ .of_match_table = dt_ids, \ ++ }, \ ++ .id_table = spi_ids, \ ++ .probe = fbtft_driver_probe_spi, \ ++ .remove = fbtft_driver_remove_spi, \ ++}; \ + \ + module_spi_driver(fbtft_driver_spi_driver); +#define FBTFT_REGISTER_DRIVER(_name, _compatible, _display) \ + FBTFT_REGISTER_DRIVER_START(_display) \ @@ -99624,10 +154159,10 @@ /* shorthand debug levels */ diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig -index 747c6cf1d795..a0c5ec9b3968 100644 +index bc6c7b248f86..89f5081454ef 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig -@@ -34,6 +34,8 @@ source "drivers/staging/media/omap4iss/Kconfig" +@@ -36,6 +36,8 @@ source "drivers/staging/media/omap4iss/Kconfig" source "drivers/staging/media/rkvdec/Kconfig" @@ -99635,22 +154170,22 @@ + source "drivers/staging/media/sunxi/Kconfig" - source "drivers/staging/media/tegra-vde/Kconfig" + source "drivers/staging/media/tegra-video/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile -index b59571826ba6..51a921132ca7 100644 +index 1a4c3a062e3d..5f9a87005db7 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile -@@ -5,6 +5,7 @@ obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/ +@@ -6,6 +6,7 @@ obj-$(CONFIG_VIDEO_MAX96712) += max96712/ 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/ + obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ diff --git a/drivers/staging/media/rpivid/Kconfig b/drivers/staging/media/rpivid/Kconfig new file mode 100644 -index 000000000000..304c3edf0e71 +index 000000000000..f9a8a4491301 --- /dev/null +++ b/drivers/staging/media/rpivid/Kconfig @@ -0,0 +1,16 @@ @@ -99658,7 +154193,7 @@ + +config VIDEO_RPIVID + tristate "Rpi H265 driver" -+ depends on VIDEO_DEV && VIDEO_V4L2 ++ depends on VIDEO_DEV && VIDEO_DEV + depends on OF + select MEDIA_CONTROLLER + select MEDIA_CONTROLLER_REQUEST_API @@ -99683,10 +154218,10 @@ + rpivid_hw.o rpivid_h265.o diff --git a/drivers/staging/media/rpivid/rpivid.c b/drivers/staging/media/rpivid/rpivid.c new file mode 100644 -index 000000000000..848a1823ec7f +index 000000000000..70b9aa1ac48d --- /dev/null +++ b/drivers/staging/media/rpivid/rpivid.c -@@ -0,0 +1,447 @@ +@@ -0,0 +1,466 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Raspberry Pi HEVC driver @@ -99726,43 +154261,55 @@ +static const struct rpivid_control rpivid_ctrls = { + { + .cfg = { -+ .id = V4L2_CID_MPEG_VIDEO_HEVC_SPS, ++ .id = V4L2_CID_STATELESS_HEVC_SPS, + .ops = &rpivid_hevc_sps_ctrl_ops, + }, + .required = true, + }, + { + .cfg = { -+ .id = V4L2_CID_MPEG_VIDEO_HEVC_PPS, ++ .id = V4L2_CID_STATELESS_HEVC_PPS, + .ops = &rpivid_hevc_pps_ctrl_ops, + }, + .required = true, + }, + { + .cfg = { -+ .id = V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX, ++ .id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX, + }, + .required = false, + }, + { + .cfg = { -+ .id = V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS, ++ .id = V4L2_CID_STATELESS_HEVC_DECODE_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, ++ .name = "Slice param array", ++ .id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS, ++ .type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS, ++ .flags = V4L2_CTRL_FLAG_DYNAMIC_ARRAY, ++ .dims = { 0x1000 }, ++ }, ++ .required = true, ++ }, ++ { ++ .cfg = { ++ .id = V4L2_CID_STATELESS_HEVC_DECODE_MODE, ++ .min = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED, ++ .max = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED, ++ .def = V4L2_STATELESS_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, ++ .id = V4L2_CID_STATELESS_HEVC_START_CODE, ++ .min = V4L2_STATELESS_HEVC_START_CODE_NONE, ++ .max = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B, ++ .def = V4L2_STATELESS_HEVC_START_CODE_NONE, + }, + .required = false, + }, @@ -100037,6 +154584,13 @@ + snprintf(vfd->name, sizeof(vfd->name), "%s", rpivid_video_device.name); + video_set_drvdata(vfd, dev); + ++ ret = dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(36)); ++ if (ret) { ++ v4l2_err(&dev->v4l2_dev, ++ "Failed dma_set_mask_and_coherent\n"); ++ goto err_v4l2; ++ } ++ + dev->m2m_dev = v4l2_m2m_init(&rpivid_m2m_ops); + if (IS_ERR(dev->m2m_dev)) { + v4l2_err(&dev->v4l2_dev, @@ -100136,10 +154690,10 @@ +MODULE_DESCRIPTION("Raspberry Pi HEVC V4L2 driver"); diff --git a/drivers/staging/media/rpivid/rpivid.h b/drivers/staging/media/rpivid/rpivid.h new file mode 100644 -index 000000000000..31d320b596b4 +index 000000000000..9d6c2adb331b --- /dev/null +++ b/drivers/staging/media/rpivid/rpivid.h -@@ -0,0 +1,202 @@ +@@ -0,0 +1,203 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Raspberry Pi HEVC driver @@ -100192,6 +154746,7 @@ + u32 slice_ents; + const struct v4l2_ctrl_hevc_sps *sps; + const struct v4l2_ctrl_hevc_pps *pps; ++ const struct v4l2_ctrl_hevc_decode_params *dec; + const struct v4l2_ctrl_hevc_slice_params *slice_params; + const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix; +}; @@ -100231,7 +154786,6 @@ + struct v4l2_pix_format_mplane dst_fmt; + int dst_fmt_set; + -+ struct clk_request *clk_req; + int src_stream_on; + int dst_stream_on; + @@ -100327,6 +154881,7 @@ + void __iomem *base_h265; + + struct clk *clock; ++ unsigned long max_clock_rate; + + int cache_align; + @@ -100344,10 +154899,10 @@ +#endif diff --git a/drivers/staging/media/rpivid/rpivid_dec.c b/drivers/staging/media/rpivid/rpivid_dec.c new file mode 100644 -index 000000000000..fa8af01d753b +index 000000000000..e51408dabbdb --- /dev/null +++ b/drivers/staging/media/rpivid/rpivid_dec.c -@@ -0,0 +1,81 @@ +@@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Raspberry Pi HEVC driver @@ -100396,19 +154951,34 @@ + + switch (ctx->src_fmt.pixelformat) { + case V4L2_PIX_FMT_HEVC_SLICE: ++ { ++ const struct v4l2_ctrl *ctrl; ++ + run.h265.sps = + rpivid_find_control_data(ctx, -+ V4L2_CID_MPEG_VIDEO_HEVC_SPS); ++ V4L2_CID_STATELESS_HEVC_SPS); + run.h265.pps = + rpivid_find_control_data(ctx, -+ V4L2_CID_MPEG_VIDEO_HEVC_PPS); -+ run.h265.slice_params = ++ V4L2_CID_STATELESS_HEVC_PPS); ++ run.h265.dec = + rpivid_find_control_data(ctx, -+ V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS); ++ V4L2_CID_STATELESS_HEVC_DECODE_PARAMS); ++ ++ ctrl = rpivid_find_ctrl(ctx, ++ V4L2_CID_STATELESS_HEVC_SLICE_PARAMS); ++ if (!ctrl || !ctrl->elems) { ++ v4l2_err(&dev->v4l2_dev, "%s: Missing slice params\n", ++ __func__); ++ goto fail; ++ } ++ run.h265.slice_ents = ctrl->elems; ++ run.h265.slice_params = ctrl->p_cur.p; ++ + run.h265.scaling_matrix = + rpivid_find_control_data(ctx, -+ V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX); ++ V4L2_CID_STATELESS_HEVC_SCALING_MATRIX); + break; ++ } + + default: + break; @@ -100456,10 +155026,10 @@ +#endif diff --git a/drivers/staging/media/rpivid/rpivid_h265.c b/drivers/staging/media/rpivid/rpivid_h265.c new file mode 100644 -index 000000000000..17b3a565c315 +index 000000000000..81ff98df1322 --- /dev/null +++ b/drivers/staging/media/rpivid/rpivid_h265.c -@@ -0,0 +1,2688 @@ +@@ -0,0 +1,2706 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Raspberry Pi HEVC driver @@ -100707,13 +155277,15 @@ + + // Slice vars + unsigned int slice_idx; -+ bool frame_end; + bool slice_temporal_mvp; /* Slice flag but constant for frame */ ++ bool use_aux; ++ bool mk_aux; + + // 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; ++ const struct v4l2_ctrl_hevc_decode_params *dec; + unsigned int nb_refs2; + unsigned int slice_qp; + unsigned int max_num_merge_cand; // 0 if I-slice @@ -101086,7 +155658,7 @@ + // 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; ++ unsigned int offset = s->sh->data_byte_offset; + const unsigned int len = (s->sh->bit_size + 7) / 8 - offset; + dma_addr_t addr; + @@ -101201,7 +155773,8 @@ + V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED)) + << 24)); + -+ if ((sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED) != 0) ++ if (!s->start_ts && ++ (sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED) != 0) + write_scaling_factors(de); + + if (!s->dependent_slice_segment_flag) { @@ -101240,18 +155813,12 @@ +// 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) ++ const s32 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 - dpbidxi.pic_order_cnt0) & 0x8000) != 0) ++ if (cur_poc < dpbidxi.pic_order_cnt_val) + return 0; + } + return 1; @@ -101261,6 +155828,7 @@ + const struct rpivid_dec_state *const s) +{ + const struct v4l2_ctrl_hevc_slice_params *const sh = s->sh; ++ const struct v4l2_ctrl_hevc_decode_params *const dec = s->dec; + int weighted_pred_flag, idx; + u16 cmd_slice; + unsigned int collocated_from_l0_flag; @@ -101287,9 +155855,9 @@ + 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_refsL0, ++ has_backward(dec->dpb, sh->ref_idx_l0, s->nb_refsL0, + sh->slice_pic_order_cnt) && -+ has_backward(sh->dpb, sh->ref_idx_l1, s->nb_refsL1, ++ has_backward(dec->dpb, sh->ref_idx_l1, s->nb_refsL1, + sh->slice_pic_order_cnt); + cmd_slice |= no_backward_pred_flag << 10; + msg_slice(de, cmd_slice); @@ -101317,11 +155885,11 @@ + + msg_slice(de, + dpb_no | -+ (sh->dpbdpb_no.rps == -+ V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR ? ++ ((dec->dpbdpb_no.flags & ++ V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE) ? + (1 << 4) : 0) | + (weighted_pred_flag ? (3 << 5) : 0)); -+ msg_slice(de, sh->dpbdpb_no.pic_order_cnt0); ++ msg_slice(de, dec->dpbdpb_no.pic_order_cnt_val & 0xffff); + + if (weighted_pred_flag) { + const struct v4l2_hevc_pred_weight_table @@ -101363,11 +155931,11 @@ + // "L1%d=dpb%d\n", idx, dpb_no); + msg_slice(de, + dpb_no | -+ (sh->dpbdpb_no.rps == -+ V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR ? ++ ((dec->dpbdpb_no.flags & ++ V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE) ? + (1 << 4) : 0) | + (weighted_pred_flag ? (3 << 5) : 0)); -+ msg_slice(de, sh->dpbdpb_no.pic_order_cnt0); ++ msg_slice(de, dec->dpbdpb_no.pic_order_cnt_val & 0xffff); + if (weighted_pred_flag) { + const struct v4l2_hevc_pred_weight_table + *const w = &sh->pred_weight_table; @@ -101571,7 +156139,8 @@ + * next chunk code simpler + */ +static int wpp_decode_slice(struct rpivid_dec_env *const de, -+ const struct rpivid_dec_state *const s) ++ const struct rpivid_dec_state *const s, ++ bool last_slice) +{ + bool reset_qp_y = true; + const bool indep = !s->dependent_slice_segment_flag; @@ -101610,7 +156179,7 @@ + 0, 0, s->start_ctb_x, s->start_ctb_y, + s->slice_qp, slice_reg_const(s)); + -+ if (s->frame_end) { ++ if (last_slice) { + rv = wpp_entry_fill(de, s, s->ctb_height - 1); + if (rv) + return rv; @@ -101689,7 +156258,8 @@ +} + +static int decode_slice(struct rpivid_dec_env *const de, -+ const struct rpivid_dec_state *const s) ++ const struct rpivid_dec_state *const s, ++ bool last_slice) +{ + bool reset_qp_y; + unsigned int tile_x = ctb_to_tile_x(s, s->start_ctb_x); @@ -101735,7 +156305,7 @@ + * 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) { ++ if (last_slice) { + rv = tile_entry_fill(de, s, + s->tile_width - 1, + s->tile_height - 1); @@ -102115,7 +156685,7 @@ + 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) ++ if (s->mk_aux) + c |= BIT(15); /* Write motion vectors to external memory */ + c |= (pps->log2_parallel_merge_level_minus2 + 2) << 16; + if (s->slice_temporal_mvp) @@ -102127,35 +156697,44 @@ + return c; +} + ++static inline bool is_ref_unit_type(const unsigned int nal_unit_type) ++{ ++ /* From Table 7-1 ++ * True for 1, 3, 5, 7, 9, 11, 13, 15 ++ */ ++ return (nal_unit_type & ~0xe) != 0; ++} ++ +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; ++ const struct v4l2_ctrl_hevc_decode_params *const dec = ++ run->h265.dec; ++ /* sh0 used where slice header contents should be constant over all ++ * slices, or first slice of frame ++ */ ++ const struct v4l2_ctrl_hevc_slice_params *const sh0 = ++ run->h265.slice_params; + struct rpivid_q_aux *dpb_q_auxV4L2_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; ++ bool frame_end; + + xtrace_in(dev, de); ++ s->sh = NULL; // Avoid use until in the slice loop + -+// pred_weight_table = &sh->pred_weight_table; -+ -+ s->frame_end = ++ frame_end = + ((run->src->flags & V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF) == 0); + -+ slice_temporal_mvp = (sh->flags & ++ slice_temporal_mvp = (sh0->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 @@ -102163,7 +156742,7 @@ + default: + v4l2_err(&dev->v4l2_dev, "%s: Unexpected state: %d\n", + __func__, de->state); -+ /* FALLTHRU */ ++ fallthrough; + case RPIVID_DECODE_ERROR_CONTINUE: + // Uncleared error - fail now + goto fail; @@ -102284,11 +156863,21 @@ + */ + s->slice_temporal_mvp = slice_temporal_mvp; + ++ /* ++ * Need Aux ents for all (ref) DPB ents if temporal MV could ++ * be enabled for any pic ++ */ ++ s->use_aux = ((s->sps.flags & ++ V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED) != 0); ++ s->mk_aux = s->use_aux && ++ (s->sps.sps_max_sub_layers_minus1 >= sh0->nuh_temporal_id_plus1 || ++ is_ref_unit_type(sh0->nal_unit_type)); ++ + // 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; ++ de->rpi_currpoc = sh0->slice_pic_order_cnt; + + if (s->sps.flags & + V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED) { @@ -102297,17 +156886,17 @@ + + s->slice_idx = 0; + -+ if (sh->slice_segment_addr != 0) { ++ if (sh0->slice_segment_addr != 0) { + v4l2_warn(&dev->v4l2_dev, + "New frame but segment_addr=%d\n", -+ sh->slice_segment_addr); ++ sh0->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) { ++ if (!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, @@ -102331,21 +156920,7 @@ + s->src_addr = 0; + s->src_buf = NULL; + -+ if (run->src->planes0.bytesused < (sh->bit_size + 7) / 8) { -+ v4l2_warn(&dev->v4l2_dev, -+ "Bit size %d > bytesused %d\n", -+ sh->bit_size, run->src->planes0.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) ++ if (frame_end) + s->src_addr = vb2_dma_contig_plane_dma_addr(&run->src->vb2_buf, + 0); + if (!s->src_addr) @@ -102356,43 +156931,64 @@ + } + + // 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 ? ++ s->dec = dec; ++ for (i = 0; i != run->h265.slice_ents; ++i) { ++ const struct v4l2_ctrl_hevc_slice_params *const sh = sh0 + i; ++ const bool last_slice = frame_end && i + 1 == run->h265.slice_ents; ++ ++ s->sh = sh; ++ ++ if (run->src->planes0.bytesused < (sh->bit_size + 7) / 8) { ++ v4l2_warn(&dev->v4l2_dev, ++ "Bit size %d > bytesused %d\n", ++ sh->bit_size, run->src->planes0.bytesused); ++ goto fail; ++ } ++ if (sh->data_byte_offset >= sh->bit_size / 8) { ++ v4l2_warn(&dev->v4l2_dev, ++ "Bit size %u < Byte offset %u * 8\n", ++ sh->bit_size, sh->data_byte_offset); ++ goto fail; ++ } ++ ++ s->slice_qp = 26 + s->pps.init_qp_minus26 + sh->slice_qp_delta; ++ s->max_num_merge_cand = sh->slice_type == HEVC_SLICE_I ? ++ 0 : ++ (5 - sh->five_minus_max_num_merge_cand); ++ s->dependent_slice_segment_flag = ++ ((sh->flags & ++ V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT) != 0); ++ ++ s->nb_refs0 = (sh->slice_type == HEVC_SLICE_I) ? ++ 0 : ++ sh->num_ref_idx_l0_active_minus1 + 1; ++ s->nb_refs1 = (sh->slice_type != HEVC_SLICE_B) ? + 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_refs0 = (sh->slice_type == HEVC_SLICE_I) ? -+ 0 : -+ sh->num_ref_idx_l0_active_minus1 + 1; -+ s->nb_refs1 = (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_tssh->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_rss->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; ++ sh->num_ref_idx_l1_active_minus1 + 1; + -+ 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->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_tssh->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_rss->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, last_slice); ++ else ++ rv = decode_slice(de, s, last_slice); ++ if (rv) ++ goto fail; ++ ++ ++s->slice_idx; ++ } + -+ if (!s->frame_end) { ++ if (!frame_end) { + xtrace_ok(dev, de); + return; + } @@ -102400,15 +156996,6 @@ + // 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 @@ -102427,27 +157014,22 @@ + 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->dpbi.timestamp, 0); -+ struct vb2_buffer *buf = buffer_index < 0 ? -+ NULL : -+ vb2_get_buffer(vq, buffer_index); -+ ++ for (i = 0; i < dec->num_active_dpb_entries; ++i) { ++ struct vb2_buffer *buf = vb2_find_buffer(vq, dec->dpbi.timestamp); + if (!buf) { + v4l2_warn(&dev->v4l2_dev, -+ "Missing DPB ent %d, timestamp=%lld, index=%d\n", -+ i, (long long)sh->dpbi.timestamp, -+ buffer_index); ++ "Missing DPB ent %d, timestamp=%lld\n", ++ i, (long long)dec->dpbi.timestamp); + continue; + } + -+ if (use_aux) { ++ if (s->use_aux) { ++ int buffer_index = buf->index; + dpb_q_auxi = aux_q_ref_idx(ctx, buffer_index); + if (!dpb_q_auxi) + v4l2_warn(&dev->v4l2_dev, + "Missing DPB AUX ent %d, timestamp=%lld, index=%d\n", -+ i, (long long)sh->dpbi.timestamp, ++ i, (long long)dec->dpbi.timestamp, + buffer_index); + } + @@ -102464,9 +157046,7 @@ + // 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 ++ if (s->mk_aux) { + s->frame_aux = aux_q_new(ctx, run->dst->vb2_buf.index); + + if (!s->frame_aux) { @@ -102479,11 +157059,11 @@ + } + + if (de->dpbno_col != ~0U) { -+ if (de->dpbno_col >= sh->num_active_dpb_entries) { ++ if (de->dpbno_col >= dec->num_active_dpb_entries) { + v4l2_err(&dev->v4l2_dev, + "Col ref index %d >= %d\n", + de->dpbno_col, -+ sh->num_active_dpb_entries); ++ dec->num_active_dpb_entries); + } else { + // Standard requires that the col pic is + // constant for the duration of the pic @@ -102511,8 +157091,8 @@ +fail: + if (de) + // Actual error reporting happens in Trigger -+ de->state = s->frame_end ? RPIVID_DECODE_ERROR_DONE : -+ RPIVID_DECODE_ERROR_CONTINUE; ++ de->state = frame_end ? RPIVID_DECODE_ERROR_DONE : ++ RPIVID_DECODE_ERROR_CONTINUE; + xtrace_fail(dev, de); +} + @@ -102947,11 +157527,19 @@ + for (i = 0; i != ARRAY_SIZE(ctx->pu_bufs); ++i) { + // Don't actually need a kernel mapping here + if (gptr_alloc(dev, ctx->pu_bufs + i, pu_alloc, -+ DMA_ATTR_NO_KERNEL_MAPPING)) ++ DMA_ATTR_NO_KERNEL_MAPPING)) { ++ v4l2_err(&dev->v4l2_dev, ++ "Failed to alloc %#zx PU%d buffer\n", ++ pu_alloc, i); + goto fail; ++ } + if (gptr_alloc(dev, ctx->coeff_bufs + i, coeff_alloc, -+ DMA_ATTR_NO_KERNEL_MAPPING)) ++ DMA_ATTR_NO_KERNEL_MAPPING)) { ++ v4l2_err(&dev->v4l2_dev, ++ "Failed to alloc %#zx Coeff%d buffer\n", ++ pu_alloc, i); + goto fail; ++ } + } + aux_q_init(ctx); + @@ -102972,7 +157560,7 @@ + switch (!de ? RPIVID_DECODE_ERROR_CONTINUE : de->state) { + case RPIVID_DECODE_SLICE_START: + de->state = RPIVID_DECODE_SLICE_CONTINUE; -+ /* FALLTHRU */ ++ fallthrough; + case RPIVID_DECODE_SLICE_CONTINUE: + v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx, + VB2_BUF_STATE_DONE); @@ -102982,11 +157570,11 @@ + default: + v4l2_err(&dev->v4l2_dev, "%s: Unexpected state: %d\n", __func__, + de->state); -+ /* FALLTHRU */ ++ fallthrough; + case RPIVID_DECODE_ERROR_DONE: + ctx->dec0 = NULL; + dec_env_delete(de); -+ /* FALLTHRU */ ++ fallthrough; + case RPIVID_DECODE_ERROR_CONTINUE: + xtrace_fin(dev, de); + v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx, @@ -103150,10 +157738,10 @@ + diff --git a/drivers/staging/media/rpivid/rpivid_hw.c b/drivers/staging/media/rpivid/rpivid_hw.c new file mode 100644 -index 000000000000..e7d1793105c5 +index 000000000000..1026fa6b8b04 --- /dev/null +++ b/drivers/staging/media/rpivid/rpivid_hw.c -@@ -0,0 +1,366 @@ +@@ -0,0 +1,383 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Raspberry Pi HEVC driver @@ -103181,6 +157769,8 @@ +#include <media/videobuf2-core.h> +#include <media/v4l2-mem2mem.h> + ++#include <soc/bcm2835/raspberrypi-firmware.h> ++ +#include "rpivid.h" +#include "rpivid_hw.h" + @@ -103459,6 +158049,8 @@ + +int rpivid_hw_probe(struct rpivid_dev *dev) +{ ++ struct rpi_firmware *firmware; ++ struct device_node *node; + struct resource *res; + __u32 irq_stat; + int irq_dec; @@ -103487,6 +158079,19 @@ + if (IS_ERR(dev->clock)) + return PTR_ERR(dev->clock); + ++ node = rpi_firmware_find_node(); ++ if (!node) ++ return -EINVAL; ++ ++ firmware = rpi_firmware_get(node); ++ of_node_put(node); ++ if (!firmware) ++ return -EPROBE_DEFER; ++ ++ dev->max_clock_rate = rpi_firmware_clk_get_max_rate(firmware, ++ RPI_FIRMWARE_HEVC_CLK_ID); ++ rpi_firmware_put(firmware); ++ + dev->cache_align = dma_get_cache_alignment(); + + // Disable IRQs & reset anything pending @@ -103831,10 +158436,10 @@ +#endif diff --git a/drivers/staging/media/rpivid/rpivid_video.c b/drivers/staging/media/rpivid/rpivid_video.c new file mode 100644 -index 000000000000..93b3d86b41e3 +index 000000000000..ef2dc2742ee9 --- /dev/null +++ b/drivers/staging/media/rpivid/rpivid_video.c -@@ -0,0 +1,707 @@ +@@ -0,0 +1,696 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Raspberry Pi HEVC driver @@ -104124,7 +158729,7 @@ +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); ++ rpivid_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SPS); + struct v4l2_pix_format_mplane pix_fmt; + + memset(&pix_fmt, 0, sizeof(pix_fmt)); @@ -104142,7 +158747,7 @@ + const int index) +{ + const struct v4l2_ctrl_hevc_sps * const sps = -+ rpivid_find_control_data(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SPS); ++ rpivid_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SPS); + + return pixelformat_from_sps(sps, index); +} @@ -104204,7 +158809,7 @@ +{ + 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); ++ rpivid_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SPS); + u32 pixelformat; + int i; + @@ -104382,38 +158987,27 @@ +static void stop_clock(struct rpivid_dev *dev, struct rpivid_ctx *ctx) +{ + if (ctx->src_stream_on || -+ ctx->dst_stream_on || -+ !ctx->clk_req) ++ ctx->dst_stream_on) + return; + -+ clk_request_done(ctx->clk_req); -+ ctx->clk_req = NULL; -+ ++ clk_set_min_rate(dev->clock, 0); + 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) { ++ rv = clk_set_min_rate(dev->clock, dev->max_clock_rate); ++ if (rv) { + dev_err(dev->dev, "Failed to set clock rate\n"); -+ return -EIO; ++ return rv; + } + + 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; + } + @@ -104582,10 +159176,10 @@ + +#endif diff --git a/drivers/staging/vc04_services/Kconfig b/drivers/staging/vc04_services/Kconfig -index 4b886293f198..8b912617bfec 100644 +index 31e58c9d1a11..de6f87e073a7 100644 --- a/drivers/staging/vc04_services/Kconfig +++ b/drivers/staging/vc04_services/Kconfig -@@ -23,6 +23,10 @@ source "drivers/staging/vc04_services/bcm2835-audio/Kconfig" +@@ -44,6 +44,10 @@ source "drivers/staging/vc04_services/bcm2835-audio/Kconfig" source "drivers/staging/vc04_services/bcm2835-camera/Kconfig" @@ -104597,10 +159191,10 @@ endif diff --git a/drivers/staging/vc04_services/Makefile b/drivers/staging/vc04_services/Makefile -index 7546d70116a0..fc42251ec5ef 100644 +index 44794bdf6173..0dc02bba3c3f 100644 --- a/drivers/staging/vc04_services/Makefile +++ b/drivers/staging/vc04_services/Makefile -@@ -11,6 +11,9 @@ vchiq-objs := \ +@@ -14,4 +14,7 @@ endif obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/ obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/ obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/ @@ -104608,113 +159202,97 @@ +obj-$(CONFIG_VIDEO_CODEC_BCM2835) += bcm2835-codec/ +obj-$(CONFIG_VIDEO_ISP_BCM2835) += bcm2835-isp/ - ccflags-y += -I $(srctree)/$(src)/include -D__VCCOREVER__=0x04000000 - diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c -index 096f2c54258a..fa5cf5b9550f 100644 +index 68e8d491a7ec..29e773fdd7ad 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c -@@ -14,14 +14,14 @@ static const struct snd_pcm_hardware snd_bcm2835_playback_hw = { - SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_SYNC_APPLPTR), - .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, -- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, -+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000, - .rate_min = 8000, -- .rate_max = 48000, -+ .rate_max = 192000, - .channels_min = 1, -- .channels_max = 2, -- .buffer_bytes_max = 128 * 1024, -+ .channels_max = 8, -+ .buffer_bytes_max = 512 * 1024, - .period_bytes_min = 1 * 1024, -- .period_bytes_max = 128 * 1024, -+ .period_bytes_max = 512 * 1024, - .periods_min = 1, - .periods_max = 128, - }; +@@ -321,10 +321,11 @@ static const struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = { + + /* create a pcm device */ + int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, const char *name, +- int idx, enum snd_bcm2835_route route, ++ enum snd_bcm2835_route route, + u32 numchannels, bool spdif) + { + struct snd_pcm *pcm; ++ int idx = chip->index++; + int err; + + err = snd_pcm_new(chip->card, name, idx, numchannels, 0, &pcm); diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c -index c250fbef2fa3..ccda115ab9e0 100644 +index 00bc898b0189..6347becff898 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c -@@ -6,13 +6,14 @@ - #include <linux/init.h> - #include <linux/slab.h> +@@ -8,8 +8,9 @@ #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"); -@@ -21,8 +22,6 @@ MODULE_PARM_DESC(enable_headphones, "Enables Headphones virtual audio device"); - 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 bool enable_headphones = true; + static int num_channels = MAX_SUBSTREAMS; - static void bcm2835_devm_free_vchi_ctx(struct device *dev, void *res) +@@ -65,14 +66,13 @@ static int bcm2835_audio_dual_newpcm(struct bcm2835_chip *chip, + u32 numchannels) { -@@ -81,7 +80,11 @@ static int bcm2835_audio_alsa_newpcm(struct bcm2835_chip *chip, + int err; +- +- err = snd_bcm2835_new_pcm(chip, name, 0, route, ++ err = snd_bcm2835_new_pcm(chip, name, route, + numchannels, false); + 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); +- err = snd_bcm2835_new_pcm(chip, "IEC958", 1, route, 1, true); ++ err = snd_bcm2835_new_pcm(chip, name, route, 1, true); if (err) return err; -@@ -108,17 +111,30 @@ static struct bcm2835_audio_driver bcm2835_audio_alsa = { - .newctl = snd_bcm2835_new_ctl, - }; +@@ -84,20 +84,33 @@ static int bcm2835_audio_simple_newpcm(struct bcm2835_chip *chip, + enum snd_bcm2835_route route, + u32 numchannels) + { +- return snd_bcm2835_new_pcm(chip, name, 0, route, numchannels, false); ++ return snd_bcm2835_new_pcm(chip, name, route, numchannels, false); + } -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 1", ++ .longname = "bcm2835 HDMI 1", ++ .minchannels = 1, ++ .newpcm = bcm2835_audio_dual_newpcm, ++ .newctl = snd_bcm2835_new_hdmi_ctl, ++ .route = AUDIO_DEST_HDMI0 ++}; ++ ++static struct bcm2835_audio_driver bcm2835_audio_hdmi1 = { .driver = { .name = "bcm2835_hdmi", .owner = THIS_MODULE, }, - .shortname = "bcm2835 HDMI", - .longname = "bcm2835 HDMI", -+ .shortname = "bcm2835 HDMI 1", -+ .longname = "bcm2835 HDMI 1", ++ .shortname = "bcm2835 HDMI 2", ++ .longname = "bcm2835 HDMI 2", .minchannels = 1, - .newpcm = bcm2835_audio_simple_newpcm, + .newpcm = bcm2835_audio_dual_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 = { -@@ -145,8 +161,12 @@ static struct bcm2835_audio_drivers children_devices = { - .is_enabled = &enable_compat_alsa, - }, +@@ -120,8 +133,12 @@ struct bcm2835_audio_drivers { + + static struct bcm2835_audio_drivers children_devices = { { - .audio_driver = &bcm2835_audio_hdmi, - .is_enabled = &enable_hdmi, @@ -104727,38 +159305,46 @@ }, { .audio_driver = &bcm2835_audio_headphones, -@@ -293,22 +313,93 @@ static int snd_add_child_devices(struct device *device, u32 numchans) +@@ -268,10 +285,70 @@ static int snd_add_child_devices(struct device *device, u32 numchans) return 0; } +static void set_hdmi_enables(struct device *dev) +{ + struct device_node *firmware_node; -+ struct rpi_firmware *firmware; ++ struct rpi_firmware *firmware = NULL; + 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); ++ firmware_node = of_find_compatible_node(NULL, NULL, ++ "raspberrypi,bcm2835-firmware"); ++ if (firmware_node) { ++ firmware = rpi_firmware_get(firmware_node); ++ of_node_put(firmware_node); ++ } + -+ if (!firmware) ++ if (!firmware) { ++ dev_err(dev, "Failed to get fw structure\n"); + return; -+ -+ of_node_put(firmware_node); ++ } + + ret = rpi_firmware_property(firmware, + RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS, + &num_displays, sizeof(u32)); -+ -+ if (ret) -+ return; ++ if (ret) { ++ dev_err(dev, "Failed to get fw property NUM_DISPLAYS\n"); ++ goto out_rpi_fw_put; ++ } + + 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 (ret) { ++ dev_err(dev, "Failed to get fw property DISPLAY_ID " ++ "(i = %d)\n", i); ++ } else { + if (display_id == 2) + enable_hdmi0 = true; + if (display_id == 7) @@ -104776,106 +159362,83 @@ + enable_hdmi1 = false; + bcm2835_audio_hdmi0.route = AUDIO_DEST_HDMI1; + } ++ ++out_rpi_fw_put: ++ rpi_firmware_put(firmware); ++ return; +} + static int snd_bcm2835_alsa_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; -+ u32 numchans; int err; ++ u32 disable_headphones = 0; -- 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")) -+ set_hdmi_enables(dev); + if (num_channels <= 0 || num_channels > MAX_SUBSTREAMS) { + num_channels = MAX_SUBSTREAMS; +@@ -279,6 +356,17 @@ static int snd_bcm2835_alsa_probe(struct platform_device *pdev) + num_channels); + } + ++ if (enable_hdmi && ++ !of_property_read_bool(dev->of_node, "brcm,disable-hdmi")) ++ set_hdmi_enables(dev); + ++ if (enable_headphones) { + of_property_read_u32(dev->of_node, + "brcm,disable-headphones", + &disable_headphones); + enable_headphones = !disable_headphones; -+ } else { -+ enable_hdmi0 = enable_hdmi; - } - ++ } ++ err = bcm2835_devm_add_vchi_ctx(dev); if (err) return err; - -- err = snd_add_child_devices(dev, num_channels); -+ err = snd_add_child_devices(dev, numchans); - if (err) - return err; - -@@ -330,6 +421,12 @@ static int snd_bcm2835_alsa_resume(struct platform_device *pdev) - - #endif - -+static const struct of_device_id snd_bcm2835_of_match_table = { -+ { .compatible = "brcm,bcm2835-audio",}, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, snd_bcm2835_of_match_table); -+ - static struct platform_driver bcm2835_alsa_driver = { - .probe = snd_bcm2835_alsa_probe, - #ifdef CONFIG_PM -@@ -338,6 +435,7 @@ static struct platform_driver bcm2835_alsa_driver = { - #endif - .driver = { - .name = "bcm2835_audio", -+ .of_match_table = snd_bcm2835_of_match_table, - }, - }; - module_platform_driver(bcm2835_alsa_driver); diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h -index 1b36475872d6..02f50768af96 100644 +index 0a81383c475a..fa4228daecdd 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h -@@ -33,7 +33,9 @@ enum { +@@ -34,7 +34,8 @@ enum { enum snd_bcm2835_route { AUDIO_DEST_AUTO = 0, AUDIO_DEST_HEADPHONES = 1, - AUDIO_DEST_HDMI = 2, -+ AUDIO_DEST_HDMI = 2, // for backwards compatibility. + AUDIO_DEST_HDMI0 = 2, + AUDIO_DEST_HDMI1 = 3, AUDIO_DEST_MAX, }; +@@ -59,6 +60,7 @@ struct bcm2835_chip { + int volume; + int dest; + int mute; ++ int index; + + unsigned int opened; + unsigned int spdif_status; +@@ -86,7 +88,7 @@ struct bcm2835_alsa_stream { + + int snd_bcm2835_new_ctl(struct bcm2835_chip *chip); + int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, const char *name, +- int idx, enum snd_bcm2835_route route, ++ enum snd_bcm2835_route route, + u32 numchannels, bool spdif); + + int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip); diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c -index df90c1f9d148..7bee6e1bc69a 100644 +index 346d00df815a..504d879adc59 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c -@@ -178,7 +178,7 @@ static struct mmal_fmt formats = { +@@ -176,7 +176,7 @@ static struct mmal_fmt formats = { .ybbp = 1, - .remove_padding = 1, + .remove_padding = true, }, { - .fourcc = V4L2_PIX_FMT_BGR32, + .fourcc = V4L2_PIX_FMT_BGRX32, .mmal = MMAL_ENCODING_BGRA, .depth = 32, .mmal_component = COMP_CAMERA, -@@ -1453,6 +1453,7 @@ static const struct v4l2_ioctl_ops camera0_ioctl_ops = { +@@ -1449,6 +1449,7 @@ static const struct v4l2_ioctl_ops camera0_ioctl_ops = { .vidioc_querybuf = vb2_ioctl_querybuf, .vidioc_qbuf = vb2_ioctl_qbuf, .vidioc_dqbuf = vb2_ioctl_dqbuf, @@ -104883,7 +159446,7 @@ .vidioc_enum_framesizes = vidioc_enum_framesizes, .vidioc_enum_frameintervals = vidioc_enum_frameintervals, .vidioc_g_parm = vidioc_g_parm, -@@ -1734,6 +1735,12 @@ static int mmal_init(struct bm2835_mmal_dev *dev) +@@ -1730,6 +1731,12 @@ static int mmal_init(struct bcm2835_mmal_dev *dev) MMAL_PARAMETER_MINIMISE_FRAGMENTATION, &enable, sizeof(enable)); @@ -104894,9 +159457,9 @@ + MMAL_PARAMETER_VIDEO_ENCODE_HEADERS_WITH_FRAME, + &enable, sizeof(enable)); } - ret = bm2835_mmal_set_all_camera_controls(dev); + ret = bcm2835_mmal_set_all_camera_controls(dev); if (ret < 0) { -@@ -1928,7 +1935,7 @@ static int bcm2835_mmal_probe(struct platform_device *pdev) +@@ -1922,7 +1929,7 @@ static int bcm2835_mmal_probe(struct platform_device *pdev) q = &dev->capture.vb_vidq; memset(q, 0, sizeof(*q)); q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -104904,9 +159467,9 @@ + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF; q->drv_priv = dev; q->buf_struct_size = sizeof(struct vb2_mmal_buffer); - q->ops = &bm2835_mmal_video_qops; + q->ops = &bcm2835_mmal_video_qops; diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h -index 75524adff0f5..fdbcc35ece5b 100644 +index 0f0c6f7a3764..f27cc8e55c80 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h @@ -13,7 +13,7 @@ @@ -104919,10 +159482,10 @@ enum { COMP_CAMERA = 0, diff --git a/drivers/staging/vc04_services/bcm2835-camera/controls.c b/drivers/staging/vc04_services/bcm2835-camera/controls.c -index b096a12387f7..b1b02fbc473d 100644 +index 6bce45925bf1..40753c8fd5f3 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/controls.c +++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c -@@ -474,6 +474,10 @@ static int ctrl_set_awb_mode(struct bm2835_mmal_dev *dev, +@@ -468,6 +468,10 @@ static int ctrl_set_awb_mode(struct bcm2835_mmal_dev *dev, case V4L2_WHITE_BALANCE_SHADE: u32_value = MMAL_PARAM_AWBMODE_SHADE; break; @@ -104933,7 +159496,7 @@ } return vchiq_mmal_port_parameter_set(dev->instance, control, -@@ -705,6 +709,8 @@ static int ctrl_set_video_encode_profile_level(struct bm2835_mmal_dev *dev, +@@ -700,6 +704,8 @@ static int ctrl_set_video_encode_profile_level(struct bcm2835_mmal_dev *dev, case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: @@ -104942,7 +159505,7 @@ dev->capture.enc_level = ctrl->val; break; default: -@@ -770,6 +776,17 @@ static int ctrl_set_video_encode_profile_level(struct bm2835_mmal_dev *dev, +@@ -765,6 +771,17 @@ static int ctrl_set_video_encode_profile_level(struct bcm2835_mmal_dev *dev, case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: param.level = MMAL_VIDEO_LEVEL_H264_4; break; @@ -104960,7 +159523,7 @@ default: /* Should never get here */ break; -@@ -1052,8 +1069,8 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrlsV4L2_CTRL_COUNT = { +@@ -1046,8 +1063,8 @@ static const struct bcm2835_mmal_v4l2_ctrl v4l2_ctrlsV4L2_CTRL_COUNT = { { .id = V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, .type = MMAL_CONTROL_TYPE_STD_MENU, @@ -104971,7 +159534,7 @@ .def = V4L2_WHITE_BALANCE_AUTO, .step = 0, .imenu = NULL, -@@ -1220,8 +1237,10 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrlsV4L2_CTRL_COUNT = { +@@ -1214,8 +1231,10 @@ static const struct bcm2835_mmal_v4l2_ctrl v4l2_ctrlsV4L2_CTRL_COUNT = { BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | @@ -104984,7 +159547,7 @@ .def = V4L2_MPEG_VIDEO_H264_LEVEL_4_0, .step = 1, .imenu = NULL, -@@ -1251,6 +1270,39 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrlsV4L2_CTRL_COUNT = { +@@ -1245,6 +1264,39 @@ static const struct bcm2835_mmal_v4l2_ctrl v4l2_ctrlsV4L2_CTRL_COUNT = { .mmal_id = MMAL_PARAMETER_INTRAPERIOD, .setter = ctrl_set_video_encode_param_output, }, @@ -105023,17 +159586,17 @@ + }, }; - int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev) + int bcm2835_mmal_set_all_camera_controls(struct bcm2835_mmal_dev *dev) diff --git a/drivers/staging/vc04_services/bcm2835-codec/Kconfig b/drivers/staging/vc04_services/bcm2835-codec/Kconfig new file mode 100644 -index 000000000000..c104be9ad6da +index 000000000000..761c8ba4b40f --- /dev/null +++ b/drivers/staging/vc04_services/bcm2835-codec/Kconfig @@ -0,0 +1,11 @@ +config VIDEO_CODEC_BCM2835 + tristate "BCM2835 Video codec support" + depends on MEDIA_SUPPORT && MEDIA_CONTROLLER -+ depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST) ++ depends on VIDEO_DEV && (ARCH_BCM2835 || COMPILE_TEST) + select BCM2835_VCHIQ_MMAL + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV @@ -105065,10 +159628,10 @@ \ No newline at end of file diff --git a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c new file mode 100644 -index 000000000000..472d97d1d228 +index 000000000000..b9640f71cc5d --- /dev/null +++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -0,0 +1,3684 @@ +@@ -0,0 +1,3964 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* @@ -105112,6 +159675,8 @@ +#include "vchiq-mmal/mmal-parameters.h" +#include "vchiq-mmal/mmal-vchiq.h" + ++MODULE_IMPORT_NS(DMA_BUF); ++ +/* + * Default /dev/videoN node numbers for decode and encode. + * Deliberately avoid the very low numbers as these are often taken by webcams @@ -105133,6 +159698,10 @@ +module_param(deinterlace_video_nr, int, 0644); +MODULE_PARM_DESC(deinterlace_video_nr, "deinterlace video device number"); + ++static int encode_image_nr = 31; ++module_param(encode_image_nr, int, 0644); ++MODULE_PARM_DESC(encode_image_nr, "encoder image device number"); ++ +/* + * Workaround for GStreamer v4l2convert component not considering Bayer formats + * as raw, and therefore not considering a V4L2 device that supports them as @@ -105159,6 +159728,7 @@ + ENCODE, + ISP, + DEINTERLACE, ++ ENCODE_IMAGE, + NUM_ROLES +}; + @@ -105167,6 +159737,7 @@ + "encode", + "isp", + "image_fx", ++ "encode_image", +}; + +static const char * const components = { @@ -105174,6 +159745,7 @@ + "ril.video_encode", + "ril.isp", + "ril.image_fx", ++ "ril.image_encode", +}; + +/* Timeout for stop_streaming to allow all buffers to return */ @@ -105181,8 +159753,10 @@ + +#define MIN_W 32 +#define MIN_H 32 -+#define MAX_W 1920 -+#define MAX_H 1920 ++#define MAX_W_CODEC 1920 ++#define MAX_H_CODEC 1920 ++#define MAX_W_ISP 16384 ++#define MAX_H_ISP 16384 +#define BPL_ALIGN 32 +/* + * The decoder spec supports the V4L2_EVENT_SOURCE_CHANGE event, but the docs @@ -105207,6 +159781,8 @@ + */ +#define DEF_COMP_BUF_SIZE_GREATER_720P (768 << 10) +#define DEF_COMP_BUF_SIZE_720P_OR_LESS (512 << 10) ++/* JPEG image can be very large. For paranoid reasons 4MB is used */ ++#define DEF_COMP_BUF_SIZE_JPEG (4096 << 10) + +/* Flags that indicate a format can be used for capture/output */ +#define MEM2MEM_CAPTURE BIT(0) @@ -105229,94 +159805,108 @@ + /* YUV formats */ + .fourcc = V4L2_PIX_FMT_YUV420, + .depth = 8, -+ .bytesperline_align = { 32, 64, 64, 32 }, ++ .bytesperline_align = { 32, 64, 64, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_I420, + .size_multiplier_x2 = 3, + }, { + .fourcc = V4L2_PIX_FMT_YVU420, + .depth = 8, -+ .bytesperline_align = { 32, 64, 64, 32 }, ++ .bytesperline_align = { 32, 64, 64, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_YV12, + .size_multiplier_x2 = 3, + }, { + .fourcc = V4L2_PIX_FMT_NV12, + .depth = 8, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_NV12, + .size_multiplier_x2 = 3, + }, { + .fourcc = V4L2_PIX_FMT_NV21, + .depth = 8, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_NV21, + .size_multiplier_x2 = 3, + }, { + .fourcc = V4L2_PIX_FMT_RGB565, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_RGB16, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 64, 64, 64, 64, 64 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_YUYV, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 64, 64, 64, 64, 64 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_UYVY, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_YVYU, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 64, 64, 64, 64, 64 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_YVYU, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_VYUY, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 64, 64, 64, 64, 64 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_VYUY, + .size_multiplier_x2 = 2, + }, { ++ .fourcc = V4L2_PIX_FMT_NV12_COL128, ++ .depth = 8, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_YUVUV128, ++ .size_multiplier_x2 = 3, ++ }, { + /* RGB formats */ + .fourcc = V4L2_PIX_FMT_RGB24, + .depth = 24, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_RGB24, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_BGR24, + .depth = 24, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BGR24, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_BGR32, + .depth = 32, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BGRA, + .size_multiplier_x2 = 2, + }, { ++ .fourcc = V4L2_PIX_FMT_RGBA32, ++ .depth = 32, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_RGBA, ++ .size_multiplier_x2 = 2, ++ }, { + /* Bayer formats */ + /* 8 bit */ + .fourcc = V4L2_PIX_FMT_SRGGB8, + .depth = 8, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB8, + .size_multiplier_x2 = 2, @@ -105324,7 +159914,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .depth = 8, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR8, + .size_multiplier_x2 = 2, @@ -105332,7 +159922,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .depth = 8, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG8, + .size_multiplier_x2 = 2, @@ -105340,7 +159930,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .depth = 8, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG8, + .size_multiplier_x2 = 2, @@ -105349,7 +159939,7 @@ + /* 10 bit */ + .fourcc = V4L2_PIX_FMT_SRGGB10P, + .depth = 10, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB10P, + .size_multiplier_x2 = 2, @@ -105357,7 +159947,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SBGGR10P, + .depth = 10, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR10P, + .size_multiplier_x2 = 2, @@ -105365,7 +159955,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SGRBG10P, + .depth = 10, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG10P, + .size_multiplier_x2 = 2, @@ -105373,7 +159963,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SGBRG10P, + .depth = 10, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG10P, + .size_multiplier_x2 = 2, @@ -105382,7 +159972,7 @@ + /* 12 bit */ + .fourcc = V4L2_PIX_FMT_SRGGB12P, + .depth = 12, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB12P, + .size_multiplier_x2 = 2, @@ -105390,7 +159980,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SBGGR12P, + .depth = 12, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR12P, + .size_multiplier_x2 = 2, @@ -105398,7 +159988,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SGRBG12P, + .depth = 12, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG12P, + .size_multiplier_x2 = 2, @@ -105406,7 +159996,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SGBRG12P, + .depth = 12, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG12P, + .size_multiplier_x2 = 2, @@ -105415,7 +160005,7 @@ + /* 14 bit */ + .fourcc = V4L2_PIX_FMT_SRGGB14P, + .depth = 14, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB14P, + .size_multiplier_x2 = 2, @@ -105423,7 +160013,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SBGGR14P, + .depth = 14, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR14P, + .size_multiplier_x2 = 2, @@ -105432,7 +160022,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SGRBG14P, + .depth = 14, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG14P, + .size_multiplier_x2 = 2, @@ -105440,7 +160030,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SGBRG14P, + .depth = 14, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG14P, + .size_multiplier_x2 = 2, @@ -105449,7 +160039,7 @@ + /* 16 bit */ + .fourcc = V4L2_PIX_FMT_SRGGB16, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB16, + .size_multiplier_x2 = 2, @@ -105457,7 +160047,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SBGGR16, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR16, + .size_multiplier_x2 = 2, @@ -105465,7 +160055,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SGRBG16, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG16, + .size_multiplier_x2 = 2, @@ -105473,7 +160063,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SGBRG16, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG16, + .size_multiplier_x2 = 2, @@ -105483,7 +160073,7 @@ + /* 10 bit */ + .fourcc = V4L2_PIX_FMT_SRGGB10, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB10, + .size_multiplier_x2 = 2, @@ -105491,7 +160081,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR10, + .size_multiplier_x2 = 2, @@ -105499,7 +160089,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG10, + .size_multiplier_x2 = 2, @@ -105507,7 +160097,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG10, + .size_multiplier_x2 = 2, @@ -105516,7 +160106,7 @@ + /* 12 bit */ + .fourcc = V4L2_PIX_FMT_SRGGB12, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB12, + .size_multiplier_x2 = 2, @@ -105524,7 +160114,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SBGGR12, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR12, + .size_multiplier_x2 = 2, @@ -105532,7 +160122,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SGRBG12, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG12, + .size_multiplier_x2 = 2, @@ -105540,7 +160130,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SGBRG12, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG12, + .size_multiplier_x2 = 2, @@ -105549,7 +160139,7 @@ + /* 14 bit */ + .fourcc = V4L2_PIX_FMT_SRGGB14, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB14, + .size_multiplier_x2 = 2, @@ -105557,7 +160147,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SBGGR14, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR14, + .size_multiplier_x2 = 2, @@ -105565,7 +160155,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SGRBG14, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG14, + .size_multiplier_x2 = 2, @@ -105573,7 +160163,7 @@ + }, { + .fourcc = V4L2_PIX_FMT_SGBRG14, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG14, + .size_multiplier_x2 = 2, @@ -105583,7 +160173,7 @@ + /* 8 bit */ + .fourcc = V4L2_PIX_FMT_GREY, + .depth = 8, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_GREY, + .size_multiplier_x2 = 2, @@ -105591,7 +160181,7 @@ + /* 10 bit */ + .fourcc = V4L2_PIX_FMT_Y10P, + .depth = 10, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_Y10P, + .size_multiplier_x2 = 2, @@ -105599,7 +160189,7 @@ + /* 12 bit */ + .fourcc = V4L2_PIX_FMT_Y12P, + .depth = 12, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_Y12P, + .size_multiplier_x2 = 2, @@ -105607,7 +160197,7 @@ + /* 14 bit */ + .fourcc = V4L2_PIX_FMT_Y14P, + .depth = 14, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_Y14P, + .size_multiplier_x2 = 2, @@ -105615,7 +160205,7 @@ + /* 16 bit */ + .fourcc = V4L2_PIX_FMT_Y16, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_Y16, + .size_multiplier_x2 = 2, @@ -105623,7 +160213,7 @@ + /* 10 bit as 16bpp */ + .fourcc = V4L2_PIX_FMT_Y10, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_Y10, + .size_multiplier_x2 = 2, @@ -105631,7 +160221,7 @@ + /* 12 bit as 16bpp */ + .fourcc = V4L2_PIX_FMT_Y12, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_Y12, + .size_multiplier_x2 = 2, @@ -105639,7 +160229,7 @@ + /* 14 bit as 16bpp */ + .fourcc = V4L2_PIX_FMT_Y14, + .depth = 16, -+ .bytesperline_align = { 32, 32, 32, 32 }, ++ .bytesperline_align = { 32, 32, 32, 32, 32 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_Y14, + .size_multiplier_x2 = 2, @@ -105650,6 +160240,11 @@ + .flags = V4L2_FMT_FLAG_COMPRESSED, + .mmal_fmt = MMAL_ENCODING_H264, + }, { ++ .fourcc = V4L2_PIX_FMT_JPEG, ++ .depth = 0, ++ .flags = V4L2_FMT_FLAG_COMPRESSED, ++ .mmal_fmt = MMAL_ENCODING_JPEG, ++ }, { + .fourcc = V4L2_PIX_FMT_MJPEG, + .depth = 0, + .flags = V4L2_FMT_FLAG_COMPRESSED, @@ -105727,6 +160322,13 @@ + /* The list of formats supported on input and output queues. */ + struct bcm2835_codec_fmt_list supported_fmts2; + ++ /* ++ * Max size supported varies based on role. Store during ++ * bcm2835_codec_create for use later. ++ */ ++ unsigned int max_w; ++ unsigned int max_h; ++ + struct vchiq_mmal_instance *instance; + + struct v4l2_m2m_dev *m2m_dev; @@ -105737,6 +160339,7 @@ + struct bcm2835_codec_dev *dev; + + struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gop_size; + + struct vchiq_mmal_component *component; + bool component_enabled; @@ -105769,6 +160372,7 @@ + struct bcm2835_codec_dev *decode; + struct bcm2835_codec_dev *isp; + struct bcm2835_codec_dev *deinterlace; ++ struct bcm2835_codec_dev *encode_image; +}; + +enum { @@ -105902,20 +160506,41 @@ + struct bcm2835_codec_fmt *fmt) +{ + if (fmt->flags & V4L2_FMT_FLAG_COMPRESSED) { ++ if (fmt->fourcc == V4L2_PIX_FMT_JPEG) ++ return DEF_COMP_BUF_SIZE_JPEG; ++ + if (width * height > 1280 * 720) + return DEF_COMP_BUF_SIZE_GREATER_720P; + else + return DEF_COMP_BUF_SIZE_720P_OR_LESS; -+ } else { -+ return (bpl * height * fmt->size_multiplier_x2) >> 1; + } ++ ++ if (fmt->fourcc != V4L2_PIX_FMT_NV12_COL128) ++ return (bpl * height * fmt->size_multiplier_x2) >> 1; ++ ++ /* ++ * V4L2_PIX_FMT_NV12_COL128 is 128 pixel wide columns. ++ * bytesperline is the column stride in lines, so multiply by ++ * the number of columns and 128. ++ */ ++ return (ALIGN(width, 128) * bpl); +} + -+static inline unsigned int get_bytesperline(int width, ++static inline unsigned int get_bytesperline(int width, int height, + struct bcm2835_codec_fmt *fmt, + enum bcm2835_codec_role role) +{ -+ return ALIGN((width * fmt->depth) >> 3, fmt->bytesperline_alignrole); ++ if (fmt->fourcc != V4L2_PIX_FMT_NV12_COL128) ++ return ALIGN((width * fmt->depth) >> 3, ++ fmt->bytesperline_alignrole); ++ ++ /* ++ * V4L2_PIX_FMT_NV12_COL128 passes the column stride in lines via ++ * bytesperline. ++ * The minimum value for this is sufficient for the base luma and chroma ++ * with no padding. ++ */ ++ return (height * 3) >> 1; +} + +static void setup_mmal_port_format(struct bcm2835_codec_ctx *ctx, @@ -105923,16 +160548,27 @@ + struct vchiq_mmal_port *port) +{ + port->format.encoding = q_data->fmt->mmal_fmt; ++ port->format.flags = 0; + + if (!(q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED)) { -+ /* Raw image format - set width/height */ -+ port->es.video.width = (q_data->bytesperline << 3) / -+ q_data->fmt->depth; -+ port->es.video.height = q_data->height; -+ port->es.video.crop.width = q_data->crop_width; -+ port->es.video.crop.height = q_data->crop_height; -+ port->es.video.frame_rate.num = ctx->framerate_num; -+ port->es.video.frame_rate.den = ctx->framerate_denom; ++ if (q_data->fmt->mmal_fmt != MMAL_ENCODING_YUVUV128) { ++ /* Raw image format - set width/height */ ++ port->es.video.width = (q_data->bytesperline << 3) / ++ q_data->fmt->depth; ++ port->es.video.height = q_data->height; ++ port->es.video.crop.width = q_data->crop_width; ++ port->es.video.crop.height = q_data->crop_height; ++ } else { ++ /* NV12_COL128 / YUVUV128 column format */ ++ /* Column stride in lines */ ++ port->es.video.width = q_data->bytesperline; ++ port->es.video.height = q_data->height; ++ port->es.video.crop.width = q_data->crop_width; ++ port->es.video.crop.height = q_data->crop_height; ++ port->format.flags = MMAL_ES_FORMAT_FLAG_COL_FMTS_WIDTH_IS_COL_STRIDE; ++ } ++ port->es.video.frame_rate.numerator = ctx->framerate_num; ++ port->es.video.frame_rate.denominator = ctx->framerate_denom; + } else { + /* Compressed format - leave resolution as 0 for decode */ + if (ctx->dev->role == DECODE) { @@ -105946,8 +160582,8 @@ + port->es.video.crop.width = q_data->crop_width; + port->es.video.crop.height = q_data->crop_height; + port->format.bitrate = ctx->bitrate; -+ port->es.video.frame_rate.num = ctx->framerate_num; -+ port->es.video.frame_rate.den = ctx->framerate_denom; ++ port->es.video.frame_rate.numerator = ctx->framerate_num; ++ port->es.video.frame_rate.denominator = ctx->framerate_denom; + } + } + port->es.video.crop.x = 0; @@ -106113,6 +160749,7 @@ + */ + q_data->selection_set = true; + q_data->bytesperline = get_bytesperline(format->es.video.width, ++ format->es.video.height, + q_data->fmt, ctx->dev->role); + + q_data->height = format->es.video.height; @@ -106121,8 +160758,8 @@ + color_mmal2v4l(ctx, format->format.encoding, + format->es.video.color_space); + -+ q_data->aspect_ratio.numerator = format->es.video.par.num; -+ q_data->aspect_ratio.denominator = format->es.video.par.den; ++ q_data->aspect_ratio.numerator = format->es.video.par.numerator; ++ q_data->aspect_ratio.denominator = format->es.video.par.denominator; + + ret = vchiq_mmal_port_parameter_get(ctx->dev->instance, + &ctx->component->output0, @@ -106205,10 +160842,15 @@ + v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: Empty buffer - flags %04x", + __func__, mmal_buf->mmal_flags); + if (!(mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS)) { -+ vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_QUEUED); -+ if (!port->enabled && -+ atomic_read(&port->buffers_with_vpu)) -+ complete(&ctx->frame_cmplt); ++ if (!port->enabled) { ++ vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_QUEUED); ++ if (atomic_read(&port->buffers_with_vpu)) ++ complete(&ctx->frame_cmplt); ++ } else { ++ vchiq_mmal_submit_buffer(ctx->dev->instance, ++ &ctx->component->output0, ++ mmal_buf); ++ } + return; + } + } @@ -106473,10 +161115,10 @@ + * The V4L2 specification requires the driver to correct the format + * struct if any of the dimensions is unsupported + */ -+ if (f->fmt.pix_mp.width > MAX_W) -+ f->fmt.pix_mp.width = MAX_W; -+ if (f->fmt.pix_mp.height > MAX_H) -+ f->fmt.pix_mp.height = MAX_H; ++ if (f->fmt.pix_mp.width > ctx->dev->max_w) ++ f->fmt.pix_mp.width = ctx->dev->max_w; ++ if (f->fmt.pix_mp.height > ctx->dev->max_h) ++ f->fmt.pix_mp.height = ctx->dev->max_h; + + if (!(fmt->flags & V4L2_FMT_FLAG_COMPRESSED)) { + /* Only clip min w/h on capture. Treat 0x0 as unknown. */ @@ -106486,17 +161128,18 @@ + f->fmt.pix_mp.height = MIN_H; + + /* -+ * For decoders the buffer must have a vertical alignment of 16 -+ * lines. ++ * For decoders and image encoders the buffer must have ++ * a vertical alignment of 16 lines. + * The selection will reflect any cropping rectangle when only + * some of the pixels are active. + */ -+ if (ctx->dev->role == DECODE) ++ if (ctx->dev->role == DECODE || ctx->dev->role == ENCODE_IMAGE) + f->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16); + } + f->fmt.pix_mp.num_planes = 1; -+ min_bytesperline = get_bytesperline(f->fmt.pix_mp.width, fmt, -+ ctx->dev->role); ++ min_bytesperline = get_bytesperline(f->fmt.pix_mp.width, ++ f->fmt.pix_mp.height, ++ fmt, ctx->dev->role); + if (f->fmt.pix_mp.plane_fmt0.bytesperline < min_bytesperline) + f->fmt.pix_mp.plane_fmt0.bytesperline = min_bytesperline; + f->fmt.pix_mp.plane_fmt0.bytesperline = @@ -106616,7 +161259,8 @@ + f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + q_data->crop_width = f->fmt.pix_mp.width; + q_data->height = f->fmt.pix_mp.height; -+ if (!q_data->selection_set) ++ if (!q_data->selection_set || ++ (q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED)) + q_data->crop_height = requested_height; + + /* @@ -106637,12 +161281,13 @@ + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calculated bpl as %u, size %u\n", + q_data->bytesperline, q_data->sizeimage); + -+ if (ctx->dev->role == DECODE && ++ if ((ctx->dev->role == DECODE || ctx->dev->role == ENCODE_IMAGE) && + q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED && + q_data->crop_width && q_data->height) { + /* -+ * On the decoder, if provided with a resolution on the input -+ * side, then replicate that to the output side. ++ * On the decoder or image encoder, if provided with ++ * a resolution on the input side, then replicate that ++ * to the output side. + * GStreamer appears not to support V4L2_EVENT_SOURCE_CHANGE, + * nor set up a resolution on the output side, therefore + * we can't decode anything at a resolution other than the @@ -106656,8 +161301,9 @@ + q_data_dst->height = ALIGN(q_data->crop_height, 16); + + q_data_dst->bytesperline = -+ get_bytesperline(f->fmt.pix_mp.width, q_data_dst->fmt, -+ ctx->dev->role); ++ get_bytesperline(f->fmt.pix_mp.width, ++ f->fmt.pix_mp.height, ++ q_data_dst->fmt, ctx->dev->role); + q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline, + q_data_dst->crop_width, + q_data_dst->height, @@ -106783,7 +161429,7 @@ + switch (s->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + /* CAPTURE on encoder is not valid. */ -+ if (ctx->dev->role == ENCODE) ++ if (ctx->dev->role == ENCODE || ctx->dev->role == ENCODE_IMAGE) + return -EINVAL; + q_data = &ctx->q_dataV4L2_M2M_DST; + break; @@ -106826,6 +161472,7 @@ + } + break; + case ENCODE: ++ case ENCODE_IMAGE: + switch (s->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: @@ -106845,7 +161492,6 @@ + } + break; + case ISP: -+ break; + case DEINTERLACE: + if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + switch (s->target) { @@ -106898,6 +161544,8 @@ +{ + struct bcm2835_codec_ctx *ctx = file2ctx(file); + struct bcm2835_codec_q_data *q_data = NULL; ++ struct vchiq_mmal_port *port = NULL; ++ int ret; + + /* + * The selection API takes V4L2_BUF_TYPE_VIDEO_CAPTURE and @@ -106910,15 +161558,19 @@ + switch (s->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + /* CAPTURE on encoder is not valid. */ -+ if (ctx->dev->role == ENCODE) ++ if (ctx->dev->role == ENCODE || ctx->dev->role == ENCODE_IMAGE) + return -EINVAL; + q_data = &ctx->q_dataV4L2_M2M_DST; ++ if (ctx->component) ++ port = &ctx->component->output0; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + /* OUTPUT on deoder is not valid. */ + if (ctx->dev->role == DECODE) + return -EINVAL; + q_data = &ctx->q_dataV4L2_M2M_SRC; ++ if (ctx->component) ++ port = &ctx->component->input0; + break; + default: + return -EINVAL; @@ -106946,6 +161598,7 @@ + } + break; + case ENCODE: ++ case ENCODE_IMAGE: + switch (s->target) { + case V4L2_SEL_TGT_CROP: + /* Only support crop from (0,0) */ @@ -106962,7 +161615,6 @@ + } + break; + case ISP: -+ break; + case DEINTERLACE: + if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + switch (s->target) { @@ -107002,6 +161654,17 @@ + break; + } + ++ if (!port) ++ return 0; ++ ++ setup_mmal_port_format(ctx, q_data, port); ++ ret = vchiq_mmal_port_set_format(ctx->dev->instance, port); ++ if (ret) { ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on port, ret %d\n", ++ __func__, ret); ++ return -EINVAL; ++ } ++ + return 0; +} + @@ -107170,6 +161833,12 @@ + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + param.level = MMAL_VIDEO_LEVEL_H264_42; + break; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: ++ param.level = MMAL_VIDEO_LEVEL_H264_5; ++ break; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: ++ param.level = MMAL_VIDEO_LEVEL_H264_51; ++ break; + default: + /* Should never get here */ + break; @@ -107190,6 +161859,9 @@ + container_of(ctrl->handler, struct bcm2835_codec_ctx, hdl); + int ret = 0; + ++ if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) ++ return 0; ++ + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_BITRATE: + ctx->bitrate = ctrl->val; @@ -107249,6 +161921,17 @@ + break; + + case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: ++ /* ++ * Incorrect initial implementation meant that H264_I_PERIOD ++ * was implemented to control intra-I period. As the MMAL ++ * encoder never produces I-frames that aren't IDR frames, it ++ * should actually have been GOP_SIZE. ++ * Support both controls, but writing to H264_I_PERIOD will ++ * update GOP_SIZE. ++ */ ++ __v4l2_ctrl_s_ctrl(ctx->gop_size, ctrl->val); ++ fallthrough; ++ case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + if (!ctx->component) + break; + @@ -107330,9 +162013,23 @@ + sizeof(u32_value)); + break; + } ++ case V4L2_CID_MPEG_VIDEO_B_FRAMES: ++ ret = 0; ++ break; ++ ++ case V4L2_CID_JPEG_COMPRESSION_QUALITY: ++ if (!ctx->component) ++ break; ++ ++ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance, ++ &ctx->component->output0, ++ MMAL_PARAMETER_JPEG_Q_FACTOR, ++ &ctrl->val, ++ sizeof(ctrl->val)); ++ break; + + default: -+ v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n"); ++ v4l2_err(&ctx->dev->v4l2_dev, "Invalid control %08x\n", ctrl->id); + return -EINVAL; + } + @@ -107426,11 +162123,6 @@ +static int vidioc_try_encoder_cmd(struct file *file, void *priv, + struct v4l2_encoder_cmd *cmd) +{ -+ struct bcm2835_codec_ctx *ctx = file2ctx(file); -+ -+ if (ctx->dev->role != ENCODE) -+ return -EINVAL; -+ + switch (cmd->cmd) { + case V4L2_ENC_CMD_STOP: + break; @@ -107496,6 +162188,7 @@ +static int vidioc_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ ++ struct bcm2835_codec_ctx *ctx = file2ctx(file); + struct bcm2835_codec_fmt *fmt; + + fmt = find_format_pix_fmt(fsize->pixel_format, file2ctx(file)->dev, @@ -107514,10 +162207,10 @@ + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + + fsize->stepwise.min_width = MIN_W; -+ fsize->stepwise.max_width = MAX_W; ++ fsize->stepwise.max_width = ctx->dev->max_w; + fsize->stepwise.step_width = 2; + fsize->stepwise.min_height = MIN_H; -+ fsize->stepwise.max_height = MAX_H; ++ fsize->stepwise.max_height = ctx->dev->max_h; + fsize->stepwise.step_height = 2; + + return 0; @@ -107631,6 +162324,20 @@ + MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, + ¶ms, + sizeof(params)); ++ ++ } else if (dev->role == ENCODE_IMAGE) { ++ enable = 0; ++ vchiq_mmal_port_parameter_set(dev->instance, ++ &ctx->component->control, ++ MMAL_PARAMETER_EXIF_DISABLE, ++ &enable, ++ sizeof(enable)); ++ enable = 1; ++ vchiq_mmal_port_parameter_set(dev->instance, ++ &ctx->component->output0, ++ MMAL_PARAMETER_JPEG_IJG_SCALING, ++ &enable, ++ sizeof(enable)); + } + + setup_mmal_port_format(ctx, &ctx->q_dataV4L2_M2M_SRC, @@ -107659,7 +162366,7 @@ + goto destroy_component; + } + -+ if (dev->role == ENCODE) { ++ if (dev->role == ENCODE || dev->role == ENCODE_IMAGE) { + u32 param = 1; + + if (ctx->q_dataV4L2_M2M_SRC.sizeimage < @@ -107668,27 +162375,29 @@ + ctx->q_dataV4L2_M2M_SRC.sizeimage, + ctx->component->output0.minimum_buffer.size); + -+ /* Enable SPS Timing header so framerate information is encoded -+ * in the H264 header. -+ */ -+ vchiq_mmal_port_parameter_set(ctx->dev->instance, -+ &ctx->component->output0, -+ MMAL_PARAMETER_VIDEO_ENCODE_SPS_TIMING, -+ ¶m, sizeof(param)); -+ -+ /* Enable inserting headers into the first frame */ -+ vchiq_mmal_port_parameter_set(ctx->dev->instance, -+ &ctx->component->control, -+ MMAL_PARAMETER_VIDEO_ENCODE_HEADERS_WITH_FRAME, -+ ¶m, sizeof(param)); -+ /* -+ * Avoid fragmenting the buffers over multiple frames (unless -+ * the frame is bigger than the whole buffer) -+ */ -+ vchiq_mmal_port_parameter_set(ctx->dev->instance, -+ &ctx->component->control, -+ MMAL_PARAMETER_MINIMISE_FRAGMENTATION, -+ ¶m, sizeof(param)); ++ if (dev->role == ENCODE) { ++ /* Enable SPS Timing header so framerate information is encoded ++ * in the H264 header. ++ */ ++ vchiq_mmal_port_parameter_set(ctx->dev->instance, ++ &ctx->component->output0, ++ MMAL_PARAMETER_VIDEO_ENCODE_SPS_TIMING, ++ ¶m, sizeof(param)); ++ ++ /* Enable inserting headers into the first frame */ ++ vchiq_mmal_port_parameter_set(ctx->dev->instance, ++ &ctx->component->control, ++ MMAL_PARAMETER_VIDEO_ENCODE_HEADERS_WITH_FRAME, ++ ¶m, sizeof(param)); ++ /* ++ * Avoid fragmenting the buffers over multiple frames (unless ++ * the frame is bigger than the whole buffer) ++ */ ++ vchiq_mmal_port_parameter_set(ctx->dev->instance, ++ &ctx->component->control, ++ MMAL_PARAMETER_MINIMISE_FRAGMENTATION, ++ ¶m, sizeof(param)); ++ } + } else { + if (ctx->q_dataV4L2_M2M_DST.sizeimage < + ctx->component->output0.minimum_buffer.size) @@ -107808,7 +162517,7 @@ + } + + if (vb2_plane_size(vb, 0) < q_data->sizeimage) { -+ v4l2_err(&ctx->dev->v4l2_dev, "%s data will not fit into plane (%lu < %lu)\n", ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), + (long)q_data->sizeimage); + return -EINVAL; @@ -108139,6 +162848,96 @@ + return vb2_queue_init(dst_vq); +} + ++static void dec_add_profile_ctrls(struct bcm2835_codec_dev *const dev, ++ struct v4l2_ctrl_handler *const hdl) ++{ ++ struct v4l2_ctrl *ctrl; ++ unsigned int i; ++ const struct bcm2835_codec_fmt_list *const list = &dev->supported_fmts0; ++ ++ for (i = 0; i < list->num_entries; ++i) { ++ switch (list->listi.fourcc) { ++ case V4L2_PIX_FMT_H264: ++ ctrl = v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, ++ V4L2_CID_MPEG_VIDEO_H264_LEVEL, ++ V4L2_MPEG_VIDEO_H264_LEVEL_4_2, ++ ~(BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2)), ++ V4L2_MPEG_VIDEO_H264_LEVEL_4_0); ++ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ ctrl = v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, ++ V4L2_CID_MPEG_VIDEO_H264_PROFILE, ++ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, ++ ~(BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | ++ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | ++ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | ++ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)), ++ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH); ++ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ break; ++ case V4L2_PIX_FMT_MPEG2: ++ ctrl = v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, ++ V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL, ++ V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH, ++ ~(BIT(V4L2_MPEG_VIDEO_MPEG2_LEVEL_LOW) | ++ BIT(V4L2_MPEG_VIDEO_MPEG2_LEVEL_MAIN) | ++ BIT(V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH_1440) | ++ BIT(V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH)), ++ V4L2_MPEG_VIDEO_MPEG2_LEVEL_MAIN); ++ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ ctrl = v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, ++ V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE, ++ V4L2_MPEG_VIDEO_MPEG2_PROFILE_MAIN, ++ ~(BIT(V4L2_MPEG_VIDEO_MPEG2_PROFILE_SIMPLE) | ++ BIT(V4L2_MPEG_VIDEO_MPEG2_PROFILE_MAIN)), ++ V4L2_MPEG_VIDEO_MPEG2_PROFILE_MAIN); ++ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ break; ++ case V4L2_PIX_FMT_MPEG4: ++ ctrl = v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, ++ V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, ++ V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, ++ ~(BIT(V4L2_MPEG_VIDEO_MPEG4_LEVEL_0) | ++ BIT(V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B) | ++ BIT(V4L2_MPEG_VIDEO_MPEG4_LEVEL_1) | ++ BIT(V4L2_MPEG_VIDEO_MPEG4_LEVEL_2) | ++ BIT(V4L2_MPEG_VIDEO_MPEG4_LEVEL_3) | ++ BIT(V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B) | ++ BIT(V4L2_MPEG_VIDEO_MPEG4_LEVEL_4) | ++ BIT(V4L2_MPEG_VIDEO_MPEG4_LEVEL_5)), ++ V4L2_MPEG_VIDEO_MPEG4_LEVEL_4); ++ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ ctrl = v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, ++ V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, ++ V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE, ++ ~(BIT(V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE) | ++ BIT(V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE)), ++ V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE); ++ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ break; ++ /* No profiles defined by V4L2 */ ++ case V4L2_PIX_FMT_H263: ++ case V4L2_PIX_FMT_JPEG: ++ case V4L2_PIX_FMT_MJPEG: ++ case V4L2_PIX_FMT_VC1_ANNEX_G: ++ default: ++ break; ++ } ++ } ++} ++ +/* + * File operations + */ @@ -108166,7 +162965,7 @@ + ctx->q_dataV4L2_M2M_SRC.crop_height = DEFAULT_HEIGHT; + ctx->q_dataV4L2_M2M_SRC.height = DEFAULT_HEIGHT; + ctx->q_dataV4L2_M2M_SRC.bytesperline = -+ get_bytesperline(DEFAULT_WIDTH, ++ get_bytesperline(DEFAULT_WIDTH, DEFAULT_HEIGHT, + ctx->q_dataV4L2_M2M_SRC.fmt, + dev->role); + ctx->q_dataV4L2_M2M_SRC.sizeimage = @@ -108180,7 +162979,7 @@ + ctx->q_dataV4L2_M2M_DST.crop_height = DEFAULT_HEIGHT; + ctx->q_dataV4L2_M2M_DST.height = DEFAULT_HEIGHT; + ctx->q_dataV4L2_M2M_DST.bytesperline = -+ get_bytesperline(DEFAULT_WIDTH, ++ get_bytesperline(DEFAULT_WIDTH, DEFAULT_HEIGHT, + ctx->q_dataV4L2_M2M_DST.fmt, + dev->role); + ctx->q_dataV4L2_M2M_DST.sizeimage = @@ -108207,7 +163006,7 @@ + case ENCODE: + { + /* Encode controls */ -+ v4l2_ctrl_handler_init(hdl, 11); ++ v4l2_ctrl_handler_init(hdl, 13); + + v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, @@ -108231,7 +163030,7 @@ + 1, 60); + v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, -+ V4L2_MPEG_VIDEO_H264_LEVEL_4_2, ++ V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + ~(BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | @@ -108245,7 +163044,9 @@ + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | -+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2)), ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1)), + V4L2_MPEG_VIDEO_H264_LEVEL_4_0); + v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, @@ -108266,6 +163067,13 @@ + v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, + 0, 0, 0, 0); ++ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, ++ V4L2_CID_MPEG_VIDEO_B_FRAMES, ++ 0, 0, ++ 1, 0); ++ ctx->gop_size = v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, ++ V4L2_CID_MPEG_VIDEO_GOP_SIZE, ++ 0, 0x7FFFFFFF, 1, 60); + if (hdl->error) { + rc = hdl->error; + goto free_ctrl_handler; @@ -108276,11 +163084,12 @@ + break; + case DECODE: + { -+ v4l2_ctrl_handler_init(hdl, 1); ++ v4l2_ctrl_handler_init(hdl, 1 + dev->supported_fmts0.num_entries * 2); + + v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + 1, 1, 1, 1); ++ dec_add_profile_ctrls(dev, hdl); + if (hdl->error) { + rc = hdl->error; + goto free_ctrl_handler; @@ -108312,6 +163121,23 @@ + v4l2_ctrl_handler_init(hdl, 0); + } + break; ++ case ENCODE_IMAGE: ++ { ++ /* Encode image controls */ ++ v4l2_ctrl_handler_init(hdl, 1); ++ ++ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, ++ V4L2_CID_JPEG_COMPRESSION_QUALITY, ++ 1, 100, ++ 1, 80); ++ if (hdl->error) { ++ rc = hdl->error; ++ goto free_ctrl_handler; ++ } ++ ctx->fh.ctrl_handler = hdl; ++ v4l2_ctrl_handler_setup(hdl); ++ } ++ break; + case NUM_ROLES: + break; + } @@ -108556,6 +163382,9 @@ + if (ret) + goto vchiq_finalise; + ++ dev->max_w = MAX_W_CODEC; ++ dev->max_h = MAX_H_CODEC; ++ + switch (role) { + case DECODE: + v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); @@ -108572,18 +163401,16 @@ + video_nr = encode_video_nr; + break; + case ISP: -+ v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); -+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); + v4l2_disable_ioctl(vfd, VIDIOC_G_PARM); + function = MEDIA_ENT_F_PROC_VIDEO_SCALER; + video_nr = isp_video_nr; ++ dev->max_w = MAX_W_ISP; ++ dev->max_h = MAX_H_ISP; + break; + case DEINTERLACE: -+ v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); -+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); @@ -108591,6 +163418,12 @@ + function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; + video_nr = deinterlace_video_nr; + break; ++ case ENCODE_IMAGE: ++ v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); ++ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); ++ function = MEDIA_ENT_F_PROC_VIDEO_ENCODER; ++ video_nr = encode_image_nr; ++ break; + default: + ret = -EINVAL; + goto unreg_dev; @@ -108690,6 +163523,10 @@ + if (ret) + goto out; + ++ ret = bcm2835_codec_create(drv, &drv->encode_image, ENCODE_IMAGE); ++ if (ret) ++ goto out; ++ + /* Register the media device node */ + if (media_device_register(mdev) < 0) + goto out; @@ -108699,6 +163536,10 @@ + return 0; + +out: ++ if (drv->encode_image) { ++ bcm2835_codec_destroy(drv->encode_image); ++ drv->encode_image = NULL; ++ } + if (drv->deinterlace) { + bcm2835_codec_destroy(drv->deinterlace); + drv->deinterlace = NULL; @@ -108724,6 +163565,8 @@ + + media_device_unregister(&drv->mdev); + ++ bcm2835_codec_destroy(drv->encode_image); ++ + bcm2835_codec_destroy(drv->deinterlace); + + bcm2835_codec_destroy(drv->isp); @@ -108755,14 +163598,14 @@ +MODULE_ALIAS("platform:bcm2835-codec"); diff --git a/drivers/staging/vc04_services/bcm2835-isp/Kconfig b/drivers/staging/vc04_services/bcm2835-isp/Kconfig new file mode 100644 -index 000000000000..71b14acc297e +index 000000000000..6222799ebe16 --- /dev/null +++ b/drivers/staging/vc04_services/bcm2835-isp/Kconfig @@ -0,0 +1,14 @@ +config VIDEO_ISP_BCM2835 + tristate "BCM2835 ISP support" + depends on MEDIA_SUPPORT -+ depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST) ++ depends on VIDEO_DEV && (ARCH_BCM2835 || COMPILE_TEST) + depends on MEDIA_CONTROLLER + select BCM2835_VCHIQ_MMAL + select VIDEOBUF2_DMA_CONTIG @@ -108867,10 +163710,10 @@ +#endif diff --git a/drivers/staging/vc04_services/bcm2835-isp/bcm2835-isp-fmts.h b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-isp-fmts.h new file mode 100644 -index 000000000000..a545dbf2b5dd +index 000000000000..5ab232ff9bd9 --- /dev/null +++ b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-isp-fmts.h -@@ -0,0 +1,553 @@ +@@ -0,0 +1,558 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Broadcom BCM2835 ISP driver @@ -108907,14 +163750,19 @@ +#define V4L2_COLORSPACE_MASK_RAW V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_RAW) + +/* -+ * The colour spaces we support for YUV outputs. SRGB features here because, -+ * once you assign the default transfer func and so on, it and JPEG effectively -+ * mean the same. -+ */ -+#define V4L2_COLORSPACE_MASK_YUV (V4L2_COLORSPACE_MASK_JPEG | \ -+ V4L2_COLORSPACE_MASK_SRGB | \ -+ V4L2_COLORSPACE_MASK_SMPTE170M | \ -+ V4L2_COLORSPACE_MASK_REC709) ++ * All three colour spaces JPEG, SMPTE170M and REC709 are fundamentally sRGB ++ * underneath (as near as makes no difference to us), just with different YCbCr ++ * encodings. Therefore the ISP can generate sRGB on its main output and any of ++ * the others on its low resolution output. Applications should, when using both ++ * outputs, program the colour spaces on them to be the same, matching whatever ++ * is requested for the low resolution output, even if the main output is ++ * producing an RGB format. In turn this requires us to allow all these colour ++ * spaces for every YUV/RGB output format. ++ */ ++#define V4L2_COLORSPACE_MASK_ALL_SRGB (V4L2_COLORSPACE_MASK_JPEG | \ ++ V4L2_COLORSPACE_MASK_SRGB | \ ++ V4L2_COLORSPACE_MASK_SMPTE170M | \ ++ V4L2_COLORSPACE_MASK_REC709) + +static const struct bcm2835_isp_fmt supported_formats = { + { @@ -108924,7 +163772,7 @@ + .bytesperline_align = 64, + .mmal_fmt = MMAL_ENCODING_I420, + .size_multiplier_x2 = 3, -+ .colorspace_mask = V4L2_COLORSPACE_MASK_YUV, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, + .colorspace_default = V4L2_COLORSPACE_JPEG, + .step_size = 2, + }, { @@ -108933,7 +163781,7 @@ + .bytesperline_align = 64, + .mmal_fmt = MMAL_ENCODING_YV12, + .size_multiplier_x2 = 3, -+ .colorspace_mask = V4L2_COLORSPACE_MASK_YUV, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, + .colorspace_default = V4L2_COLORSPACE_SMPTE170M, + .step_size = 2, + }, { @@ -108942,7 +163790,7 @@ + .bytesperline_align = 32, + .mmal_fmt = MMAL_ENCODING_NV12, + .size_multiplier_x2 = 3, -+ .colorspace_mask = V4L2_COLORSPACE_MASK_YUV, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, + .colorspace_default = V4L2_COLORSPACE_SMPTE170M, + .step_size = 2, + }, { @@ -108951,7 +163799,7 @@ + .bytesperline_align = 32, + .mmal_fmt = MMAL_ENCODING_NV21, + .size_multiplier_x2 = 3, -+ .colorspace_mask = V4L2_COLORSPACE_MASK_YUV, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, + .colorspace_default = V4L2_COLORSPACE_SMPTE170M, + .step_size = 2, + }, { @@ -108960,7 +163808,7 @@ + .bytesperline_align = 64, + .mmal_fmt = MMAL_ENCODING_YUYV, + .size_multiplier_x2 = 2, -+ .colorspace_mask = V4L2_COLORSPACE_MASK_YUV, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, + .colorspace_default = V4L2_COLORSPACE_SMPTE170M, + .step_size = 2, + }, { @@ -108969,7 +163817,7 @@ + .bytesperline_align = 64, + .mmal_fmt = MMAL_ENCODING_UYVY, + .size_multiplier_x2 = 2, -+ .colorspace_mask = V4L2_COLORSPACE_MASK_YUV, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, + .colorspace_default = V4L2_COLORSPACE_SMPTE170M, + .step_size = 2, + }, { @@ -108978,7 +163826,7 @@ + .bytesperline_align = 64, + .mmal_fmt = MMAL_ENCODING_YVYU, + .size_multiplier_x2 = 2, -+ .colorspace_mask = V4L2_COLORSPACE_MASK_YUV, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, + .colorspace_default = V4L2_COLORSPACE_SMPTE170M, + .step_size = 2, + }, { @@ -108987,7 +163835,7 @@ + .bytesperline_align = 64, + .mmal_fmt = MMAL_ENCODING_VYUY, + .size_multiplier_x2 = 2, -+ .colorspace_mask = V4L2_COLORSPACE_MASK_YUV, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, + .colorspace_default = V4L2_COLORSPACE_SMPTE170M, + .step_size = 2, + }, { @@ -108997,7 +163845,7 @@ + .bytesperline_align = 32, + .mmal_fmt = MMAL_ENCODING_RGB24, + .size_multiplier_x2 = 2, -+ .colorspace_mask = V4L2_COLORSPACE_MASK_SRGB, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, + .colorspace_default = V4L2_COLORSPACE_SRGB, + .step_size = 1, + }, { @@ -109006,7 +163854,7 @@ + .bytesperline_align = 32, + .mmal_fmt = MMAL_ENCODING_RGB16, + .size_multiplier_x2 = 2, -+ .colorspace_mask = V4L2_COLORSPACE_MASK_SRGB, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, + .colorspace_default = V4L2_COLORSPACE_SRGB, + .step_size = 1, + }, { @@ -109015,7 +163863,7 @@ + .bytesperline_align = 32, + .mmal_fmt = MMAL_ENCODING_BGR24, + .size_multiplier_x2 = 2, -+ .colorspace_mask = V4L2_COLORSPACE_MASK_SRGB, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, + .colorspace_default = V4L2_COLORSPACE_SRGB, + .step_size = 1, + }, { @@ -109024,7 +163872,7 @@ + .bytesperline_align = 64, + .mmal_fmt = MMAL_ENCODING_BGRA, + .size_multiplier_x2 = 2, -+ .colorspace_mask = V4L2_COLORSPACE_MASK_SRGB, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, + .colorspace_default = V4L2_COLORSPACE_SRGB, + .step_size = 1, + }, { @@ -109033,7 +163881,7 @@ + .bytesperline_align = 64, + .mmal_fmt = MMAL_ENCODING_RGBA, + .size_multiplier_x2 = 2, -+ .colorspace_mask = V4L2_COLORSPACE_MASK_SRGB, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, + .colorspace_default = V4L2_COLORSPACE_SRGB, + .step_size = 1, + }, { @@ -109426,10 +164274,10 @@ +#endif diff --git a/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c new file mode 100644 -index 000000000000..42c43438303c +index 000000000000..c10fc6af1897 --- /dev/null +++ b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c -@@ -0,0 +1,1810 @@ +@@ -0,0 +1,1816 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Broadcom BCM2835 ISP driver @@ -109464,6 +164312,8 @@ + */ +#define BCM2835_ISP_NUM_INSTANCES 2 + ++MODULE_IMPORT_NS(DMA_BUF); ++ +static unsigned int debug; +module_param(debug, uint, 0644); +MODULE_PARM_DESC(debug, "activates debug info"); @@ -109630,9 +164480,9 @@ + +static int set_digital_gain(struct bcm2835_isp_node *node, uint32_t gain) +{ -+ struct mmal_parameter_rational digital_gain = { -+ .num = gain, -+ .den = 1000 ++ struct s32_fract digital_gain = { ++ .numerator = gain, ++ .denominator = 1000 + }; + + return set_isp_param(node, MMAL_PARAMETER_DIGITAL_GAIN, @@ -110054,7 +164904,6 @@ +{ + struct bcm2835_isp_node *node = vb2_get_drv_priv(q); + struct bcm2835_isp_dev *dev = node_get_dev(node); -+ unsigned int i; + int ret; + + v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: node %s%d, mmal port %p\n", @@ -110085,17 +164934,22 @@ + } + } + -+ /* Release the VCSM handle here to release the associated dmabuf */ -+ for (i = 0; i < q->num_buffers; i++) { -+ struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(q->bufsi); -+ struct bcm2835_isp_buffer *buf = -+ container_of(vb2, struct bcm2835_isp_buffer, vb); -+ bcm2835_isp_mmal_buf_cleanup(&buf->mmal); -+ } -+ + atomic_dec(&dev->num_streaming); + /* If all ports disabled, then disable the component */ + if (atomic_read(&dev->num_streaming) == 0) { ++ struct bcm2835_isp_lens_shading ls; ++ /* ++ * The ISP component on the firmware has a reference to the ++ * dmabuf handle for the lens shading table. Pass a null handle ++ * to remove that reference now. ++ */ ++ memset(&ls, 0, sizeof(ls)); ++ /* Must set a valid grid size for the FW */ ++ ls.grid_cell_size = 16; ++ set_isp_param(&dev->node0, ++ MMAL_PARAMETER_LENS_SHADING_OVERRIDE, ++ &ls, sizeof(ls)); ++ + ret = vchiq_mmal_component_disable(dev->mmal_instance, + dev->component); + if (ret) { @@ -110905,7 +165759,7 @@ +} + +/* Unregister one of the /dev/video<N> nodes associated with the ISP. */ -+static void unregister_node(struct bcm2835_isp_node *node) ++static void bcm2835_unregister_node(struct bcm2835_isp_node *node) +{ + struct bcm2835_isp_dev *dev = node_get_dev(node); + @@ -111107,7 +165961,7 @@ + media_controller_unregister(dev); + + for (i = 0; i < BCM2835_ISP_NUM_NODES; i++) -+ unregister_node(&dev->nodei); ++ bcm2835_unregister_node(&dev->nodei); + + v4l2_device_unregister(&dev->v4l2_dev); + @@ -111360,28 +166214,65 @@ + struct vc_sm_cma_ioctl_clean_invalid2) + +#endif /* __VC_SM_CMA_IOCTL_H */ -diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c -index 8782ebe0b39a..2a1d8d6541b2 100644 ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c -@@ -7,6 +7,7 @@ - #include <linux/interrupt.h> - #include <linux/pagemap.h> +diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +index aa2313f3bcab..def331ad5517 100644 +--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +@@ -22,6 +22,7 @@ + #include <linux/platform_device.h> + #include <linux/compat.h> #include <linux/dma-mapping.h> +#include <linux/dmapool.h> - #include <linux/io.h> - #include <linux/platform_device.h> - #include <linux/uaccess.h> -@@ -29,6 +30,8 @@ - #define BELL0 0x00 - #define BELL2 0x08 + #include <linux/rcupdate.h> + #include <linux/delay.h> + #include <linux/slab.h> +@@ -51,6 +52,8 @@ + + #define ARM_DS_ACTIVE BIT(2) +#define VCHIQ_DMA_POOL_SIZE PAGE_SIZE + + /* Override the default prefix, which would be vchiq_arm (from the filename) */ + #undef MODULE_PARAM_PREFIX + #define MODULE_PARAM_PREFIX DEVICE_NAME "." +@@ -61,15 +64,24 @@ + /* Run time control of log level, based on KERN_XXX level. */ + int vchiq_arm_log_level = VCHIQ_LOG_DEFAULT; + int vchiq_susp_log_level = VCHIQ_LOG_ERROR; ++module_param_named(arm_log_level, vchiq_arm_log_level, int, 0644); ++module_param_named(susp_log_level, vchiq_susp_log_level, int, 0644); ++module_param_named(core_log_level, vchiq_core_log_level, int, 0644); ++module_param_named(core_msg_log_level, vchiq_core_msg_log_level, int, 0644); ++module_param_named(sync_log_level, vchiq_sync_log_level, int, 0644); + + DEFINE_SPINLOCK(msg_queue_spinlock); + struct vchiq_state g_state; + + static struct platform_device *bcm2835_camera; + static struct platform_device *bcm2835_audio; ++static struct platform_device *bcm2835_codec; ++static struct platform_device *vcsm_cma; ++static struct platform_device *bcm2835_isp; + + struct vchiq_drvdata { + const unsigned int cache_line_size; ++ const bool use_36bit_addrs; + struct rpi_firmware *fw; + }; + +@@ -115,6 +127,11 @@ struct vchiq_arm_state { + int first_connect; + }; + ++static struct vchiq_drvdata bcm2711_drvdata = { ++ .cache_line_size = 64, ++ .use_36bit_addrs = true, ++}; ++ struct vchiq_2835_state { int inited; struct vchiq_arm_state arm_state; -@@ -38,6 +41,7 @@ struct vchiq_pagelist_info { +@@ -124,6 +141,7 @@ struct vchiq_pagelist_info { struct pagelist *pagelist; size_t pagelist_buffer_size; dma_addr_t dma_addr; @@ -111389,7 +166280,7 @@ enum dma_data_direction dma_dir; unsigned int num_pages; unsigned int pages_need_release; -@@ -58,11 +62,14 @@ static void __iomem *g_regs; +@@ -144,10 +162,13 @@ static void __iomem *g_regs; * of 32. */ static unsigned int g_cache_line_size = 32; @@ -111399,89 +166290,15 @@ static char *g_fragments_base; static char *g_free_fragments; static struct semaphore g_free_fragments_sema; - static struct device *g_dev; +static struct device *g_dma_dev; - static DEFINE_SEMAPHORE(g_free_fragments_mutex); - -@@ -79,6 +86,7 @@ free_pagelist(struct vchiq_pagelist_info *pagelistinfo, - int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state) - { - struct device *dev = &pdev->dev; -+ struct device *dma_dev = NULL; - struct vchiq_drvdata *drvdata = platform_get_drvdata(pdev); - struct rpi_firmware *fw = drvdata->fw; - struct vchiq_slot_zero *vchiq_slot_zero; -@@ -100,6 +108,24 @@ int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state) - g_cache_line_size = drvdata->cache_line_size; - g_fragments_size = 2 * g_cache_line_size; - -+ if (drvdata->use_36bit_addrs) { -+ struct device_node *dma_node = -+ of_find_compatible_node(NULL, NULL, "brcm,bcm2711-dma"); -+ -+ if (dma_node) { -+ struct platform_device *pdev; -+ -+ pdev = of_find_device_by_node(dma_node); -+ if (pdev) -+ dma_dev = &pdev->dev; -+ of_node_put(dma_node); -+ g_use_36bit_addrs = true; -+ } else { -+ dev_err(dev, "40-bit DMA controller not found\n"); -+ return -EINVAL; -+ } -+ } -+ - /* Allocate space for the channels in coherent memory */ - slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE); - frag_mem_size = PAGE_ALIGN(g_fragments_size * MAX_FRAGMENTS); -@@ -112,13 +138,14 @@ int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state) - } - - WARN_ON(((unsigned long)slot_mem & (PAGE_SIZE - 1)) != 0); -+ channelbase = slot_phys; - - vchiq_slot_zero = vchiq_init_slots(slot_mem, slot_mem_size); - if (!vchiq_slot_zero) - return -EINVAL; - - vchiq_slot_zero->platform_dataVCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX = -- (int)slot_phys + slot_mem_size; -+ channelbase + slot_mem_size; - vchiq_slot_zero->platform_dataVCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX = - MAX_FRAGMENTS; - -@@ -151,7 +178,6 @@ int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state) - } - - /* Send the base address of the slots to VideoCore */ -- channelbase = slot_phys; - err = rpi_firmware_property(fw, RPI_FIRMWARE_VCHIQ_INIT, - &channelbase, sizeof(channelbase)); - if (err || channelbase) { -@@ -160,6 +186,15 @@ int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state) - } + static DEFINE_SEMAPHORE(g_free_fragments_mutex, 1); - g_dev = dev; -+ g_dma_dev = dma_dev ?: dev; -+ g_dma_pool = dmam_pool_create("vchiq_scatter_pool", dev, -+ VCHIQ_DMA_POOL_SIZE, g_cache_line_size, -+ 0); -+ if (!g_dma_pool) { -+ dev_err(dev, "failed to create dma pool"); -+ return -ENOMEM; -+ } -+ - vchiq_log_info(vchiq_arm_log_level, - "vchiq_init - done (slots %pK, phys %pad)", - vchiq_slot_zero, &slot_phys); -@@ -284,15 +319,21 @@ static void - cleanup_pagelistinfo(struct vchiq_pagelist_info *pagelistinfo) +@@ -177,15 +198,20 @@ static void + cleanup_pagelistinfo(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagelistinfo) { if (pagelistinfo->scatterlist_mapped) { -- dma_unmap_sg(g_dev, pagelistinfo->scatterlist, +- dma_unmap_sg(instance->state->dev, pagelistinfo->scatterlist, + dma_unmap_sg(g_dma_dev, pagelistinfo->scatterlist, pagelistinfo->num_pages, pagelistinfo->dma_dir); } @@ -111489,20 +166306,19 @@ if (pagelistinfo->pages_need_release) unpin_user_pages(pagelistinfo->pages, pagelistinfo->num_pages); -- dma_free_coherent(g_dev, pagelistinfo->pagelist_buffer_size, +- dma_free_coherent(instance->state->dev, pagelistinfo->pagelist_buffer_size, - pagelistinfo->pagelist, pagelistinfo->dma_addr); + if (pagelistinfo->is_from_pool) { + dma_pool_free(g_dma_pool, pagelistinfo->pagelist, + pagelistinfo->dma_addr); + } else { -+ dma_free_coherent(g_dev, pagelistinfo->pagelist_buffer_size, -+ pagelistinfo->pagelist, -+ pagelistinfo->dma_addr); ++ dma_free_coherent(instance->state->dev, pagelistinfo->pagelist_buffer_size, ++ pagelistinfo->pagelist, pagelistinfo->dma_addr); + } } - /* There is a potential problem with partial cache lines (pages?) -@@ -313,6 +354,7 @@ create_pagelist(char *buf, char __user *ubuf, + static inline bool +@@ -220,6 +246,7 @@ create_pagelist(struct vchiq_instance *instance, char *buf, char __user *ubuf, u32 *addrs; unsigned int num_pages, offset, i, k; int actual_pages; @@ -111510,17 +166326,15 @@ size_t pagelist_size; struct scatterlist *scatterlist, *sg; int dma_buffers; -@@ -342,8 +384,16 @@ create_pagelist(char *buf, char __user *ubuf, +@@ -249,8 +276,14 @@ create_pagelist(struct vchiq_instance *instance, char *buf, char __user *ubuf, /* Allocate enough storage to hold the page pointers and the page * list */ -- pagelist = dma_alloc_coherent(g_dev, pagelist_size, &dma_addr, +- pagelist = dma_alloc_coherent(instance->state->dev, pagelist_size, &dma_addr, - GFP_KERNEL); + if (pagelist_size > VCHIQ_DMA_POOL_SIZE) { -+ pagelist = dma_alloc_coherent(g_dev, -+ pagelist_size, -+ &dma_addr, -+ GFP_KERNEL); ++ pagelist = dma_alloc_coherent(instance->state->dev, pagelist_size, &dma_addr, ++ GFP_KERNEL); + is_from_pool = false; + } else { + pagelist = dma_pool_alloc(g_dma_pool, GFP_KERNEL, &dma_addr); @@ -111529,7 +166343,7 @@ vchiq_log_trace(vchiq_arm_log_level, "%s - %pK", __func__, pagelist); -@@ -364,6 +414,7 @@ create_pagelist(char *buf, char __user *ubuf, +@@ -271,6 +304,7 @@ create_pagelist(struct vchiq_instance *instance, char *buf, char __user *ubuf, pagelistinfo->pagelist = pagelist; pagelistinfo->pagelist_buffer_size = pagelist_size; pagelistinfo->dma_addr = dma_addr; @@ -111537,16 +166351,16 @@ pagelistinfo->dma_dir = (type == PAGELIST_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE; pagelistinfo->num_pages = num_pages; -@@ -433,7 +484,7 @@ create_pagelist(char *buf, char __user *ubuf, +@@ -337,7 +371,7 @@ create_pagelist(struct vchiq_instance *instance, char *buf, char __user *ubuf, count -= len; } -- dma_buffers = dma_map_sg(g_dev, +- dma_buffers = dma_map_sg(instance->state->dev, + dma_buffers = dma_map_sg(g_dma_dev, scatterlist, num_pages, pagelistinfo->dma_dir); -@@ -447,25 +498,60 @@ create_pagelist(char *buf, char __user *ubuf, +@@ -351,22 +385,61 @@ create_pagelist(struct vchiq_instance *instance, char *buf, char __user *ubuf, /* Combine adjacent blocks for performance */ k = 0; @@ -111561,10 +166375,7 @@ - WARN_ON(len == 0); - WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK)); - WARN_ON(i && (addr & ~PAGE_MASK)); -- if (k > 0 && -- ((addrsk - 1 & PAGE_MASK) + -- (((addrsk - 1 & ~PAGE_MASK) + 1) << PAGE_SHIFT)) -- == (addr & PAGE_MASK)) +- if (is_adjacent_block(addrs, addr, k)) - addrsk - 1 += ((len + PAGE_SIZE - 1) >> PAGE_SHIFT); - else - addrsk++ = (addr & PAGE_MASK) | @@ -111585,6 +166396,7 @@ + (i != (dma_buffers - 1)) && (len & ~PAGE_MASK)); + WARN_ON(i && (addr & ~PAGE_MASK)); + WARN_ON(upper_32_bits(addr) > 0xf); ++ + if (k > 0 && + ((addrsk - 1 & ~0xff) + + (((addrsk - 1 & 0xff) + 1) << 8) @@ -111626,42 +166438,89 @@ } /* Partial cache lines (fragments) require special measures */ -@@ -509,7 +595,7 @@ free_pagelist(struct vchiq_pagelist_info *pagelistinfo, +@@ -410,7 +483,7 @@ free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagel * NOTE: dma_unmap_sg must be called before the * cpu can touch any of the data/pages. */ -- dma_unmap_sg(g_dev, pagelistinfo->scatterlist, +- dma_unmap_sg(instance->state->dev, pagelistinfo->scatterlist, + dma_unmap_sg(g_dma_dev, pagelistinfo->scatterlist, pagelistinfo->num_pages, pagelistinfo->dma_dir); pagelistinfo->scatterlist_mapped = 0; -diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -index 3d378da119e7..a936102dbc34 100644 ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -@@ -109,6 +109,9 @@ static struct class *vchiq_class; - static DEFINE_SPINLOCK(msg_queue_spinlock); - static struct platform_device *bcm2835_camera; - static struct platform_device *bcm2835_audio; -+static struct platform_device *bcm2835_codec; -+static struct platform_device *vcsm_cma; -+static struct platform_device *bcm2835_isp; +@@ -465,6 +538,7 @@ free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagel + static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state) + { + struct device *dev = &pdev->dev; ++ struct device *dma_dev = NULL; + struct vchiq_drvdata *drvdata = platform_get_drvdata(pdev); + struct rpi_firmware *fw = drvdata->fw; + struct vchiq_slot_zero *vchiq_slot_zero; +@@ -486,6 +560,24 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state + g_cache_line_size = drvdata->cache_line_size; + g_fragments_size = 2 * g_cache_line_size; - static struct vchiq_drvdata bcm2835_drvdata = { - .cache_line_size = 32, -@@ -118,6 +121,11 @@ static struct vchiq_drvdata bcm2836_drvdata = { - .cache_line_size = 64, - }; ++ if (drvdata->use_36bit_addrs) { ++ struct device_node *dma_node = ++ of_find_compatible_node(NULL, NULL, "brcm,bcm2711-dma"); ++ ++ if (dma_node) { ++ struct platform_device *pdev; ++ ++ pdev = of_find_device_by_node(dma_node); ++ if (pdev) ++ dma_dev = &pdev->dev; ++ of_node_put(dma_node); ++ g_use_36bit_addrs = true; ++ } else { ++ dev_err(dev, "40-bit DMA controller not found\n"); ++ return -EINVAL; ++ } ++ } ++ + /* Allocate space for the channels in coherent memory */ + slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE); + frag_mem_size = PAGE_ALIGN(g_fragments_size * MAX_FRAGMENTS); +@@ -498,13 +590,14 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state + } -+static struct vchiq_drvdata bcm2711_drvdata = { -+ .cache_line_size = 64, -+ .use_36bit_addrs = true, -+}; + WARN_ON(((unsigned long)slot_mem & (PAGE_SIZE - 1)) != 0); ++ channelbase = slot_phys; + + vchiq_slot_zero = vchiq_init_slots(slot_mem, slot_mem_size); + if (!vchiq_slot_zero) + return -ENOMEM; + + vchiq_slot_zero->platform_dataVCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX = +- (int)slot_phys + slot_mem_size; ++ channelbase + slot_mem_size; + vchiq_slot_zero->platform_dataVCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX = + MAX_FRAGMENTS; + +@@ -538,7 +631,6 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state + } + + /* Send the base address of the slots to VideoCore */ +- channelbase = slot_phys; + err = rpi_firmware_property(fw, RPI_FIRMWARE_VCHIQ_INIT, + &channelbase, sizeof(channelbase)); + if (err) { +@@ -552,6 +644,15 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state + return -ENXIO; + } + ++ g_dma_dev = dma_dev ?: dev; ++ g_dma_pool = dmam_pool_create("vchiq_scatter_pool", dev, ++ VCHIQ_DMA_POOL_SIZE, g_cache_line_size, ++ 0); ++ if (!g_dma_pool) { ++ dev_err(dev, "failed to create dma pool"); ++ return -ENOMEM; ++ } + - static const char *const ioctl_names = { - "CONNECT", - "SHUTDOWN", -@@ -2679,6 +2687,7 @@ void vchiq_platform_conn_state_changed(struct vchiq_state *state, + vchiq_log_info(vchiq_arm_log_level, "vchiq_init - done (slots %pK, phys %pad)", + vchiq_slot_zero, &slot_phys); + +@@ -1765,6 +1866,7 @@ void vchiq_platform_conn_state_changed(struct vchiq_state *state, static const struct of_device_id vchiq_of_match = { { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata }, { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata }, @@ -111669,7 +166528,7 @@ {}, }; MODULE_DEVICE_TABLE(of, vchiq_of_match); -@@ -2688,6 +2697,7 @@ vchiq_register_child(struct platform_device *pdev, const char *name) +@@ -1774,6 +1876,7 @@ vchiq_register_child(struct platform_device *pdev, const char *name) { struct platform_device_info pdevinfo; struct platform_device *child; @@ -111677,7 +166536,7 @@ memset(&pdevinfo, 0, sizeof(pdevinfo)); -@@ -2696,12 +2706,32 @@ vchiq_register_child(struct platform_device *pdev, const char *name) +@@ -1782,12 +1885,32 @@ vchiq_register_child(struct platform_device *pdev, const char *name) pdevinfo.id = PLATFORM_DEVID_NONE; pdevinfo.dma_mask = DMA_BIT_MASK(32); @@ -111710,9 +166569,9 @@ return child; } -@@ -2759,8 +2789,11 @@ static int vchiq_probe(struct platform_device *pdev) - VCHIQ_VERSION, VCHIQ_VERSION_MIN, - MAJOR(vchiq_devid), MINOR(vchiq_devid)); +@@ -1838,8 +1961,11 @@ static int vchiq_probe(struct platform_device *pdev) + goto error_exit; + } + vcsm_cma = vchiq_register_child(pdev, "vcsm-cma"); + bcm2835_codec = vchiq_register_child(pdev, "bcm2835-codec"); @@ -111722,9 +166581,9 @@ return 0; -@@ -2773,8 +2806,11 @@ static int vchiq_probe(struct platform_device *pdev) +@@ -1851,8 +1977,11 @@ static int vchiq_probe(struct platform_device *pdev) - static int vchiq_remove(struct platform_device *pdev) + static void vchiq_remove(struct platform_device *pdev) { + platform_device_unregister(bcm2835_isp); platform_device_unregister(bcm2835_audio); @@ -111732,20 +166591,8 @@ + platform_device_unregister(bcm2835_codec); + platform_device_unregister(vcsm_cma); vchiq_debugfs_deinit(); - device_destroy(vchiq_class, vchiq_devid); - cdev_del(&vchiq_cdev); -diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h -index 0784c5002417..f8b1c005af62 100644 ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h -@@ -52,6 +52,7 @@ struct vchiq_arm_state { - - struct vchiq_drvdata { - const unsigned int cache_line_size; -+ const bool use_36bit_addrs; - struct rpi_firmware *fw; - }; - + vchiq_deregister_chrdev(); + } diff --git a/drivers/staging/vc04_services/vc-sm-cma/Kconfig b/drivers/staging/vc04_services/vc-sm-cma/Kconfig new file mode 100644 index 000000000000..d812021385a0 @@ -111789,7 +166636,7 @@ +No currently outstanding tasks except some clean-up. diff --git a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c new file mode 100644 -index 000000000000..88c4df822922 +index 000000000000..34155d62a450 --- /dev/null +++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c @@ -0,0 +1,1707 @@ @@ -111850,6 +166697,8 @@ +#include "vc_sm_knl.h" +#include <linux/broadcom/vc_sm_cma_ioctl.h> + ++MODULE_IMPORT_NS(DMA_BUF); ++ +/* ---- Private Constants and Types --------------------------------------- */ + +#define DEVICE_NAME "vcsm-cma" @@ -111899,6 +166748,7 @@ + * has finished with a resource. + */ + u32 int_trans_id; /* Interrupted transaction. */ ++ struct vchiq_instance *vchiq_instance; +}; + +struct vc_sm_dma_buf_attachment { @@ -112047,7 +166897,7 @@ + buffer->import.sgt = NULL; + } + if (buffer->import.attach) { -+ dma_buf_detach(buffer->dma_buf, buffer->import.attach); ++ dma_buf_detach(buffer->import.dma_buf, buffer->import.attach); + buffer->import.attach = NULL; + } +} @@ -112236,16 +167086,13 @@ +{ + struct vc_sm_dma_buf_attachment *a = attachment->priv; + /* stealing dmabuf mutex to serialize map/unmap operations */ -+ struct mutex *lock = &attachment->dmabuf->lock; + struct sg_table *table; + -+ mutex_lock(lock); + pr_debug("%s attachment %p\n", __func__, attachment); + table = &a->sg_table; + + /* return previously mapped sg table */ + if (a->dma_dir == direction) { -+ mutex_unlock(lock); + return table; + } + @@ -112261,12 +167108,10 @@ + table->orig_nents, direction); + if (!table->nents) { + pr_err("failed to map scatterlist\n"); -+ mutex_unlock(lock); + return ERR_PTR(-EIO); + } + + a->dma_dir = direction; -+ mutex_unlock(lock); + + pr_debug("%s attachment %p\n", __func__, attachment); + return table; @@ -112288,8 +167133,6 @@ + pr_debug("%s dmabuf %p, buf %p, vm_start %08lX\n", __func__, dmabuf, + buf, vma->vm_start); + -+ mutex_lock(&buf->lock); -+ + /* now map it to userspace */ + vma->vm_pgoff = 0; + @@ -112301,9 +167144,7 @@ + return ret; + } + -+ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; -+ -+ mutex_unlock(&buf->lock); ++ vm_flags_reset(vma, vma->vm_flags | VM_DONTEXPAND | VM_DONTDUMP); + + if (ret) + pr_err("%s: failure mapping buffer to userspace\n", @@ -112325,7 +167166,7 @@ + + pr_debug("%s dmabuf %p, buffer %p\n", __func__, dmabuf, buffer); + -+ buffer->in_use = 0; ++ buffer->in_use = false; + + /* Unmap on the VPU */ + vc_sm_vpu_free(buffer); @@ -112515,6 +167356,7 @@ + struct dma_buf_attachment *attach = NULL; + struct sg_table *sgt = NULL; + dma_addr_t dma_addr; ++ u32 cache_alias; + int ret = 0; + int status; + @@ -112557,9 +167399,13 @@ + import.type = VC_SM_ALLOC_NON_CACHED; + dma_addr = sg_dma_address(sgt->sgl); + import.addr = (u32)dma_addr; -+ if ((import.addr & 0xC0000000) != 0xC0000000) { ++ cache_alias = import.addr & 0xC0000000; ++ if (cache_alias != 0xC0000000 && cache_alias != 0x80000000) { + pr_err("%s: Expecting an uncached alias for dma_addr %pad\n", + __func__, &dma_addr); ++ /* Note that this assumes we're on >= Pi2, but it implies a ++ * DT configuration error. ++ */ + import.addr |= 0xC0000000; + } + import.size = sg_dma_len(sgt->sgl); @@ -112600,13 +167446,13 @@ + buffer->size = import.size; + buffer->vpu_state = VPU_MAPPED; + -+ buffer->imported = 1; ++ buffer->imported = true; + buffer->import.dma_buf = dma_buf; + + buffer->import.attach = attach; + buffer->import.sgt = sgt; + buffer->dma_addr = dma_addr; -+ buffer->in_use = 1; ++ buffer->in_use = true; + buffer->kernel_id = import.kernel_id; + + /* @@ -113037,7 +167883,9 @@ + return NULL; + + case VC_SM_CACHE_OP_INV: ++ return dmac_inv_range; + case VC_SM_CACHE_OP_CLEAN: ++ return dmac_clean_range; + case VC_SM_CACHE_OP_FLUSH: + return dmac_flush_range; + @@ -113277,7 +168125,6 @@ +static void vc_sm_connected_init(void) +{ + int ret; -+ struct vchiq_instance *vchiq_instance; + struct vc_sm_version version; + struct vc_sm_result_t version_result; + @@ -113287,7 +168134,7 @@ + * Initialize and create a VCHI connection for the shared memory service + * running on videocore. + */ -+ ret = vchiq_initialise(&vchiq_instance); ++ ret = vchiq_initialise(&sm_state->vchiq_instance); + if (ret) { + pr_err("%s: failed to initialise VCHI instance (ret=%d)\n", + __func__, ret); @@ -113295,7 +168142,7 @@ + return; + } + -+ ret = vchiq_connect(vchiq_instance); ++ ret = vchiq_connect(sm_state->vchiq_instance); + if (ret) { + pr_err("%s: failed to connect VCHI instance (ret=%d)\n", + __func__, ret); @@ -113304,7 +168151,7 @@ + } + + /* Initialize an instance of the shared memory service. */ -+ sm_state->sm_handle = vc_sm_cma_vchi_init(vchiq_instance, 1, ++ sm_state->sm_handle = vc_sm_cma_vchi_init(sm_state->vchiq_instance, 1, + vc_sm_vpu_event); + if (!sm_state->sm_handle) { + pr_err("%s: failed to initialize shared memory service\n", @@ -113362,7 +168209,7 @@ + misc_deregister(&sm_state->misc_dev); +err_remove_debugfs: + debugfs_remove_recursive(sm_state->dir_root); -+ vc_sm_cma_vchi_stop(&sm_state->sm_handle); ++ vc_sm_cma_vchi_stop(sm_state->vchiq_instance, &sm_state->sm_handle); +} + +/* Driver loading. */ @@ -113400,7 +168247,7 @@ + debugfs_remove_recursive(sm_state->dir_root); + + /* Stop the videocore shared memory service. */ -+ vc_sm_cma_vchi_stop(&sm_state->sm_handle); ++ vc_sm_cma_vchi_stop(sm_state->vchiq_instance, &sm_state->sm_handle); + } + + if (sm_state) { @@ -113502,7 +168349,7 @@ +MODULE_ALIAS("platform:vcsm-cma"); diff --git a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h new file mode 100644 -index 000000000000..f1c7b95b14ce +index 000000000000..2f0dc7045da6 --- /dev/null +++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h @@ -0,0 +1,84 @@ @@ -113565,8 +168412,8 @@ + + char nameVC_SM_MAX_NAME_LEN; + -+ int in_use:1; /* Kernel is still using this resource */ -+ int imported:1; /* Imported dmabuf */ ++ bool in_use:1; /* Kernel is still using this resource */ ++ bool imported:1; /* Imported dmabuf */ + + enum vc_sm_vpu_mapping_state vpu_state; + u32 vc_handle; /* VideoCore handle for this buffer */ @@ -113592,10 +168439,10 @@ +#endif diff --git a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c new file mode 100644 -index 000000000000..122f2f66096f +index 000000000000..ddfef55d289d --- /dev/null +++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c -@@ -0,0 +1,503 @@ +@@ -0,0 +1,511 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * VideoCore Shared Memory CMA allocator @@ -113668,7 +168515,7 @@ + struct list_head free_list; + + struct semaphore free_sema; -+ ++ struct vchiq_instance *vchiq_instance; +}; + +/* ---- Private Variables ------------------------------------------------ */ @@ -113677,11 +168524,11 @@ + +/* ---- Private Functions ------------------------------------------------ */ +static int -+bcm2835_vchi_msg_queue(unsigned int handle, ++bcm2835_vchi_msg_queue(struct vchiq_instance *vchiq_instance, unsigned int handle, + void *data, + unsigned int size) +{ -+ return vchiq_queue_kernel_message(handle, data, size); ++ return vchiq_queue_kernel_message(vchiq_instance, handle, data, size); +} + +static struct @@ -113785,12 +168632,12 @@ + + while (1) { + if (svc_use) -+ vchiq_release_service(instance->service_handle0); ++ vchiq_release_service(instance->vchiq_instance, instance->service_handle0); + svc_use = 0; + + if (wait_for_completion_interruptible(&instance->io_cmplt)) + continue; -+ vchiq_use_service(instance->service_handle0); ++ vchiq_use_service(instance->vchiq_instance, instance->service_handle0); + svc_use = 1; + + do { @@ -113810,7 +168657,8 @@ + mutex_unlock(&instance->lock); + /* Send the command */ + status = -+ bcm2835_vchi_msg_queue(instance->service_handle0, ++ bcm2835_vchi_msg_queue(instance->vchiq_instance, ++ instance->service_handle0, + cmd->msg, cmd->length); + if (status) { + pr_err("%s: failed to queue message (%d)", @@ -113833,7 +168681,8 @@ + + } while (1); + -+ while ((header = vchiq_msg_hold(instance->service_handle0))) { ++ while ((header = vchiq_msg_hold(instance->vchiq_instance, ++ instance->service_handle0))) { + reply = (struct vc_sm_result_t *)header->data; + if (reply->trans_id & 0x80000000) { + /* Async event or cmd from the VPU */ @@ -113845,7 +168694,8 @@ + header->size); + } + -+ vchiq_release_message(instance->service_handle0, ++ vchiq_release_message(instance->vchiq_instance, ++ instance->service_handle0, + header); + } + @@ -113862,25 +168712,28 @@ + return 0; +} + -+static enum vchiq_status vc_sm_cma_vchi_callback(enum vchiq_reason reason, ++static int vc_sm_cma_vchi_callback(struct vchiq_instance *vchiq_instance, ++ enum vchiq_reason reason, + struct vchiq_header *header, + unsigned int handle, void *userdata) +{ -+ struct sm_instance *instance = vchiq_get_service_userdata(handle); ++ struct sm_instance *instance = vchiq_get_service_userdata(vchiq_instance, handle); + + switch (reason) { + case VCHIQ_MESSAGE_AVAILABLE: -+ vchiq_msg_queue_push(handle, header); ++ vchiq_msg_queue_push(vchiq_instance, handle, header); + complete(&instance->io_cmplt); + break; + + case VCHIQ_SERVICE_CLOSED: + pr_info("%s: service CLOSED!!", __func__); ++ break; ++ + default: + break; + } + -+ return VCHIQ_SUCCESS; ++ return 0; +} + +struct sm_instance *vc_sm_cma_vchi_init(struct vchiq_instance *vchiq_instance, @@ -113916,6 +168769,8 @@ + list_add(&instance->free_blki.head, &instance->free_list); + } + ++ instance->vchiq_instance = vchiq_instance; ++ + /* Open the VCHI service connections */ + instance->num_connections = num_connections; + for (i = 0; i < num_connections; i++) { @@ -113954,7 +168809,7 @@ +err_close_services: + for (i = 0; i < instance->num_connections; i++) { + if (instance->service_handlei) -+ vchiq_close_service(instance->service_handlei); ++ vchiq_close_service(vchiq_instance, instance->service_handlei); + } + kfree(instance); +err_null: @@ -113962,7 +168817,7 @@ + return NULL; +} + -+int vc_sm_cma_vchi_stop(struct sm_instance **handle) ++int vc_sm_cma_vchi_stop(struct vchiq_instance *vchiq_instance, struct sm_instance **handle) +{ + struct sm_instance *instance; + u32 i; @@ -113981,8 +168836,8 @@ + + /* Close all VCHI service connections */ + for (i = 0; i < instance->num_connections; i++) { -+ vchiq_use_service(instance->service_handlei); -+ vchiq_close_service(instance->service_handlei); ++ vchiq_use_service(vchiq_instance, instance->service_handlei); ++ vchiq_close_service(vchiq_instance, instance->service_handlei); + } + + kfree(instance); @@ -114101,7 +168956,7 @@ +} diff --git a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h new file mode 100644 -index 000000000000..ed881c56d69c +index 000000000000..a4f40d4cef05 --- /dev/null +++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h @@ -0,0 +1,63 @@ @@ -114142,7 +168997,7 @@ +/* + * Terminates the shared memory service. + */ -+int vc_sm_cma_vchi_stop(struct sm_instance **handle); ++int vc_sm_cma_vchi_stop(struct vchiq_instance *vchi_instance, struct sm_instance **handle); + +/* + * Ask the shared memory service to free up some memory that was previously @@ -114519,7 +169374,7 @@ Enables the MMAL API over VCHIQ interface as used for the majority of the multimedia services on VideoCore. diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h -index 5bd7410a034a..72e5a0386c5b 100644 +index b33129403a30..a643cad54b12 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h @@ -50,6 +50,11 @@ struct mmal_buffer { @@ -114535,7 +169390,7 @@ u32 mmal_flags; s64 dts; diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h b/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h -index 2be9941a1f30..59f7ad3a5b3b 100644 +index e15ae7b24f73..d8d7ec5b962c 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h @@ -69,10 +69,76 @@ @@ -114615,8 +169470,29 @@ /* }@ */ /** \name Pre-defined audio encodings */ +diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-msg-format.h b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg-format.h +index 5569876d8c7d..e8f5ca85a7c4 100644 +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-msg-format.h ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg-format.h +@@ -53,6 +53,16 @@ union mmal_es_specific_format { + struct mmal_subpicture_format subpicture; + }; + ++/* The elementary stream will already be framed */ ++#define MMAL_ES_FORMAT_FLAG_FRAMED BIT(0) ++/* ++ * For column formats we ideally want to pass in the column stride. This hasn't ++ * been the past behaviour, so require a new flag to be set should ++ * es->video.width be the column stride (in lines) instead of an ignored width ++ * value. ++ */ ++#define MMAL_ES_FORMAT_FLAG_COL_FMTS_WIDTH_IS_COL_STRIDE BIT(1) ++ + /* Definition of an elementary stream format (MMAL_ES_FORMAT_T) */ + struct mmal_es_format_local { + u32 type; /* enum mmal_es_type */ diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h -index b636e889c8a1..883b77ffae25 100644 +index 471413248a14..baf37254645a 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h @@ -253,6 +253,25 @@ struct mmal_msg_port_action_reply { @@ -114688,10 +169564,10 @@ u32 client_component; /* component context */ diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h b/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h -index a1e39b1b1701..21087496a481 100644 +index a0cdd28101f2..825daadf2fea 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h -@@ -221,6 +221,64 @@ enum mmal_parameter_camera_type { +@@ -223,6 +223,66 @@ enum mmal_parameter_camera_type { MMAL_PARAMETER_SHUTTER_SPEED, /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */ MMAL_PARAMETER_CUSTOM_AWB_GAINS, @@ -114753,10 +169629,12 @@ + MMAL_PARAMETER_GAMMA, + /**< Takes a @ref MMAL_PARAMETER_CDN_T */ + MMAL_PARAMETER_CDN, ++ /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_JPEG_IJG_SCALING, }; - struct mmal_parameter_rational { -@@ -313,6 +371,7 @@ enum mmal_parameter_awbmode { + enum mmal_parameter_camera_config_timestamp_mode { +@@ -310,6 +370,7 @@ enum mmal_parameter_awbmode { MMAL_PARAM_AWBMODE_INCANDESCENT, MMAL_PARAM_AWBMODE_FLASH, MMAL_PARAM_AWBMODE_HORIZON, @@ -114764,7 +169642,7 @@ }; enum mmal_parameter_imagefx { -@@ -339,6 +398,9 @@ enum mmal_parameter_imagefx { +@@ -336,6 +397,9 @@ enum mmal_parameter_imagefx { MMAL_PARAM_IMAGEFX_COLOURPOINT, MMAL_PARAM_IMAGEFX_COLOURBALANCE, MMAL_PARAM_IMAGEFX_CARTOON, @@ -114774,7 +169652,7 @@ }; enum MMAL_PARAM_FLICKERAVOID { -@@ -580,7 +642,49 @@ enum mmal_parameter_video_type { +@@ -577,7 +641,49 @@ enum mmal_parameter_video_type { MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG, /**< @ref MMAL_PARAMETER_BOOLEAN_T */ @@ -114825,7 +169703,7 @@ }; /** Valid mirror modes */ -@@ -711,6 +815,43 @@ struct mmal_parameter_displayregion { +@@ -708,6 +814,43 @@ struct mmal_parameter_displayregion { u32 alpha; }; @@ -114869,7 +169747,7 @@ #define MMAL_MAX_IMAGEFX_PARAMETERS 5 struct mmal_parameter_imagefx_parameters { -@@ -749,7 +890,113 @@ struct mmal_parameter_camera_info { +@@ -746,7 +889,113 @@ struct mmal_parameter_camera_info { struct mmal_parameter_camera_info_camera camerasMMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS; struct mmal_parameter_camera_info_flash @@ -114878,7 +169756,7 @@ +}; + +struct mmal_parameter_ccm { -+ struct mmal_parameter_rational ccm33; ++ struct s32_fract ccm33; + s32 offsets3; +}; + @@ -114932,7 +169810,7 @@ +struct mmal_parameter_geq { + u32 enabled; + u32 offset; -+ struct mmal_parameter_rational slope; ++ struct s32_fract slope; +}; + +#define MMAL_NUM_GAMMA_PTS 33 @@ -114956,15 +169834,15 @@ +struct mmal_parameter_denoise { + u32 enabled; + u32 constant; -+ struct mmal_parameter_rational slope; -+ struct mmal_parameter_rational strength; ++ struct s32_fract slope; ++ struct s32_fract strength; +}; + +struct mmal_parameter_sharpen { + u32 enabled; -+ struct mmal_parameter_rational threshold; -+ struct mmal_parameter_rational strength; -+ struct mmal_parameter_rational limit; ++ struct s32_fract threshold; ++ struct s32_fract strength; ++ struct s32_fract limit; +}; + +enum mmal_dpc_mode { @@ -114985,34 +169863,18 @@ #endif diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -index d697ea55a0da..a6cdc7dc9c30 100644 +index 258aa0e37f55..86a4c5260278 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -@@ -15,21 +15,33 @@ - - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -+#include <linux/completion.h> - #include <linux/errno.h> - #include <linux/kernel.h> -+#include <linux/mm.h> - #include <linux/module.h> - #include <linux/mutex.h> --#include <linux/mm.h> --#include <linux/slab.h> --#include <linux/completion.h> --#include <linux/vmalloc.h> - #include <linux/raspberrypi/vchiq.h> --#include <media/videobuf2-vmalloc.h> -+#include <linux/vmalloc.h> -+#include <media/videobuf2-v4l2.h> +@@ -27,9 +27,22 @@ + #include "../include/linux/raspberrypi/vchiq.h" #include "mmal-common.h" +#include "mmal-parameters.h" #include "mmal-vchiq.h" #include "mmal-msg.h" -+#include "vc-sm-cma/vc_sm_knl.h" ++#include "../vc-sm-cma/vc_sm_knl.h" + +#define pr_dbg_lvl(__level, __debug, __fmt, __arg...) \ + do { \ @@ -115027,7 +169889,7 @@ /* * maximum number of components supported. * This matches the maximum permitted by default on the VPU -@@ -143,6 +155,8 @@ struct mmal_msg_context { +@@ -143,6 +156,8 @@ struct mmal_msg_context { /* Presentation and Decode timestamps */ s64 pts; s64 dts; @@ -115036,7 +169898,7 @@ int status; /* context status */ -@@ -233,18 +247,6 @@ release_msg_context(struct mmal_msg_context *msg_context) +@@ -230,18 +245,6 @@ release_msg_context(struct mmal_msg_context *msg_context) kfree(msg_context); } @@ -115055,7 +169917,7 @@ /* workqueue scheduled callback * * we do this because it is important we do not call any other vchiq -@@ -266,13 +268,18 @@ static void buffer_work_cb(struct work_struct *work) +@@ -263,13 +266,18 @@ static void buffer_work_cb(struct work_struct *work) buffer->mmal_flags = msg_context->u.bulk.mmal_flags; buffer->dts = msg_context->u.bulk.dts; buffer->pts = msg_context->u.bulk.pts; @@ -115075,7 +169937,7 @@ } /* workqueue scheduled callback to handle receiving buffers -@@ -350,6 +357,7 @@ static int bulk_receive(struct vchiq_mmal_instance *instance, +@@ -347,6 +355,7 @@ static int bulk_receive(struct vchiq_mmal_instance *instance, msg_context->u.bulk.buffer_used = rd_len; msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts; msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts; @@ -115083,7 +169945,7 @@ queue_work(msg_context->instance->bulk_wq, &msg_context->u.bulk.buffer_to_host_work); -@@ -384,7 +392,8 @@ buffer_from_host(struct vchiq_mmal_instance *instance, +@@ -381,7 +390,8 @@ buffer_from_host(struct vchiq_mmal_instance *instance, if (!port->enabled) return -EINVAL; @@ -115093,7 +169955,7 @@ /* get context */ if (!buf->msg_context) { -@@ -423,14 +432,27 @@ buffer_from_host(struct vchiq_mmal_instance *instance, +@@ -420,14 +430,27 @@ buffer_from_host(struct vchiq_mmal_instance *instance, /* buffer header */ m.u.buffer_from_host.buffer_header.cmd = 0; @@ -115126,9 +169988,9 @@ + m.u.buffer_from_host.buffer_header.dts = buf->dts; + } - /* clear buffer type sepecific data */ + /* clear buffer type specific data */ memset(&m.u.buffer_from_host.buffer_header_type_specific, 0, -@@ -452,6 +474,103 @@ buffer_from_host(struct vchiq_mmal_instance *instance, +@@ -449,6 +472,103 @@ buffer_from_host(struct vchiq_mmal_instance *instance, return ret; } @@ -115232,7 +170094,7 @@ /* deals with receipt of buffer to host message */ static void buffer_to_host_cb(struct vchiq_mmal_instance *instance, struct mmal_msg *msg, u32 msg_len) -@@ -459,8 +578,8 @@ static void buffer_to_host_cb(struct vchiq_mmal_instance *instance, +@@ -456,8 +576,8 @@ static void buffer_to_host_cb(struct vchiq_mmal_instance *instance, struct mmal_msg_context *msg_context; u32 handle; @@ -115243,7 +170105,7 @@ if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) { handle = msg->u.buffer_from_host.drvbuf.client_context; -@@ -485,6 +604,22 @@ static void buffer_to_host_cb(struct vchiq_mmal_instance *instance, +@@ -482,6 +602,22 @@ static void buffer_to_host_cb(struct vchiq_mmal_instance *instance, msg_context->u.bulk.status = msg->h.status; @@ -115266,7 +170128,7 @@ } else if (msg->u.buffer_from_host.buffer_header.length == 0) { /* empty buffer */ if (msg->u.buffer_from_host.buffer_header.flags & -@@ -714,42 +849,43 @@ static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance, +@@ -711,39 +847,42 @@ static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance, static void dump_port_info(struct vchiq_mmal_port *port) { @@ -115312,34 +170174,24 @@ if (port->format.type == MMAL_ES_TYPE_VIDEO) { - pr_debug - ("es video format: width:%d height:%d colourspace:0x%x\n", -- port->es.video.width, port->es.video.height, -- port->es.video.color_space); -- ++ pr_dbg_lvl(3, debug, ++ "es video format: width:%d height:%d colourspace:0x%x\n", + port->es.video.width, port->es.video.height, + port->es.video.color_space); + - pr_debug(" : crop xywh %d,%d,%d,%d\n", -- port->es.video.crop.x, -- port->es.video.crop.y, -- port->es.video.crop.width, port->es.video.crop.height); ++ pr_dbg_lvl(3, debug, ++ " : crop xywh %d,%d,%d,%d\n", + port->es.video.crop.x, + port->es.video.crop.y, + port->es.video.crop.width, port->es.video.crop.height); - pr_debug(" : framerate %d/%d aspect %d/%d\n", -- port->es.video.frame_rate.num, -- port->es.video.frame_rate.den, -- port->es.video.par.num, port->es.video.par.den); + pr_dbg_lvl(3, debug, -+ "es video format: width:%d height:%d colourspace:0x%x\n", -+ port->es.video.width, port->es.video.height, -+ port->es.video.color_space); -+ -+ pr_dbg_lvl(3, debug, " : crop xywh %d,%d,%d,%d\n", -+ port->es.video.crop.x, -+ port->es.video.crop.y, -+ port->es.video.crop.width, port->es.video.crop.height); -+ pr_dbg_lvl(3, debug, " : framerate %d/%d aspect %d/%d\n", -+ port->es.video.frame_rate.num, -+ port->es.video.frame_rate.den, -+ port->es.video.par.num, port->es.video.par.den); - } - } - -@@ -780,7 +916,7 @@ static int port_info_set(struct vchiq_mmal_instance *instance, ++ " : framerate %d/%d aspect %d/%d\n", + port->es.video.frame_rate.numerator, + port->es.video.frame_rate.denominator, + port->es.video.par.numerator, port->es.video.par.denominator); +@@ -777,7 +916,7 @@ static int port_info_set(struct vchiq_mmal_instance *instance, struct mmal_msg *rmsg; struct vchiq_header *rmsg_handle; @@ -115348,7 +170200,7 @@ if (!port) return -1; dump_port_info(port); -@@ -823,8 +959,8 @@ static int port_info_set(struct vchiq_mmal_instance *instance, +@@ -820,8 +959,8 @@ static int port_info_set(struct vchiq_mmal_instance *instance, /* return operation status */ ret = -rmsg->u.port_info_get_reply.status; @@ -115358,8 +170210,8 @@ + ret, port->component->handle, port->handle); release_msg: - vchiq_release_message(instance->service_handle, rmsg_handle); -@@ -914,13 +1050,13 @@ static int port_info_get(struct vchiq_mmal_instance *instance, + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); +@@ -911,13 +1050,13 @@ static int port_info_get(struct vchiq_mmal_instance *instance, rmsg->u.port_info_get_reply.extradata, port->format.extradata_size); @@ -115374,9 +170226,9 @@ + pr_dbg_lvl(1, debug, "%s:result:%d component:0x%x port:%d\n", + __func__, ret, port->component->handle, port->handle); - vchiq_release_message(instance->service_handle, rmsg_handle); + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); -@@ -965,9 +1101,9 @@ static int create_component(struct vchiq_mmal_instance *instance, +@@ -962,9 +1101,9 @@ static int create_component(struct vchiq_mmal_instance *instance, component->outputs = rmsg->u.component_create_reply.output_num; component->clocks = rmsg->u.component_create_reply.clock_num; @@ -115388,8 +170240,8 @@ + component->inputs, component->outputs, component->clocks); release_msg: - vchiq_release_message(instance->service_handle, rmsg_handle); -@@ -1136,10 +1272,9 @@ static int port_action_port(struct vchiq_mmal_instance *instance, + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); +@@ -1133,10 +1272,9 @@ static int port_action_port(struct vchiq_mmal_instance *instance, ret = -rmsg->u.port_action_reply.status; @@ -115402,8 +170254,8 @@ + port_action_type_namesaction_type, action_type); release_msg: - vchiq_release_message(instance->service_handle, rmsg_handle); -@@ -1183,11 +1318,11 @@ static int port_action_handle(struct vchiq_mmal_instance *instance, + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); +@@ -1180,11 +1318,11 @@ static int port_action_handle(struct vchiq_mmal_instance *instance, ret = -rmsg->u.port_action_reply.status; @@ -115419,8 +170271,8 @@ + action_type, connect_component_handle, connect_port_handle); release_msg: - vchiq_release_message(instance->service_handle, rmsg_handle); -@@ -1226,9 +1361,9 @@ static int port_parameter_set(struct vchiq_mmal_instance *instance, + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); +@@ -1223,9 +1361,9 @@ static int port_parameter_set(struct vchiq_mmal_instance *instance, ret = -rmsg->u.port_parameter_set_reply.status; @@ -115432,8 +170284,8 @@ + parameter_id); release_msg: - vchiq_release_message(instance->service_handle, rmsg_handle); -@@ -1286,8 +1421,9 @@ static int port_parameter_get(struct vchiq_mmal_instance *instance, + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); +@@ -1283,8 +1421,9 @@ static int port_parameter_get(struct vchiq_mmal_instance *instance, /* Always report the size of the returned parameter to the caller */ *value_size = rmsg->u.port_parameter_get_reply.size; @@ -115444,8 +170296,8 @@ + parameter_id); release_msg: - vchiq_release_message(instance->service_handle, rmsg_handle); -@@ -1332,6 +1468,7 @@ static int port_disable(struct vchiq_mmal_instance *instance, + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); +@@ -1329,6 +1468,7 @@ static int port_disable(struct vchiq_mmal_instance *instance, mmalbuf->mmal_flags = 0; mmalbuf->dts = MMAL_TIME_UNKNOWN; mmalbuf->pts = MMAL_TIME_UNKNOWN; @@ -115453,16 +170305,16 @@ port->buffer_cb(instance, port, 0, mmalbuf); } -@@ -1363,6 +1500,8 @@ static int port_enable(struct vchiq_mmal_instance *instance, +@@ -1360,6 +1500,8 @@ static int port_enable(struct vchiq_mmal_instance *instance, - port->enabled = 1; + port->enabled = true; + atomic_set(&port->buffers_with_vpu, 0); + if (port->buffer_cb) { /* send buffer headers to videocore */ hdr_count = 1; -@@ -1428,6 +1567,9 @@ int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance, +@@ -1425,6 +1567,9 @@ int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance, mutex_unlock(&instance->vchiq_mutex); @@ -115472,7 +170324,7 @@ return ret; } EXPORT_SYMBOL_GPL(vchiq_mmal_port_parameter_set); -@@ -1540,7 +1682,7 @@ int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance, +@@ -1537,7 +1682,7 @@ int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance, if (!dst) { /* do not make new connection */ ret = 0; @@ -115481,7 +170333,7 @@ goto release_unlock; } -@@ -1558,14 +1700,14 @@ int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance, +@@ -1555,14 +1700,14 @@ int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance, /* set new format */ ret = port_info_set(instance, dst); if (ret) { @@ -115498,7 +170350,7 @@ goto release_unlock; } -@@ -1574,9 +1716,9 @@ int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance, +@@ -1571,9 +1716,9 @@ int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance, MMAL_MSG_PORT_ACTION_TYPE_CONNECT, dst->component->handle, dst->handle); if (ret < 0) { @@ -115511,7 +170363,7 @@ goto release_unlock; } src->connected = dst; -@@ -1596,6 +1738,32 @@ int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance, +@@ -1593,6 +1738,32 @@ int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance, unsigned long flags = 0; int ret; @@ -115544,7 +170396,7 @@ ret = buffer_from_host(instance, port, buffer); if (ret == -EINVAL) { /* Port is disabled. Queue for when it is enabled. */ -@@ -1629,10 +1797,74 @@ int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf) +@@ -1626,10 +1797,74 @@ int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf) release_msg_context(msg_context); buf->msg_context = NULL; @@ -115619,7 +170471,7 @@ /* Initialise a mmal component and its ports * */ -@@ -1682,6 +1914,7 @@ int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance, +@@ -1679,6 +1914,7 @@ int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance, ret = port_info_get(instance, &component->control); if (ret < 0) goto release_component; @@ -115627,7 +170479,7 @@ for (idx = 0; idx < component->inputs; idx++) { component->inputidx.type = MMAL_PORT_TYPE_INPUT; -@@ -1692,6 +1925,7 @@ int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance, +@@ -1689,6 +1925,7 @@ int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance, ret = port_info_get(instance, &component->inputidx); if (ret < 0) goto release_component; @@ -115635,7 +170487,7 @@ } for (idx = 0; idx < component->outputs; idx++) { -@@ -1703,6 +1937,7 @@ int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance, +@@ -1700,6 +1937,7 @@ int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance, ret = port_info_get(instance, &component->outputidx); if (ret < 0) goto release_component; @@ -115643,7 +170495,7 @@ } for (idx = 0; idx < component->clocks; idx++) { -@@ -1714,6 +1949,7 @@ int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance, +@@ -1711,6 +1949,7 @@ int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance, ret = port_info_get(instance, &component->clockidx); if (ret < 0) goto release_component; @@ -115651,24 +170503,24 @@ } *component_out = component; -@@ -1724,6 +1960,7 @@ int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance, +@@ -1721,6 +1960,7 @@ int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance, release_component: destroy_component(instance, component); + release_all_event_contexts(component); unlock: if (component) - component->in_use = 0; -@@ -1751,6 +1988,8 @@ int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance, + component->in_use = false; +@@ -1748,6 +1988,8 @@ int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance, - component->in_use = 0; + component->in_use = false; + release_all_event_contexts(component); + mutex_unlock(&instance->vchiq_mutex); return ret; -@@ -1775,7 +2014,7 @@ int vchiq_mmal_component_enable(struct vchiq_mmal_instance *instance, +@@ -1772,7 +2014,7 @@ int vchiq_mmal_component_enable(struct vchiq_mmal_instance *instance, ret = enable_component(instance, component); if (ret == 0) @@ -115678,13 +170530,13 @@ mutex_unlock(&instance->vchiq_mutex); diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h -index 1dc81ecf9268..247521fbcc1d 100644 +index 09f030919d4e..628f76038522 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h @@ -49,6 +49,7 @@ typedef void (*vchiq_mmal_buffer_cb)( struct vchiq_mmal_port { - u32 enabled:1; + bool enabled; + u32 zero_copy:1; u32 handle; u32 type; /* port type, cached to use on port info set */ @@ -115701,73 +170553,44 @@ struct vchiq_mmal_component { diff --git a/drivers/thermal/broadcom/bcm2711_thermal.c b/drivers/thermal/broadcom/bcm2711_thermal.c -index 67c2a737bc9d..73cf85fc24b7 100644 +index 03ac2d02e9d4..de581c31a8f7 100644 --- a/drivers/thermal/broadcom/bcm2711_thermal.c +++ b/drivers/thermal/broadcom/bcm2711_thermal.c -@@ -52,7 +52,7 @@ static int bcm2711_get_temp(void *data, int *temp) - /* Convert a HW code to a temperature reading (millidegree celsius) */ - t = slope * val + offset; - -- *temp = t < 0 ? 0 : t; -+ *temp = t; +@@ -92,7 +92,7 @@ static int bcm2711_thermal_probe(struct platform_device *pdev) + &bcm2711_thermal_of_ops); + if (IS_ERR(thermal)) { + ret = PTR_ERR(thermal); +- dev_err(dev, "could not register sensor: %d\n", ret); ++ dev_err_probe(dev, ret, "could not register sensor: %d\n", ret); + return ret; + } - return 0; - } diff --git a/drivers/thermal/gov_step_wise.c b/drivers/thermal/gov_step_wise.c -index 2ae7198d3067..5c8602933201 100644 +index 849dc1ec8d27..394c6de3250b 100644 --- a/drivers/thermal/gov_step_wise.c +++ b/drivers/thermal/gov_step_wise.c -@@ -24,7 +24,7 @@ - * for this trip point - * d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit - * for this trip point -- * If the temperature is lower than a trip point, -+ * If the temperature is lower than a hysteresis temperature, - * a. if the trend is THERMAL_TREND_RAISING, do nothing - * b. if the trend is THERMAL_TREND_DROPPING, use lower cooling - * state for this trip point, if the cooling state already -@@ -115,7 +115,7 @@ static void update_passive_instance(struct thermal_zone_device *tz, - - static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) - { -- int trip_temp; -+ int trip_temp, hyst_temp; - enum thermal_trip_type trip_type; - enum thermal_trend trend; +@@ -86,22 +86,33 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip_id struct thermal_instance *instance; -@@ -123,22 +123,23 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) + bool throttle = false; int old_target; ++ int hyst_temp; - if (trip == THERMAL_TRIPS_NONE) { -- trip_temp = tz->forced_passive; -+ hyst_temp = trip_temp = tz->forced_passive; - trip_type = THERMAL_TRIPS_NONE; - } else { - tz->ops->get_trip_temp(tz, trip, &trip_temp); -+ hyst_temp = trip_temp; -+ if (tz->ops->get_trip_hyst) { -+ tz->ops->get_trip_hyst(tz, trip, &hyst_temp); -+ hyst_temp = trip_temp - hyst_temp; -+ } - tz->ops->get_trip_type(tz, trip, &trip_type); - } - - trend = get_tz_trend(tz, trip); + trend = get_tz_trend(tz, trip_id); -- if (tz->temperature >= trip_temp) { +- if (tz->temperature >= trip->temperature) { - throttle = true; -- trace_thermal_zone_trip(tz, trip, trip_type); +- trace_thermal_zone_trip(tz, trip_id, trip->type); - } -- ++ hyst_temp = trip->temperature - trip->hysteresis; + - dev_dbg(&tz->device, "Trip%dtype=%d,temp=%d:trend=%d,throttle=%d\n", -- trip, trip_type, trip_temp, trend, throttle); +- trip_id, trip->type, trip->temperature, trend, throttle); + dev_dbg(&tz->device, + "Trip%dtype=%d,temp=%d,hyst=%d:trend=%d,throttle=%d\n", -+ trip, trip_type, trip_temp, hyst_temp, trend, throttle); ++ trip_id, trip->type, trip->temperature, hyst_temp, trend, throttle); - mutex_lock(&tz->lock); - -@@ -147,6 +148,18 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) + list_for_each_entry(instance, &tz->thermal_instances, tz_node) { + if (instance->trip != trip) continue; old_target = instance->target; @@ -115776,23 +170599,43 @@ + * Lower the mitigation only if the temperature + * goes below the hysteresis temperature. + */ -+ if (tz->temperature >= trip_temp || ++ if (tz->temperature >= trip->temperature || + (tz->temperature >= hyst_temp && -+ old_target == instance->upper)) { ++ old_target == instance->upper)) { + throttle = true; -+ trace_thermal_zone_trip(tz, trip, trip_type); ++ trace_thermal_zone_trip(tz, trip_id, trip->type); + } + instance->target = get_target_state(instance, trend, throttle); dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n", old_target, (int)instance->target); +diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h +index 1aa3e55c8b47..ae5b995d9d9a 100644 +--- a/drivers/tty/serial/8250/8250.h ++++ b/drivers/tty/serial/8250/8250.h +@@ -92,6 +92,7 @@ struct serial8250_config { + #define UART_BUG_NOMSR BIT(2) /* UART has buggy MSR status bits (Au1x00) */ + #define UART_BUG_THRE BIT(3) /* UART has buggy THRE reassertion */ + #define UART_BUG_TXRACE BIT(5) /* UART Tx fails to set remote DR */ ++#define UART_BUG_NOMSI BIT(6) /* UART has no modem status interrupt */ + + + #ifdef CONFIG_SERIAL_8250_SHARE_IRQ diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c -index fd95860cd661..fc36e5963e30 100644 +index 4f4502fb5454..f31e3c9b7d37 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c -@@ -148,6 +148,13 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) +@@ -109,6 +109,7 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) + UPF_SKIP_TEST | UPF_IOREMAP; + up.port.rs485_config = serial8250_em485_config; + up.port.rs485_supported = serial8250_em485_supported; ++ up.bugs |= UART_BUG_NOMSI; + up.rs485_start_tx = bcm2835aux_rs485_start_tx; + up.rs485_stop_tx = bcm2835aux_rs485_stop_tx; + +@@ -182,6 +183,13 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) */ - up.port.uartclk = clk_get_rate(data->clk) * 2; + up.port.uartclk = uartclk * 2; + /* The clock is only queried at probe time, which means we get one shot + * at this. A zero clock is never going to work and is almost certainly @@ -115804,76 +170647,99 @@ /* register the port */ ret = serial8250_register_8250_port(&up); if (ret < 0) { -diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c -index 859d0c30dcc2..f65461d648c7 100644 ---- a/drivers/tty/serial/amba-pl011.c -+++ b/drivers/tty/serial/amba-pl011.c -@@ -266,6 +266,7 @@ struct uart_amba_port { - unsigned int old_cr; /* state during shutdown */ - unsigned int fixed_baud; /* vendor-set fixed baud rate */ - char type12; -+ bool irq_locked; /* in irq, unreleased lock */ - #ifdef CONFIG_DMA_ENGINE - /* DMA stuff */ - bool using_tx_dma; -@@ -812,6 +813,7 @@ __acquires(&uap->port.lock) - if (!uap->using_tx_dma) - return; - -+ uap->irq_locked = 0; - dmaengine_terminate_async(uap->dmatx.chan); - - if (uap->dmatx.queued) { -@@ -938,6 +940,7 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap, - fifotaken = pl011_fifo_to_tty(uap); - } - -+ uap->irq_locked = 0; - spin_unlock(&uap->port.lock); - dev_vdbg(uap->port.dev, - "Took %d chars from DMA buffer and %d chars from the FIFO\n", -@@ -1315,6 +1318,32 @@ static void pl011_start_tx(struct uart_port *port) - pl011_start_tx_pio(uap); +diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c +index 3449f8790e46..e561f21cd6c3 100644 +--- a/drivers/tty/serial/8250/8250_core.c ++++ b/drivers/tty/serial/8250/8250_core.c +@@ -253,6 +253,18 @@ static void serial8250_timeout(struct timer_list *t) + mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port)); } -+static void pl011_throttle(struct uart_port *port) -+{ -+ struct uart_amba_port *uap = -+ container_of(port, struct uart_amba_port, port); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&uap->port.lock, flags); -+ uap->im &= ~(UART011_RTIM | UART011_RXIM); -+ pl011_write(uap->im, uap, REG_IMSC); -+ spin_unlock_irqrestore(&uap->port.lock, flags); -+} -+ -+static void pl011_unthrottle(struct uart_port *port) ++static void serial8250_cts_poll_timeout(struct timer_list *t) +{ -+ struct uart_amba_port *uap = -+ container_of(port, struct uart_amba_port, port); ++ struct uart_8250_port *up = from_timer(up, t, timer); + unsigned long flags; + -+ spin_lock_irqsave(&uap->port.lock, flags); -+ uap->im |= UART011_RTIM; -+ if (!pl011_dma_rx_running(uap)) -+ uap->im |= UART011_RXIM; -+ pl011_write(uap->im, uap, REG_IMSC); -+ spin_unlock_irqrestore(&uap->port.lock, flags); ++ spin_lock_irqsave(&up->port.lock, flags); ++ serial8250_modem_status(up); ++ spin_unlock_irqrestore(&up->port.lock, flags); ++ if (up->port.hw_stopped) ++ mod_timer(&up->timer, jiffies + 1); +} + - static void pl011_stop_rx(struct uart_port *port) - { - struct uart_amba_port *uap = -@@ -1342,6 +1371,7 @@ __acquires(&uap->port.lock) + static void serial8250_backup_timeout(struct timer_list *t) { - pl011_fifo_to_tty(uap); + struct uart_8250_port *up = from_timer(up, t, timer); +@@ -315,6 +327,9 @@ static void univ8250_setup_timer(struct uart_8250_port *up) + uart_poll_timeout(port) + HZ / 5); + } -+ uap->irq_locked = 0; - spin_unlock(&uap->port.lock); - tty_flip_buffer_push(&uap->port.state->port); ++ if (up->bugs & UART_BUG_NOMSI) ++ up->timer.function = serial8250_cts_poll_timeout; ++ /* -@@ -1378,6 +1408,7 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, + * If the "interrupt" for this port doesn't correspond with any + * hardware interrupt, we use a timer-based system. The original +diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c +index 141627370aab..345076d7221b 100644 +--- a/drivers/tty/serial/8250/8250_port.c ++++ b/drivers/tty/serial/8250/8250_port.c +@@ -1535,6 +1535,9 @@ static void serial8250_stop_tx(struct uart_port *port) + serial_icr_write(up, UART_ACR, up->acr); + } + serial8250_rpm_put(up); ++ ++ if (port->hw_stopped && (up->bugs & UART_BUG_NOMSI)) ++ mod_timer(&up->timer, jiffies + 1); + } + + static inline void __start_tx(struct uart_port *port) +@@ -1648,6 +1651,9 @@ static void serial8250_start_tx(struct uart_port *port) + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&port->lock); + ++ if (up->bugs & UART_BUG_NOMSI) ++ del_timer(&up->timer); ++ + if (!port->x_char && uart_circ_empty(&port->state->xmit)) + return; + +@@ -1872,6 +1878,9 @@ unsigned int serial8250_modem_status(struct uart_8250_port *up) + uart_handle_cts_change(port, status & UART_MSR_CTS); + + wake_up_interruptible(&port->state->port.delta_msr_wait); ++ } else if (up->bugs & UART_BUG_NOMSI && port->hw_stopped && ++ status & UART_MSR_CTS) { ++ uart_handle_cts_change(port, status & UART_MSR_CTS); + } + + return status; +diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c +index 362bbcdece0d..a5717655b388 100644 +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -152,6 +152,20 @@ static const struct vendor_data vendor_sbsa = { + .fixed_options = true, + }; + ++static struct vendor_data vendor_arm_axi = { ++ .reg_offset = pl011_std_offsets, ++ .ifls = UART011_IFLS_RX4_8 | UART011_IFLS_TX4_8, ++ .fr_busy = UART01x_FR_BUSY, ++ .fr_dsr = UART01x_FR_DSR, ++ .fr_cts = UART01x_FR_CTS, ++ .fr_ri = UART011_FR_RI, ++ .oversampling = false, ++ .dma_threshold = false, ++ .cts_event_workaround = false, ++ .always_enabled = false, ++ .fixed_options = false, ++}; ++ + #ifdef CONFIG_ACPI_SPCR_TABLE + static const struct vendor_data vendor_qdt_qdf2400_e44 = { + .reg_offset = pl011_std_offsets, +@@ -1456,6 +1470,7 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, return false; /* unable to transmit character */ pl011_write(c, uap, REG_DR); @@ -115881,7 +170747,7 @@ uap->port.icount.tx++; return true; -@@ -1408,6 +1439,10 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) +@@ -1486,6 +1501,10 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) if (likely(from_irq) && count-- == 0) break; @@ -115892,104 +170758,7 @@ if (!pl011_tx_char(uap, xmit->bufxmit->tail, from_irq)) break; -@@ -1535,6 +1570,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id) - int handled = 0; - - spin_lock_irqsave(&uap->port.lock, flags); -+ uap->irq_locked = 1; - status = pl011_read(uap, REG_RIS) & uap->im; - if (status) { - do { -@@ -1554,7 +1590,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id) - UART011_CTSMIS|UART011_RIMIS)) - pl011_modem_status(uap); - if (status & UART011_TXIS) -- pl011_tx_chars(uap, true); -+ pl011_tx_chars(uap, uap->irq_locked); - - if (pass_counter-- == 0) - break; -@@ -1709,6 +1745,23 @@ static void pl011_put_poll_char(struct uart_port *port, - - #endif /* CONFIG_CONSOLE_POLL */ - -+unsigned long pl011_clk_round(unsigned long clk) -+{ -+ unsigned long scaler; -+ -+ /* -+ * If increasing a clock by less than 0.1% changes it -+ * from ..999.. to ..000.., round up. -+ */ -+ scaler = 1; -+ while (scaler * 100000 < clk) -+ scaler *= 10; -+ if ((clk + scaler - 1)/scaler % 1000 == 0) -+ clk = (clk/scaler + 1) * scaler; -+ -+ return clk; -+} -+ - static int pl011_hwinit(struct uart_port *port) - { - struct uart_amba_port *uap = -@@ -1725,7 +1778,7 @@ static int pl011_hwinit(struct uart_port *port) - if (retval) - return retval; - -- uap->port.uartclk = clk_get_rate(uap->clk); -+ uap->port.uartclk = pl011_clk_round(clk_get_rate(uap->clk)); - - /* Clear pending error and receive interrupts */ - pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS | -@@ -2185,6 +2238,8 @@ static const struct uart_ops amba_pl011_pops = { - .stop_tx = pl011_stop_tx, - .start_tx = pl011_start_tx, - .stop_rx = pl011_stop_rx, -+ .throttle = pl011_throttle, -+ .unthrottle = pl011_unthrottle, - .enable_ms = pl011_enable_ms, - .break_ctl = pl011_break_ctl, - .startup = pl011_startup, -@@ -2361,7 +2416,7 @@ static int pl011_console_setup(struct console *co, char *options) - plat->init(); - } - -- uap->port.uartclk = clk_get_rate(uap->clk); -+ uap->port.uartclk = pl011_clk_round(clk_get_rate(uap->clk)); - - if (uap->vendor->fixed_options) { - baud = uap->fixed_baud; -@@ -2578,6 +2633,7 @@ static struct uart_driver amba_reg = { - .cons = AMBA_CONSOLE, - }; - -+#if 0 - static int pl011_probe_dt_alias(int index, struct device *dev) - { - struct device_node *np; -@@ -2609,6 +2665,7 @@ static int pl011_probe_dt_alias(int index, struct device *dev) - - return ret; - } -+#endif - - /* unregisters the driver also if no more ports are left */ - static void pl011_unregister_port(struct uart_amba_port *uap) -@@ -2647,7 +2704,12 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, - if (IS_ERR(base)) - return PTR_ERR(base); - -+ /* Don't use DT serial<n> aliases - it causes the device to -+ be renumbered to ttyAMA1 if it is the second serial port in the -+ system, even though the other one is ttyS0. The 8250 driver -+ doesn't use this logic, so always remains ttyS0. - index = pl011_probe_dt_alias(index, dev); -+ */ - - uap->old_cr = 0; - uap->port.dev = dev; -@@ -2709,6 +2771,11 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) +@@ -2807,6 +2826,11 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) if (IS_ERR(uap->clk)) return PTR_ERR(uap->clk); @@ -116001,63 +170770,129 @@ uap->reg_offset = vendor->reg_offset; uap->vendor = vendor; uap->fifosize = vendor->get_fifosize(dev); -diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c -index 9adb8362578c..8e3b83fac33c 100644 ---- a/drivers/tty/serial/sc16is7xx.c -+++ b/drivers/tty/serial/sc16is7xx.c -@@ -523,8 +523,9 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) +@@ -2969,6 +2993,88 @@ static struct platform_driver arm_sbsa_uart_platform_driver = { + }, + }; - /* Enable enhanced features */ - regcache_cache_bypass(s->regmap, true); -- sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, -- SC16IS7XX_EFR_ENABLE_BIT); -+ sc16is7xx_port_update(port, SC16IS7XX_EFR_REG, -+ SC16IS7XX_EFR_ENABLE_BIT, -+ SC16IS7XX_EFR_ENABLE_BIT); - regcache_cache_bypass(s->regmap, false); - - /* Put LCR back to the normal mode */ -@@ -696,6 +697,8 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) - rxlen = sc16is7xx_port_read(port, SC16IS7XX_RXLVL_REG); - if (rxlen) - sc16is7xx_handle_rx(port, rxlen, iir); -+ else -+ return false; - break; - case SC16IS7XX_IIR_THRI_SRC: - sc16is7xx_handle_tx(port); -@@ -837,7 +840,7 @@ static unsigned int sc16is7xx_get_mctrl(struct uart_port *port) - /* DCD and DSR are not wired and CTS/RTS is handled automatically - * so just indicate DSR and CAR asserted - */ -- return TIOCM_DSR | TIOCM_CAR; -+ return TIOCM_DSR | TIOCM_CAR | TIOCM_RI | TIOCM_CTS; - } ++static int pl011_axi_probe(struct platform_device *pdev) ++{ ++ struct uart_amba_port *uap; ++ struct vendor_data *vendor = &vendor_arm_axi; ++ struct resource *r; ++ unsigned int periphid; ++ int portnr, ret, irq; ++ ++ portnr = pl011_find_free_port(); ++ if (portnr < 0) ++ return portnr; ++ ++ uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port), ++ GFP_KERNEL); ++ if (!uap) ++ return -ENOMEM; ++ ++ uap->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(uap->clk)) ++ return PTR_ERR(uap->clk); ++ ++ if (of_property_read_bool(pdev->dev.of_node, "cts-event-workaround")) { ++ vendor->cts_event_workaround = true; ++ dev_info(&pdev->dev, "cts_event_workaround enabled\n"); ++ } ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return irq; ++ ++ periphid = 0x00241011; /* A safe default */ ++ of_property_read_u32(pdev->dev.of_node, "arm,primecell-periphid", ++ &periphid); ++ ++ uap->reg_offset = vendor->reg_offset; ++ uap->vendor = vendor; ++ uap->fifosize = (AMBA_REV_BITS(periphid) < 3) ? 16 : 32; ++ uap->port.iotype = vendor->access_32b ? UPIO_MEM32 : UPIO_MEM; ++ uap->port.irq = irq; ++ uap->port.ops = &amba_pl011_pops; ++ uap->port.rs485_config = pl011_rs485_config; ++ uap->port.rs485_supported = pl011_rs485_supported; ++ ++ snprintf(uap->type, sizeof(uap->type), "PL011 AXI"); ++ ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ ++ ret = pl011_setup_port(&pdev->dev, uap, r, portnr); ++ if (ret) ++ return ret; ++ ++ platform_set_drvdata(pdev, uap); ++ ++ return pl011_register_port(uap); ++} ++ ++static int pl011_axi_remove(struct platform_device *pdev) ++{ ++ struct uart_amba_port *uap = platform_get_drvdata(pdev); ++ ++ uart_remove_one_port(&amba_reg, &uap->port); ++ pl011_unregister_port(uap); ++ return 0; ++} ++ ++static const struct of_device_id pl011_axi_of_match = { ++ { .compatible = "arm,pl011-axi" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, pl011_axi_of_match); ++ ++static struct platform_driver pl011_axi_platform_driver = { ++ .probe = pl011_axi_probe, ++ .remove = pl011_axi_remove, ++ .driver = { ++ .name = "pl011-axi", ++ .pm = &pl011_dev_pm_ops, ++ .of_match_table = of_match_ptr(pl011_axi_of_match), ++ .suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011), ++ }, ++}; ++ + static const struct amba_id pl011_ids = { + { + .id = 0x00041011, +@@ -3002,6 +3108,8 @@ static int __init pl011_init(void) - static void sc16is7xx_set_mctrl(struct uart_port *port, unsigned int mctrl) -@@ -924,14 +927,19 @@ static void sc16is7xx_set_termios(struct uart_port *port, - regcache_cache_bypass(s->regmap, true); - sc16is7xx_port_write(port, SC16IS7XX_XON1_REG, termios->c_ccVSTART); - sc16is7xx_port_write(port, SC16IS7XX_XOFF1_REG, termios->c_ccVSTOP); -- if (termios->c_cflag & CRTSCTS) -+ if (termios->c_cflag & CRTSCTS) { - flow |= SC16IS7XX_EFR_AUTOCTS_BIT | - SC16IS7XX_EFR_AUTORTS_BIT; -+ port->status |= UPSTAT_AUTOCTS; -+ }; - if (termios->c_iflag & IXON) - flow |= SC16IS7XX_EFR_SWFLOW3_BIT; - if (termios->c_iflag & IXOFF) - flow |= SC16IS7XX_EFR_SWFLOW1_BIT; + if (platform_driver_register(&arm_sbsa_uart_platform_driver)) + pr_warn("could not register SBSA UART platform driver\n"); ++ if (platform_driver_register(&pl011_axi_platform_driver)) ++ pr_warn("could not register PL011 AXI platform driver\n"); + return amba_driver_register(&pl011_driver); + } -+ /* Always set enable enhanced */ -+ flow |= SC16IS7XX_EFR_ENABLE_BIT; -+ - sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, flow); - regcache_cache_bypass(s->regmap, false); +diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c +index f75b8bceb8ca..eea6622122af 100644 +--- a/drivers/tty/serial/sc16is7xx.c ++++ b/drivers/tty/serial/sc16is7xx.c +@@ -760,6 +760,8 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) + if (rxlen) + sc16is7xx_handle_rx(port, rxlen, iir); ++ else ++ rc = false; + break; + /* CTSRTS interrupt comes only when CTS goes inactive */ + case SC16IS7XX_IIR_CTSRTS_SRC: +@@ -1191,6 +1193,9 @@ static int sc16is7xx_startup(struct uart_port *port) + SC16IS7XX_IER_MSI_BIT; + sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val); + ++ /* Initialize the Modem Control signals to current status */ ++ one->old_mctrl = sc16is7xx_get_hwmctrl(port); ++ + /* Enable modem status polling */ + uart_port_lock_irqsave(port, &flags); + sc16is7xx_enable_ms(port); diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile -index 1c1c1d659394..68317e5634e8 100644 +index 3a9a0dd4be70..64d602c5b238 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_USB_COMMON) += common/ @@ -116069,7 +170904,7 @@ obj-$(CONFIG_USB_DWC2) += dwc2/ obj-$(CONFIG_USB_ISP1760) += isp1760/ diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c -index 26f9fb9f67ca..fe8c7a85e141 100644 +index 740342a2812a..30f8ce75fe1d 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -190,6 +190,7 @@ int usb_choose_configuration(struct usb_device *udev) @@ -116081,10 +170916,10 @@ return i; } diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c -index ddd1d3eef912..92357f32d2c1 100644 +index 12b6dfeaf658..0de6ac768188 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c -@@ -1966,6 +1966,16 @@ int usb_hcd_alloc_bandwidth(struct usb_device *udev, +@@ -1952,6 +1952,16 @@ int usb_hcd_alloc_bandwidth(struct usb_device *udev, return ret; } @@ -116102,10 +170937,10 @@ * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must * have been called previously. Use for set_configuration, set_interface, diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c -index 18ee3914b468..6ab15e05a6f9 100644 +index 71635dfa741d..2dbfbd076493 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c -@@ -5506,7 +5506,7 @@ static void port_event(struct usb_hub *hub, int port1) +@@ -5689,7 +5689,7 @@ static void port_event(struct usb_hub *hub, int port1) port_dev->over_current_count++; port_over_current_notify(port_dev); @@ -116115,7 +170950,7 @@ usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_OVER_CURRENT); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c -index dba2baca486e..62611141f014 100644 +index 077dfe48d01c..89c7339386a6 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1265,6 +1265,21 @@ static void remove_intf_ep_devs(struct usb_interface *intf) @@ -116140,7 +170975,7 @@ /** * usb_disable_endpoint -- Disable an endpoint by address * @dev: the device whose endpoint is being disabled -@@ -2135,6 +2150,85 @@ int usb_set_configuration(struct usb_device *dev, int configuration) +@@ -2177,6 +2192,85 @@ int usb_set_configuration(struct usb_device *dev, int configuration) if (cp->string == NULL && !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) cp->string = usb_cache_string(dev, cp->desc.iConfiguration); @@ -116383,6 +171218,230 @@ return 0; } +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index b73b79fea281..ab3395199030 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -1162,6 +1162,24 @@ static void dwc3_config_threshold(struct dwc3 *dwc) + } + } + ++static void dwc3_set_axi_pipe_limit(struct dwc3 *dwc) ++{ ++ struct device *dev = dwc->dev; ++ u32 cfg; ++ ++ if (!dwc->axi_pipe_limit) ++ return; ++ if (dwc->axi_pipe_limit > 16) { ++ dev_err(dev, "Invalid axi_pipe_limit property\n"); ++ return; ++ } ++ cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG1); ++ cfg &= ~DWC3_GSBUSCFG1_PIPETRANSLIMIT(15); ++ cfg |= DWC3_GSBUSCFG1_PIPETRANSLIMIT(dwc->axi_pipe_limit - 1); ++ ++ dwc3_writel(dwc->regs, DWC3_GSBUSCFG1, cfg); ++} ++ + /** + * dwc3_core_init - Low-level initialization of DWC3 Core + * @dwc: Pointer to our controller context structure +@@ -1242,6 +1260,8 @@ static int dwc3_core_init(struct dwc3 *dwc) + + dwc3_set_incr_burst_type(dwc); + ++ dwc3_set_axi_pipe_limit(dwc); ++ + ret = dwc3_phy_power_on(dwc); + if (ret) + goto err_exit_phy; +@@ -1306,6 +1326,9 @@ static int dwc3_core_init(struct dwc3 *dwc) + if (dwc->parkmode_disable_hs_quirk) + reg |= DWC3_GUCTL1_PARKMODE_DISABLE_HS; + ++ if (dwc->parkmode_disable_fsls_quirk) ++ reg |= DWC3_GUCTL1_PARKMODE_DISABLE_FSLS; ++ + if (DWC3_VER_IS_WITHIN(DWC3, 290A, ANY) && + (dwc->maximum_speed == USB_SPEED_HIGH || + dwc->maximum_speed == USB_SPEED_FULL)) +@@ -1316,6 +1339,24 @@ static int dwc3_core_init(struct dwc3 *dwc) + + dwc3_config_threshold(dwc); + ++ if (DWC3_IP_IS(DWC3) && dwc->dr_mode == USB_DR_MODE_HOST) { ++ u8 tx_thr_num = dwc->tx_thr_num_pkt_prd; ++ u8 tx_maxburst = dwc->tx_max_burst_prd; ++ ++ if (tx_thr_num && tx_maxburst) { ++ reg = dwc3_readl(dwc->regs, DWC3_GTXTHRCFG); ++ reg |= DWC3_GTXTHRCFG_PKTCNTSEL; ++ ++ reg &= ~DWC3_GTXTHRCFG_TXPKTCNT(~0); ++ reg |= DWC3_GTXTHRCFG_TXPKTCNT(tx_thr_num); ++ ++ reg &= ~DWC3_GTXTHRCFG_MAXTXBURSTSIZE(~0); ++ reg |= DWC3_GTXTHRCFG_MAXTXBURSTSIZE(tx_maxburst); ++ ++ dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, reg); ++ } ++ } ++ + return 0; + + err_power_off_phy: +@@ -1459,6 +1500,7 @@ static void dwc3_get_properties(struct dwc3 *dwc) + u8 tx_thr_num_pkt_prd = 0; + u8 tx_max_burst_prd = 0; + u8 tx_fifo_resize_max_num; ++ u8 axi_pipe_limit; + const char *usb_psy_name; + int ret; + +@@ -1481,6 +1523,9 @@ static void dwc3_get_properties(struct dwc3 *dwc) + */ + tx_fifo_resize_max_num = 6; + ++ /* Default to 0 (don't override hardware defaults) */ ++ axi_pipe_limit = 0; ++ + dwc->maximum_speed = usb_get_maximum_speed(dev); + dwc->max_ssp_rate = usb_get_maximum_ssp_rate(dev); + dwc->dr_mode = usb_get_dr_mode(dev); +@@ -1580,6 +1625,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) + "snps,parkmode-disable-ss-quirk"); + dwc->parkmode_disable_hs_quirk = device_property_read_bool(dev, + "snps,parkmode-disable-hs-quirk"); ++ dwc->parkmode_disable_fsls_quirk = device_property_read_bool(dev, ++ "snps,parkmode-disable-fsls-quirk"); + dwc->gfladj_refclk_lpm_sel = device_property_read_bool(dev, + "snps,gfladj-refclk-lpm-sel-quirk"); + +@@ -1600,6 +1647,9 @@ static void dwc3_get_properties(struct dwc3 *dwc) + dwc->dis_split_quirk = device_property_read_bool(dev, + "snps,dis-split-quirk"); + ++ device_property_read_u8(dev, "snps,axi-pipe-limit", ++ &axi_pipe_limit); ++ + dwc->lpm_nyet_threshold = lpm_nyet_threshold; + dwc->tx_de_emphasis = tx_de_emphasis; + +@@ -1617,6 +1667,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) + dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd; + dwc->tx_max_burst_prd = tx_max_burst_prd; + ++ dwc->axi_pipe_limit = axi_pipe_limit; ++ + dwc->imod_interval = 0; + + dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num; +@@ -1892,6 +1944,12 @@ static int dwc3_probe(struct platform_device *pdev) + + dwc3_get_properties(dwc); + ++ if (!dwc->sysdev_is_parent) { ++ ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64)); ++ if (ret) ++ return ret; ++ } ++ + dwc->reset = devm_reset_control_array_get_optional_shared(dev); + if (IS_ERR(dwc->reset)) { + ret = PTR_ERR(dwc->reset); +diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h +index 6782ec8bfd64..2dd962bada45 100644 +--- a/drivers/usb/dwc3/core.h ++++ b/drivers/usb/dwc3/core.h +@@ -185,6 +185,9 @@ + #define DWC3_GSBUSCFG0_INCRBRSTENA (1 << 0) /* undefined length enable */ + #define DWC3_GSBUSCFG0_INCRBRST_MASK 0xff + ++/* Global SoC Bus Configuration Register 1 */ ++#define DWC3_GSBUSCFG1_PIPETRANSLIMIT(n) (((n) & 0xf) << 8) ++ + /* Global Debug LSP MUX Select */ + #define DWC3_GDBGLSPMUX_ENDBC BIT(15) /* Host only */ + #define DWC3_GDBGLSPMUX_HOSTSELECT(n) ((n) & 0x3fff) +@@ -268,6 +271,7 @@ + #define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24) + #define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17) + #define DWC3_GUCTL1_PARKMODE_DISABLE_HS BIT(16) ++#define DWC3_GUCTL1_PARKMODE_DISABLE_FSLS BIT(15) + #define DWC3_GUCTL1_RESUME_OPMODE_HS_HOST BIT(10) + + /* Global Status Register */ +@@ -1060,6 +1064,7 @@ struct dwc3_scratchpad_array { + * @tx_max_burst_prd: max periodic ESS transmit burst size + * @tx_fifo_resize_max_num: max number of fifos allocated during txfifo resize + * @clear_stall_protocol: endpoint number that requires a delayed status phase ++ * @axi_max_pipe: set to override the maximum number of pipelined AXI transfers + * @hsphy_interface: "utmi" or "ulpi" + * @connected: true when we're connected to a host, false otherwise + * @softconnect: true when gadget connect is called, false when disconnect runs +@@ -1111,10 +1116,12 @@ struct dwc3_scratchpad_array { + * generation after resume from suspend. + * @ulpi_ext_vbus_drv: Set to confiure the upli chip to drives CPEN pin + * VBUS with an external supply. +- * @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed +- * instances in park mode. +- * @parkmode_disable_hs_quirk: set if we need to disable all HishSpeed +- * instances in park mode. ++ * @parkmode_disable_ss_quirk: If set, disable park mode feature for all ++ * Superspeed instances. ++ * @parkmode_disable_hs_quirk: If set, disable park mode feature for all ++ * Highspeed instances. ++ * @parkmode_disable_fsls_quirk: If set, disable park mode feature for all ++ * Full/Lowspeed instances. + * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk + * @tx_de_emphasis: Tx de-emphasis value + * 0 - -6dB de-emphasis +@@ -1292,6 +1299,7 @@ struct dwc3 { + u8 tx_max_burst_prd; + u8 tx_fifo_resize_max_num; + u8 clear_stall_protocol; ++ u8 axi_pipe_limit; + + const char *hsphy_interface; + +@@ -1335,6 +1343,7 @@ struct dwc3 { + unsigned ulpi_ext_vbus_drv:1; + unsigned parkmode_disable_ss_quirk:1; + unsigned parkmode_disable_hs_quirk:1; ++ unsigned parkmode_disable_fsls_quirk:1; + unsigned gfladj_refclk_lpm_sel:1; + + unsigned tx_de_emphasis_quirk:1; +diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c +index 43230915323c..7b33f226531d 100644 +--- a/drivers/usb/dwc3/host.c ++++ b/drivers/usb/dwc3/host.c +@@ -61,16 +61,23 @@ static int dwc3_host_get_irq(struct dwc3 *dwc) + + int dwc3_host_init(struct dwc3 *dwc) + { ++ struct platform_device *pdev = to_platform_device(dwc->dev); + struct property_entry props5; + struct platform_device *xhci; + int ret, irq; + int prop_idx = 0; ++ int id; + + irq = dwc3_host_get_irq(dwc); + if (irq < 0) + return irq; + +- xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); ++ id = of_alias_get_id(pdev->dev.of_node, "usb"); ++ if (id >= 0) ++ xhci = platform_device_alloc("xhci-hcd", id); ++ else ++ xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); ++ + if (!xhci) { + dev_err(dwc->dev, "couldn't allocate xHCI device\n"); + return -ENOMEM; diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c new file mode 100644 index 000000000000..a896d73f7a93 @@ -120066,10 +175125,10 @@ +} +module_exit(fsg_cleanup); diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig -index ab12c4bf0ef1..8f2d915ecae5 100644 +index 4448d0ab06f0..4228565fed85 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig -@@ -741,6 +741,16 @@ config USB_RENESAS_USBHS_HCD +@@ -678,6 +678,16 @@ config USB_RENESAS_USBHS_HCD To compile this driver as a module, choose M here: the module will be called renesas-usbhs. @@ -120083,21 +175142,21 @@ + Enable this option to support this IP in host controller mode. + If unsure, say N. + - config USB_IMX21_HCD - tristate "i.MX21 HCD support" - depends on ARM && ARCH_MXC + config USB_HCD_BCMA + tristate "BCMA usb host driver" + depends on BCMA diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile -index bc731332fed9..5a808bde2a14 100644 +index be4e5245c52f..929af76224d5 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile -@@ -81,6 +81,7 @@ obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o +@@ -77,6 +77,7 @@ obj-$(CONFIG_USB_XHCI_TEGRA) += xhci-tegra.o + obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o - obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o +obj-$(CONFIG_USB_DWCOTG) += dwc_otg/ dwc_common_port/ - obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o + obj-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o diff --git a/drivers/usb/host/dwc_common_port/Makefile b/drivers/usb/host/dwc_common_port/Makefile new file mode 100644 index 000000000000..f10d466d1aea @@ -128302,10 +183361,10 @@ +#endif /* __DWC_NOTIFIER_H__ */ diff --git a/drivers/usb/host/dwc_common_port/dwc_os.h b/drivers/usb/host/dwc_common_port/dwc_os.h new file mode 100644 -index 000000000000..9a86d299403b +index 000000000000..7a4052964e95 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/dwc_os.h -@@ -0,0 +1,1276 @@ +@@ -0,0 +1,1275 @@ +/* ========================================================================= + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_os.h $ + * $Revision: #14 $ @@ -128369,7 +183428,6 @@ +# endif +# include <linux/spinlock.h> +# include <linux/errno.h> -+# include <stdarg.h> +#endif + +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD) @@ -129865,10 +184923,10 @@ +#endif /* _USB_H_ */ diff --git a/drivers/usb/host/dwc_otg/Makefile b/drivers/usb/host/dwc_otg/Makefile new file mode 100644 -index 000000000000..7ea65a6bcdb7 +index 000000000000..8cbe3e684f26 --- /dev/null +++ b/drivers/usb/host/dwc_otg/Makefile -@@ -0,0 +1,85 @@ +@@ -0,0 +1,86 @@ +# +# Makefile for DWC_otg Highspeed USB controller driver +# @@ -129899,6 +184957,7 @@ +ccflags-y += $(CFI) +ccflags-y += $(BUS_INTERFACE) +#ccflags-y += -DDWC_DEV_SRPCAP ++CFLAGS_dwc_otg_fiq_fsm.o += -fno-stack-protector + +obj-$(CONFIG_USB_DWCOTG) += dwc_otg.o + @@ -149314,7 +204373,7 @@ +#endif diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c new file mode 100644 -index 000000000000..f644acbce748 +index 000000000000..67e277804b2e --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c @@ -0,0 +1,1433 @@ @@ -149462,7 +204521,7 @@ + * fiq_fsm_restart_channel() - Poke channel enable bit for a split transaction + * @channel: channel to re-enable + */ -+static void fiq_fsm_restart_channel(struct fiq_state *st, int n, int force) ++static void notrace fiq_fsm_restart_channel(struct fiq_state *st, int n, int force) +{ + hcchar_data_t hcchar = { .d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR) }; + @@ -151244,10 +206303,10 @@ +END(_dwc_otg_fiq_stub) diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c new file mode 100644 -index 000000000000..e42d8ca89c01 +index 000000000000..6964784689fc --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -0,0 +1,4363 @@ +@@ -0,0 +1,4366 @@ + +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.c $ @@ -152589,8 +207648,10 @@ + * buffer. + */ + wLength = ((uint16_t *)urb->setup_packet)3; ++ #if 0 + if (hc->ep_is_in && wLength < 4) + ptr = hc->xfer_buff; ++ #endif + + hc->data_pid_start = qtd->data_toggle; + break; @@ -153299,6 +208360,7 @@ + } else { + st->fsm = FIQ_PER_SSPLIT_QUEUED; + } ++ break; + default: + break; + } @@ -158057,7 +213119,7 @@ +#endif /* DWC_DEVICE_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c new file mode 100644 -index 000000000000..9d49b2b33227 +index 000000000000..53b62bd499a8 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c @@ -0,0 +1,2757 @@ @@ -158465,7 +213527,7 @@ + hc->xfer_count += grxsts.b.bcnt; + hc->xfer_buff += grxsts.b.bcnt; + } -+ ++ break; + case DWC_GRXSTS_PKTSTS_IN_XFER_COMP: + case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR: + case DWC_GRXSTS_PKTSTS_CH_HALTED: @@ -160820,10 +215882,10 @@ +#endif /* DWC_DEVICE_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c new file mode 100644 -index 000000000000..2ee27450c6f6 +index 000000000000..ca646860a092 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -@@ -0,0 +1,1087 @@ +@@ -0,0 +1,1084 @@ + +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $ @@ -161600,7 +216662,7 @@ + speed;} + )) ; + DWC_PRINTF(" Max packet size: %d\n", -+ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); ++ usb_maxpacket(urb->dev, urb->pipe); + DWC_PRINTF(" Data buffer length: %d\n", urb->transfer_buffer_length); + DWC_PRINTF(" Transfer buffer: %p, Transfer DMA: %p\n", + urb->transfer_buffer, (void *)urb->transfer_dma); @@ -161633,7 +216695,6 @@ + struct usb_host_endpoint *ep = urb->ep; +#endif + dwc_irqflags_t irqflags; -+ void **ref_ep_hcpriv = &ep->hcpriv; + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); + dwc_otg_hcd_urb_t *dwc_otg_urb; + int i; @@ -161650,7 +216711,7 @@ + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) + || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) { + if (!dwc_otg_hcd_is_bandwidth_allocated -+ (dwc_otg_hcd, ref_ep_hcpriv)) { ++ (dwc_otg_hcd, ep->hcpriv)) { + alloc_bandwidth = 1; + } + } @@ -161686,8 +216747,7 @@ + dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe), + usb_pipeendpoint(urb->pipe), ep_type, + usb_pipein(urb->pipe), -+ usb_maxpacket(urb->dev, urb->pipe, -+ !(usb_pipein(urb->pipe)))); ++ usb_maxpacket(urb->dev, urb->pipe)); + + buf = urb->transfer_buffer; + if (hcd_uses_dma(hcd) && !buf && urb->transfer_buffer_length) { @@ -161737,13 +216797,12 @@ +#endif + { + retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb, -+ /*(dwc_otg_qh_t **)*/ -+ ref_ep_hcpriv, 1); ++ &ep->hcpriv, 1); + if (0 == retval) { + if (alloc_bandwidth) { + allocate_bus_bandwidth(hcd, + dwc_otg_hcd_get_ep_bandwidth( -+ dwc_otg_hcd, *ref_ep_hcpriv), ++ dwc_otg_hcd, ep->hcpriv), + urb); + } + } else { @@ -176156,303 +231215,284 @@ +test_main(); +0; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c -index 93f429436e45..dce3990ea33b 100644 +index 0a37f0d511cf..482963bf0018 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c -@@ -98,6 +98,7 @@ static void xhci_free_segments_for_ring(struct xhci_hcd *xhci, - */ - static void xhci_link_segments(struct xhci_segment *prev, - struct xhci_segment *next, -+ unsigned int trbs_per_seg, - enum xhci_ring_type type, bool chain_links) - { - u32 val; -@@ -106,16 +107,16 @@ static void xhci_link_segments(struct xhci_segment *prev, - return; - prev->next = next; - if (type != TYPE_EVENT) { -- prev->trbsTRBS_PER_SEGMENT-1.link.segment_ptr = -+ prev->trbstrbs_per_seg - 1.link.segment_ptr = - cpu_to_le64(next->dma); - - /* Set the last TRB in the segment to have a TRB type ID of Link TRB */ -- val = le32_to_cpu(prev->trbsTRBS_PER_SEGMENT-1.link.control); -+ val = le32_to_cpu(prev->trbstrbs_per_seg - 1.link.control); - val &= ~TRB_TYPE_BITMASK; - val |= TRB_TYPE(TRB_LINK); - if (chain_links) - val |= TRB_CHAIN; -- prev->trbsTRBS_PER_SEGMENT-1.link.control = cpu_to_le32(val); -+ prev->trbstrbs_per_seg - 1.link.control = cpu_to_le32(val); - } - } - -@@ -139,15 +140,17 @@ static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring, - (xhci->quirks & XHCI_AMD_0x96_HOST))); - - next = ring->enq_seg->next; -- xhci_link_segments(ring->enq_seg, first, ring->type, chain_links); -- xhci_link_segments(last, next, ring->type, chain_links); -+ xhci_link_segments(ring->enq_seg, first, ring->trbs_per_seg, -+ ring->type, chain_links); -+ xhci_link_segments(last, next, ring->trbs_per_seg, -+ ring->type, chain_links); - ring->num_segs += num_segs; -- ring->num_trbs_free += (TRBS_PER_SEGMENT - 1) * num_segs; -+ ring->num_trbs_free += (ring->trbs_per_seg - 1) * num_segs; - - if (ring->type != TYPE_EVENT && ring->enq_seg == ring->last_seg) { -- ring->last_seg->trbsTRBS_PER_SEGMENT-1.link.control -+ ring->last_seg->trbsring->trbs_per_seg - 1.link.control - &= ~cpu_to_le32(LINK_TOGGLE); -- last->trbsTRBS_PER_SEGMENT-1.link.control -+ last->trbsring->trbs_per_seg - 1.link.control - |= cpu_to_le32(LINK_TOGGLE); - ring->last_seg = last; - } -@@ -314,14 +317,15 @@ void xhci_initialize_ring_info(struct xhci_ring *ring, - * Each segment has a link TRB, and leave an extra TRB for SW - * accounting purpose - */ -- ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; -+ ring->num_trbs_free = ring->num_segs * (ring->trbs_per_seg - 1) - 1; - } - - /* Allocate segments and link them for a ring */ - static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, - struct xhci_segment **first, struct xhci_segment **last, -- unsigned int num_segs, unsigned int cycle_state, -- enum xhci_ring_type type, unsigned int max_packet, gfp_t flags) -+ unsigned int num_segs, unsigned int trbs_per_seg, -+ unsigned int cycle_state, enum xhci_ring_type type, -+ unsigned int max_packet, gfp_t flags) - { - struct xhci_segment *prev; - bool chain_links; -@@ -350,12 +354,12 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, - } - return -ENOMEM; - } -- xhci_link_segments(prev, next, type, chain_links); -+ xhci_link_segments(prev, next, trbs_per_seg, type, chain_links); - - prev = next; - num_segs--; - } -- xhci_link_segments(prev, *first, type, chain_links); -+ xhci_link_segments(prev, *first, trbs_per_seg, type, chain_links); - *last = prev; +@@ -1400,6 +1400,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, + unsigned int ep_index; + struct xhci_ep_ctx *ep_ctx; + struct xhci_ring *ep_ring; ++ struct usb_interface_cache *intfc; + unsigned int max_packet; + enum xhci_ring_type ring_type; + u32 max_esit_payload; +@@ -1409,6 +1410,8 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, + unsigned int mult; + unsigned int avg_trb_len; + unsigned int err_count = 0; ++ unsigned int is_ums_dev = 0; ++ unsigned int i; - return 0; -@@ -387,16 +391,28 @@ struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, - if (num_segs == 0) - return ring; - -+ ring->trbs_per_seg = TRBS_PER_SEGMENT; -+ /* -+ * The Via VL805 has a bug where cache readahead will fetch off the end -+ * of a page if the Link TRB of a transfer ring is in the last 4 slots. -+ * Where there are consecutive physical pages containing ring segments, -+ * this can cause a desync between the controller's view of a ring -+ * and the host. -+ */ -+ if (xhci->quirks & XHCI_VLI_TRB_CACHE_BUG && -+ type != TYPE_EVENT && type != TYPE_COMMAND) -+ ring->trbs_per_seg -= 4; -+ - ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg, -- &ring->last_seg, num_segs, cycle_state, type, -- max_packet, flags); -+ &ring->last_seg, num_segs, ring->trbs_per_seg, -+ cycle_state, type, max_packet, flags); - if (ret) - goto fail; + ep_index = xhci_get_endpoint_index(&ep->desc); + ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); +@@ -1440,9 +1443,35 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, + + mult = xhci_get_endpoint_mult(udev, ep); + max_packet = usb_endpoint_maxp(&ep->desc); +- max_burst = xhci_get_endpoint_max_burst(udev, ep); + avg_trb_len = max_esit_payload; + ++ /* ++ * VL805 errata - Bulk OUT bursts to superspeed mass-storage ++ * devices behind hub ports can cause data corruption with ++ * non-wMaxPacket-multiple transfers. ++ */ ++ for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { ++ intfc = udev->config->intf_cachei; ++ /* ++ * Slight hack - look at interface altsetting 0, which ++ * should be the UMS bulk-only interface. If the class ++ * matches, then we disable out bursts for all OUT ++ * endpoints because endpoint assignments may change ++ * between alternate settings. ++ */ ++ if (intfc->altsetting0.desc.bInterfaceClass == ++ USB_CLASS_MASS_STORAGE) { ++ is_ums_dev = 1; ++ break; ++ } ++ } ++ if (xhci->quirks & XHCI_VLI_SS_BULK_OUT_BUG && ++ usb_endpoint_is_bulk_out(&ep->desc) && is_ums_dev && ++ udev->route) ++ max_burst = 0; ++ else ++ max_burst = xhci_get_endpoint_max_burst(udev, ep); ++ + /* FIXME dig Mult and streams info out of ep companion desc */ - /* Only event ring does not use link TRB */ - if (type != TYPE_EVENT) { - /* See section 4.9.2.1 and 6.4.4.1 */ -- ring->last_seg->trbsTRBS_PER_SEGMENT - 1.link.control |= -+ ring->last_seg->trbsring->trbs_per_seg - 1.link.control |= - cpu_to_le32(LINK_TOGGLE); - } - xhci_initialize_ring_info(ring, cycle_state); -@@ -429,16 +445,15 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring, - unsigned int num_segs_needed; - int ret; + /* Allow 3 retries for everything but isoc, set CErr = 3 */ +@@ -2239,12 +2268,17 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, gfp_t flags) + struct device *dev = xhci_to_hcd(xhci)->self.sysdev; + struct xhci_interrupter *ir; + int ret; ++ unsigned int nr_event_segs; -- num_segs_needed = (num_trbs + (TRBS_PER_SEGMENT - 1) - 1) / -- (TRBS_PER_SEGMENT - 1); -- -+ num_segs_needed = (num_trbs + (ring->trbs_per_seg - 1) - 1) / -+ (ring->trbs_per_seg - 1); - /* Allocate number of segments we needed, or double the ring size */ - num_segs = ring->num_segs > num_segs_needed ? - ring->num_segs : num_segs_needed; - - ret = xhci_alloc_segments_for_ring(xhci, &first, &last, -- num_segs, ring->cycle_state, ring->type, -- ring->bounce_buf_len, flags); -+ num_segs, ring->trbs_per_seg, ring->cycle_state, -+ ring->type, ring->bounce_buf_len, flags); - if (ret) - return -ENOMEM; + ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev)); + if (!ir) + return NULL; -@@ -1825,7 +1840,7 @@ int xhci_alloc_erst(struct xhci_hcd *xhci, - for (val = 0; val < evt_ring->num_segs; val++) { - entry = &erst->entriesval; - entry->seg_addr = cpu_to_le64(seg->dma); -- entry->seg_size = cpu_to_le32(TRBS_PER_SEGMENT); -+ entry->seg_size = cpu_to_le32(evt_ring->trbs_per_seg); - entry->rsvd = 0; - seg = seg->next; - } -@@ -2533,9 +2548,11 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) - * Event ring setup: Allocate a normal ring, but also setup - * the event ring segment table (ERST). Section 4.9.3. - */ -+ val2 = 1 << HCS_ERST_MAX(xhci->hcs_params2); -+ val2 = min_t(unsigned int, ERST_MAX_SEGS, val2); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring"); -- xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT, -- 0, flags); -+ xhci->event_ring = xhci_ring_alloc(xhci, val2, 1, TYPE_EVENT, -+ 0, flags); - if (!xhci->event_ring) - goto fail; - if (xhci_check_trb_in_td_math(xhci) < 0) -@@ -2548,7 +2565,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) +- ir->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT, ++ nr_event_segs = min_t(unsigned int, ++ 1 << HCS_ERST_MAX(xhci->hcs_params2), ++ ERST_MAX_SEGS); ++ ++ ir->event_ring = xhci_ring_alloc(xhci, nr_event_segs, 1, TYPE_EVENT, + 0, flags); + if (!ir->event_ring) { + xhci_warn(xhci, "Failed to allocate interrupter event ring\n"); +@@ -2281,7 +2315,7 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir, /* set ERST count with the number of entries in the segment table */ - val = readl(&xhci->ir_set->erst_size); - val &= ERST_SIZE_MASK; -- val |= ERST_NUM_SEGS; -+ val |= val2; - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Write ERST size = %i to ir_set 0 (some bits preserved)", - val); + erst_size = readl(&ir->ir_set->erst_size); + erst_size &= ERST_SIZE_MASK; +- erst_size |= ERST_NUM_SEGS; ++ erst_size |= ir->event_ring->num_segs; + writel(erst_size, &ir->ir_set->erst_size); + + erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base); diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c -index 490ce38ae93d..97260e089e0c 100644 +index 44a749fdcafd..71ea283a4f23 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c -@@ -297,6 +297,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) - if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483) { +@@ -27,6 +27,8 @@ + #define SPARSE_DISABLE_BIT 17 + #define SPARSE_CNTL_ENABLE 0xC12C + ++#define VL805_FW_VER_0138C0 0x0138C0 ++ + /* Device for a quirk */ + #define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 + #define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 +@@ -290,6 +292,16 @@ static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev) + return 0; + } + ++static u32 xhci_vl805_get_fw_version(struct pci_dev *dev) ++{ ++ int ret; ++ u32 ver; ++ ++ ret = pci_read_config_dword(dev, 0x50, &ver); ++ /* Default to a fw version of 0 instead of ~0 */ ++ return ret ? 0 : ver; ++} ++ + static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + { + struct pci_dev *pdev = to_pci_dev(dev); +@@ -479,8 +491,15 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + pdev->device == 0x3432) + xhci->quirks |= XHCI_BROKEN_STREAMS; + +- if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483) ++ if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483) { xhci->quirks |= XHCI_LPM_SUPPORT; - xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS; ++ xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS; + xhci->quirks |= XHCI_AVOID_DQ_ON_LINK; -+ xhci->quirks |= XHCI_VLI_TRB_CACHE_BUG; - } ++ xhci->quirks |= XHCI_ZHAOXIN_TRB_FETCH; ++ xhci->quirks |= XHCI_VLI_SS_BULK_OUT_BUG; ++ if (xhci_vl805_get_fw_version(pdev) < VL805_FW_VER_0138C0) ++ xhci->quirks |= XHCI_VLI_HUB_TT_QUIRK; ++ } - if (pdev->vendor == PCI_VENDOR_ID_ZHAOXIN && + if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && + pdev->device == PCI_DEVICE_ID_ASMEDIA_1042_XHCI) { diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c -index 76389c0dda8b..545387a0679a 100644 +index d9e6a3bd3c2a..0ff536c4d61e 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c -@@ -87,15 +87,16 @@ static bool trb_is_link(union xhci_trb *trb) - return TRB_TYPE_LINK_LE32(trb->link.control); - } - --static bool last_trb_on_seg(struct xhci_segment *seg, union xhci_trb *trb) -+static bool last_trb_on_seg(struct xhci_segment *seg, -+ unsigned int trbs_per_seg, union xhci_trb *trb) - { -- return trb == &seg->trbsTRBS_PER_SEGMENT - 1; -+ return trb == &seg->trbstrbs_per_seg - 1; - } - - static bool last_trb_on_ring(struct xhci_ring *ring, - struct xhci_segment *seg, union xhci_trb *trb) - { -- return last_trb_on_seg(seg, trb) && (seg->next == ring->first_seg); -+ return last_trb_on_seg(seg, ring->trbs_per_seg, trb) && (seg->next == ring->first_seg); - } - - static bool link_trb_toggles_cycle(union xhci_trb *trb) -@@ -157,7 +158,8 @@ void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring) - { - /* event ring doesn't have link trbs, check for last trb */ - if (ring->type == TYPE_EVENT) { -- if (!last_trb_on_seg(ring->deq_seg, ring->dequeue)) { -+ if (!last_trb_on_seg(ring->deq_seg, ring->trbs_per_seg, -+ ring->dequeue)) { - ring->dequeue++; - goto out; - } -@@ -265,6 +267,12 @@ static inline int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, - return 0; - - if (ring->type != TYPE_COMMAND && ring->type != TYPE_EVENT) { -+ /* -+ * If the ring has a single segment the dequeue segment -+ * never changes, so don't use it as measure of free space. -+ */ -+ if (ring->num_segs == 1) -+ return ring->num_trbs_free >= num_trbs; - num_trbs_in_deq_seg = ring->dequeue - ring->deq_seg->trbs; - if (ring->num_trbs_free < num_trbs + num_trbs_in_deq_seg) - return 0; -@@ -666,6 +674,16 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, +@@ -626,8 +626,11 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci, + struct xhci_ring *ep_ring; + struct xhci_command *cmd; + struct xhci_segment *new_seg; ++ struct xhci_segment *halted_seg = NULL; + union xhci_trb *new_deq; + int new_cycle; ++ union xhci_trb *halted_trb; ++ int index = 0; + dma_addr_t addr; + u64 hw_dequeue; + bool cycle_found = false; +@@ -665,7 +668,27 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci, + hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id); + new_seg = ep_ring->deq_seg; + new_deq = ep_ring->dequeue; +- new_cycle = hw_dequeue & 0x1; ++ ++ /* ++ * Quirk: xHC write-back of the DCS field in the hardware dequeue ++ * pointer is wrong - use the cycle state of the TRB pointed to by ++ * the dequeue pointer. ++ */ ++ if (xhci->quirks & XHCI_EP_CTX_BROKEN_DCS && ++ !(ep->ep_state & EP_HAS_STREAMS)) ++ halted_seg = trb_in_td(xhci, td->start_seg, ++ td->first_trb, td->last_trb, ++ hw_dequeue & ~0xf, false); ++ if (halted_seg) { ++ index = ((dma_addr_t)(hw_dequeue & ~0xf) - halted_seg->dma) / ++ sizeof(*halted_trb); ++ halted_trb = &halted_seg->trbsindex; ++ new_cycle = halted_trb->generic.field3 & 0x1; ++ xhci_dbg(xhci, "Endpoint DCS = %d TRB index = %d cycle = %d\n", ++ (u8)(hw_dequeue & 0x1), index, new_cycle); ++ } else { ++ new_cycle = hw_dequeue & 0x1; ++ } + /* + * We want to find the pointer, segment and cycle state of the new trb +@@ -698,6 +721,15 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci, } while (!cycle_found || !td_last_trb_found); + deq_found: + /* + * Quirk: the xHC does not correctly parse link TRBs if the HW Dequeue + * pointer is set to one. Advance to the next TRB (and next segment). + */ + if (xhci->quirks & XHCI_AVOID_DQ_ON_LINK && trb_is_link(new_deq)) { + if (link_trb_toggles_cycle(new_deq)) -+ state->new_cycle_state ^= 0x1; ++ new_cycle ^= 0x1; + next_trb(xhci, ep_ring, &new_seg, &new_deq); + } -+ - state->new_deq_seg = new_seg; - state->new_deq_ptr = new_deq; -@@ -2966,7 +2984,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) - * that clears the EHB. - */ - while (xhci_handle_event(xhci) > 0) { -- if (event_loop++ < TRBS_PER_SEGMENT / 2) -+ if (event_loop++ < xhci->event_ring->trbs_per_seg / 2) - continue; - xhci_update_erst_dequeue(xhci, event_ring_deq); - event_loop = 0; -@@ -4258,9 +4276,9 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, + /* Don't update the ring cycle state for the producer (us). */ + addr = xhci_trb_virt_to_dma(new_seg, new_deq); +@@ -708,9 +740,9 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci, } - ep = &xhci->devsslot_id->epsep_index; + if ((ep->ep_state & SET_DEQ_PENDING)) { -- xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr\n"); -- xhci_warn(xhci, "A Set TR Deq Ptr command is pending.\n"); -- return; +- xhci_warn(xhci, "Set TR Deq already pending, don't submit for 0x%pad\n", +- &addr); +- return -EBUSY; + xhci_warn(xhci, "WARN A Set TR Deq Ptr command is pending for slot %u ep %u\n", + slot_id, ep_index); + ep->ep_state &= ~SET_DEQ_PENDING; } /* This function gets called from contexts where it cannot sleep */ +@@ -3589,6 +3621,48 @@ static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len, + return 1; + } + ++static void xhci_vl805_hub_tt_quirk(struct xhci_hcd *xhci, struct urb *urb, ++ struct xhci_ring *ring) ++{ ++ struct list_head *tmp; ++ struct usb_device *udev = urb->dev; ++ unsigned int timeout = 0; ++ unsigned int single_td = 0; ++ ++ /* ++ * Adding a TD to an Idle ring for a FS nonperiodic endpoint ++ * that is behind the internal hub's TT will run the risk of causing a ++ * downstream port babble if submitted late in uFrame 7. ++ * Wait until we've moved on into at least uFrame 0 ++ * (MFINDEX references the next SOF to be transmitted). ++ * ++ * Rings for IN endpoints in the Running state also risk causing ++ * babble if the returned data is large, but there's not much we can do ++ * about it here. ++ */ ++ if (udev->route & 0xffff0 || udev->speed != USB_SPEED_FULL) ++ return; ++ ++ list_for_each(tmp, &ring->td_list) { ++ single_td++; ++ if (single_td == 2) { ++ single_td = 0; ++ break; ++ } ++ } ++ if (single_td) { ++ while (timeout < 20 && ++ (readl(&xhci->run_regs->microframe_index) & 0x7) == 0) { ++ udelay(10); ++ timeout++; ++ } ++ if (timeout >= 20) ++ xhci_warn(xhci, "MFINDEX didn't advance - %u.%u dodged\n", ++ readl(&xhci->run_regs->microframe_index) >> 3, ++ readl(&xhci->run_regs->microframe_index) & 7); ++ } ++} ++ + /* This is very similar to what ehci-q.c qtd_fill() does */ + int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, + struct urb *urb, int slot_id, unsigned int ep_index) +@@ -3745,6 +3819,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, + } + + check_trb_math(urb, enqd_len); ++ if (xhci->quirks & XHCI_VLI_HUB_TT_QUIRK) ++ xhci_vl805_hub_tt_quirk(xhci, urb, ring); + giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, + start_cycle, start_trb); + return 0; +@@ -3880,6 +3956,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, + /* Event on completion */ + field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state); + ++ if (xhci->quirks & XHCI_VLI_HUB_TT_QUIRK) ++ xhci_vl805_hub_tt_quirk(xhci, urb, ep_ring); + giveback_first_trb(xhci, slot_id, ep_index, 0, + start_cycle, start_trb); + return 0; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c -index 7f1e5296d0f6..16b4a4b76da0 100644 +index 132b76fa7ca6..34a21cc5b530 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c -@@ -858,8 +858,8 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci) - seg = ring->deq_seg; - do { - memset(seg->trbs, 0, -- sizeof(union xhci_trb) * (TRBS_PER_SEGMENT - 1)); -- seg->trbsTRBS_PER_SEGMENT - 1.link.control &= -+ sizeof(union xhci_trb) * (ring->trbs_per_seg - 1)); -+ seg->trbsring->trbs_per_seg - 1.link.control &= - cpu_to_le32(~TRB_CYCLE); - seg = seg->next; - } while (seg != ring->deq_seg); -@@ -870,7 +870,7 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci) - ring->enq_seg = ring->deq_seg; - ring->enqueue = ring->dequeue; - -- ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; -+ ring->num_trbs_free = ring->num_segs * (ring->trbs_per_seg - 1) - 1; - /* - * Ring is now zeroed, so the HW should look for change of ownership - * when the cycle bit is set to 1. -@@ -1466,6 +1466,103 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, +@@ -1484,6 +1484,109 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, return ret; } @@ -176463,6 +231503,12 @@ + * - force an endpoint configure command + * XXX: bandwidth is not recalculated. We should probably do that. + */ ++ ++static unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index) ++{ ++ return 1 << (ep_index + 1); ++} ++ +static void xhci_fixup_endpoint(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep, int interval) +{ @@ -176540,7 +231586,7 @@ + return; + } + ctrl_ctx->add_flags = xhci_get_endpoint_flag_from_index(ep_index); -+ ctrl_ctx->drop_flags = 0; ++ ctrl_ctx->drop_flags = ctrl_ctx->add_flags; + + spin_unlock_irqrestore(&xhci->lock, flags); + @@ -176556,7 +231602,7 @@ /* * non-error returns are a promise to giveback() the urb later * we drop ownership so next owner (or urb unlink) can get it -@@ -5419,6 +5516,7 @@ static const struct hc_driver xhci_hc_driver = { +@@ -5305,6 +5408,7 @@ static const struct hc_driver xhci_hc_driver = { .endpoint_reset = xhci_endpoint_reset, .check_bandwidth = xhci_check_bandwidth, .reset_bandwidth = xhci_reset_bandwidth, @@ -176565,42 +231611,56 @@ .enable_device = xhci_enable_device, .update_hub_device = xhci_update_hub_device, diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h -index 679ef073d99d..3a75a4dfed3c 100644 +index 3aabdb06b7a3..7b5933633ea0 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h -@@ -1615,6 +1615,7 @@ struct xhci_ring { - unsigned int num_trbs_free; - unsigned int num_trbs_free_temp; - unsigned int bounce_buf_len; -+ unsigned int trbs_per_seg; - enum xhci_ring_type type; - bool last_td_was_short; - struct radix_tree_root *trb_address_map; -@@ -1653,8 +1654,8 @@ struct urb_priv { +@@ -1674,8 +1674,9 @@ struct urb_priv { * Each segment table entry is 4*32bits long. 1K seems like an ok size: * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, * meaning 64 ring segments. - * Initial allocated size of the ERST, in number of entries */ -#define ERST_NUM_SEGS 1 -+ * Maximum number of segments in the ERST */ ++ */ ++/* Maximum number of segments in the ERST */ +#define ERST_MAX_SEGS 8 - /* Initial allocated size of the ERST, in number of entries */ - #define ERST_SIZE 64 - /* Initial number of event segment rings allocated */ -@@ -1887,6 +1888,8 @@ struct xhci_hcd { - #define XHCI_ZHAOXIN_HOST BIT_ULL(41) - #define XHCI_ZHAOXIN_TRB_FETCH BIT_ULL(42) - #define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(43) -+#define XHCI_AVOID_DQ_ON_LINK BIT_ULL(44) -+#define XHCI_VLI_TRB_CACHE_BUG BIT_ULL(45) - + /* Poll every 60 seconds */ + #define POLL_TIMEOUT 60 + /* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */ +@@ -1909,6 +1910,11 @@ struct xhci_hcd { + #define XHCI_ZHAOXIN_TRB_FETCH BIT_ULL(45) + #define XHCI_ZHAOXIN_HOST BIT_ULL(46) + ++/* Downstream VLI fixes */ ++#define XHCI_AVOID_DQ_ON_LINK BIT_ULL(56) ++#define XHCI_VLI_SS_BULK_OUT_BUG BIT_ULL(57) ++#define XHCI_VLI_HUB_TT_QUIRK BIT_ULL(58) ++ unsigned int num_active_eps; unsigned int limit_active_eps; + struct xhci_port *hw_ports; +diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c +index 770081b828a4..c4b3f2484dc0 100644 +--- a/drivers/usb/phy/phy-generic.c ++++ b/drivers/usb/phy/phy-generic.c +@@ -261,13 +261,6 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop) + return dev_err_probe(dev, PTR_ERR(nop->vcc), + "could not get vcc regulator\n"); + +- nop->vbus_draw = devm_regulator_get_exclusive(dev, "vbus"); +- if (PTR_ERR(nop->vbus_draw) == -ENODEV) +- nop->vbus_draw = NULL; +- if (IS_ERR(nop->vbus_draw)) +- return dev_err_probe(dev, PTR_ERR(nop->vbus_draw), +- "could not get vbus regulator\n"); +- + nop->dev = dev; + nop->phy.dev = nop->dev; + nop->phy.label = "nop-xceiv"; diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig -index d83c87b902c1..ed22a119c992 100644 +index 51387b1ef012..b4a61d00ba39 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig -@@ -248,6 +248,13 @@ config BACKLIGHT_PWM +@@ -249,6 +249,13 @@ config BACKLIGHT_PWM If you have a LCD backlight adjustable by PWM, say Y to enable this driver. @@ -176615,17 +231675,101 @@ tristate "Backlight Driver for DA9030/DA9034 using WLED" depends on PMIC_DA903X diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile -index 685f3f1ca4df..836f0d0d1ca0 100644 +index f72e1c3c59e9..e03cc5a394e5 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile -@@ -49,6 +49,7 @@ obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o +@@ -50,6 +50,7 @@ obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o obj-$(CONFIG_BACKLIGHT_QCOM_WLED) += qcom-wled.o +obj-$(CONFIG_BACKLIGHT_RPI) += rpi_backlight.o + obj-$(CONFIG_BACKLIGHT_RT4831) += rt4831-backlight.o obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o - obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o +diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c +index 8fcb62be597b..a3412c936ca2 100644 +--- a/drivers/video/backlight/lm3630a_bl.c ++++ b/drivers/video/backlight/lm3630a_bl.c +@@ -180,7 +180,7 @@ static int lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max) + + pchip->pwmd_state.enabled = pchip->pwmd_state.duty_cycle ? true : false; + +- return pwm_apply_state(pchip->pwmd, &pchip->pwmd_state); ++ return pwm_apply_might_sleep(pchip->pwmd, &pchip->pwmd_state); + } + + /* update and get brightness */ +diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c +index da1f124db69c..7075bfab59c4 100644 +--- a/drivers/video/backlight/lp855x_bl.c ++++ b/drivers/video/backlight/lp855x_bl.c +@@ -234,7 +234,7 @@ static int lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br) + state.duty_cycle = div_u64(br * state.period, max_br); + state.enabled = state.duty_cycle; + +- return pwm_apply_state(lp->pwm, &state); ++ return pwm_apply_might_sleep(lp->pwm, &state); + } + + static int lp855x_bl_update_status(struct backlight_device *bl) +diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c +index 289bd9ce4d36..35c716e9043c 100644 +--- a/drivers/video/backlight/pwm_bl.c ++++ b/drivers/video/backlight/pwm_bl.c +@@ -103,7 +103,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl) + pwm_get_state(pb->pwm, &state); + state.duty_cycle = compute_duty_cycle(pb, brightness, &state); + state.enabled = true; +- pwm_apply_state(pb->pwm, &state); ++ pwm_apply_might_sleep(pb->pwm, &state); + + pwm_backlight_power_on(pb); + } else { +@@ -120,7 +120,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl) + * inactive output. + */ + state.enabled = !pb->power_supply && !pb->enable_gpio; +- pwm_apply_state(pb->pwm, &state); ++ pwm_apply_might_sleep(pb->pwm, &state); + } + + if (pb->notify_after) +@@ -528,7 +528,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) + if (!state.period && (data->pwm_period_ns > 0)) + state.period = data->pwm_period_ns; + +- ret = pwm_apply_state(pb->pwm, &state); ++ ret = pwm_apply_might_sleep(pb->pwm, &state); + if (ret) { + dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n", + ret); +@@ -633,7 +633,7 @@ static void pwm_backlight_remove(struct platform_device *pdev) + pwm_get_state(pb->pwm, &state); + state.duty_cycle = 0; + state.enabled = false; +- pwm_apply_state(pb->pwm, &state); ++ pwm_apply_might_sleep(pb->pwm, &state); + + if (pb->exit) + pb->exit(&pdev->dev); +@@ -649,7 +649,7 @@ static void pwm_backlight_shutdown(struct platform_device *pdev) + pwm_get_state(pb->pwm, &state); + state.duty_cycle = 0; + state.enabled = false; +- pwm_apply_state(pb->pwm, &state); ++ pwm_apply_might_sleep(pb->pwm, &state); + } + + #ifdef CONFIG_PM_SLEEP +@@ -673,7 +673,7 @@ static int pwm_backlight_suspend(struct device *dev) + pwm_get_state(pb->pwm, &state); + state.duty_cycle = 0; + state.enabled = false; +- pwm_apply_state(pb->pwm, &state); ++ pwm_apply_might_sleep(pb->pwm, &state); + + if (pb->notify_after) + pb->notify_after(pb->dev, 0); diff --git a/drivers/video/backlight/rpi_backlight.c b/drivers/video/backlight/rpi_backlight.c new file mode 100644 index 000000000000..14a0d9b03739 @@ -176752,11 +231896,11 @@ +MODULE_DESCRIPTION("Raspberry Pi mailbox based Backlight Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig -index 4f02db65dede..d3f87a523f6e 100644 +index 35b3ca2fb50a..a9718a3de63c 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig -@@ -219,6 +219,20 @@ config FB_TILEBLITTING - comment "Frame buffer hardware drivers" +@@ -61,6 +61,20 @@ config FB_MACMODES + tristate depends on FB +config FB_BCM2708 @@ -176776,9 +231920,9 @@ config FB_GRVGA tristate "Aeroflex Gaisler framebuffer support" depends on FB && SPARC -@@ -2236,6 +2250,19 @@ config FB_SM712 - called sm712fb. If you want to compile it as a module, say M - here and read <file:Documentation/kbuild/modules.rst>. +@@ -1963,6 +1977,19 @@ config FB_LS2K500 + If you want to compile it as a module, say M here and read + <file:Documentation/kbuild/modules.rst>. +config FB_RPISENSE + tristate "Raspberry Pi Sense HAT framebuffer" @@ -176797,7 +231941,7 @@ source "drivers/video/fbdev/omap2/Kconfig" source "drivers/video/fbdev/mmp/Kconfig" diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile -index 477b9624b703..5a478be6bcb4 100644 +index d3fbb185daa3..e04b745ec510 100644 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_FB_MACMODES) += macmodes.o @@ -176808,7 +231952,7 @@ obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o obj-$(CONFIG_FB_ARC) += arcfb.o obj-$(CONFIG_FB_CLPS711X) += clps711x-fb.o -@@ -129,6 +130,7 @@ obj-$(CONFIG_FB_MX3) += mx3fb.o +@@ -125,6 +126,7 @@ obj-$(CONFIG_FB_OF) += offb.o obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o obj-$(CONFIG_FB_SIMPLE) += simplefb.o @@ -176818,7 +231962,7 @@ obj-$(CONFIG_FB_VIRTUAL) += vfb.o diff --git a/drivers/video/fbdev/bcm2708_fb.c b/drivers/video/fbdev/bcm2708_fb.c new file mode 100644 -index 000000000000..365c5b96b8a0 +index 000000000000..4732cb18d792 --- /dev/null +++ b/drivers/video/fbdev/bcm2708_fb.c @@ -0,0 +1,1274 @@ @@ -177816,7 +232960,7 @@ + int ret; + + fb->fb.fbops = &bcm2708_fb_ops; -+ fb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_COPYAREA; ++ fb->fb.flags = FBINFO_HWACCEL_COPYAREA; + fb->fb.pseudo_palette = fb->cmap; + + strncpy(fb->fb.fix.id, bcm2708_name, sizeof(fb->fb.fix.id)); @@ -178096,190 +233240,13 @@ +MODULE_PARM_DESC(fbheight, "Height of ARM Framebuffer"); +MODULE_PARM_DESC(fbdepth, "Bit depth of ARM Framebuffer"); +MODULE_PARM_DESC(fbswap, "Swap order of red and blue in 24 and 32 bit modes"); -diff --git a/drivers/video/fbdev/core/cfbimgblt.c b/drivers/video/fbdev/core/cfbimgblt.c -index a2bb276a8b24..436494fba15a 100644 ---- a/drivers/video/fbdev/core/cfbimgblt.c -+++ b/drivers/video/fbdev/core/cfbimgblt.c -@@ -28,6 +28,11 @@ - * - * Also need to add code to deal with cards endians that are different than - * the native cpu endians. I also need to deal with MSB position in the word. -+ * Modified by Harm Hanemaaijer (fgenfb@yahoo.com) 2013: -+ * - Provide optimized versions of fast_imageblit for 16 and 32bpp that are -+ * significantly faster than the previous implementation. -+ * - Simplify the fast/slow_imageblit selection code, avoiding integer -+ * divides. - */ - #include <linux/module.h> - #include <linux/string.h> -@@ -262,6 +267,133 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info * - } - } - -+/* -+ * Optimized fast_imageblit for bpp == 16. ppw = 2, bit_mask = 3 folded -+ * into the code, main loop unrolled. -+ */ -+ -+static inline void fast_imageblit16(const struct fb_image *image, -+ struct fb_info *p, u8 __iomem * dst1, -+ u32 fgcolor, u32 bgcolor) -+{ -+ u32 fgx = fgcolor, bgx = bgcolor; -+ u32 spitch = (image->width + 7) / 8; -+ u32 end_mask, eorx; -+ const char *s = image->data, *src; -+ u32 __iomem *dst; -+ const u32 *tab = NULL; -+ int i, j, k; -+ -+ tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le; -+ -+ fgx <<= 16; -+ bgx <<= 16; -+ fgx |= fgcolor; -+ bgx |= bgcolor; -+ -+ eorx = fgx ^ bgx; -+ k = image->width / 2; -+ -+ for (i = image->height; i--;) { -+ dst = (u32 __iomem *) dst1; -+ src = s; -+ -+ j = k; -+ while (j >= 4) { -+ u8 bits = *src; -+ end_mask = tab(bits >> 6) & 3; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab(bits >> 4) & 3; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab(bits >> 2) & 3; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tabbits & 3; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ src++; -+ j -= 4; -+ } -+ if (j != 0) { -+ u8 bits = *src; -+ end_mask = tab(bits >> 6) & 3; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ if (j >= 2) { -+ end_mask = tab(bits >> 4) & 3; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ if (j == 3) { -+ end_mask = tab(bits >> 2) & 3; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst); -+ } -+ } -+ } -+ dst1 += p->fix.line_length; -+ s += spitch; -+ } -+} -+ -+/* -+ * Optimized fast_imageblit for bpp == 32. ppw = 1, bit_mask = 1 folded -+ * into the code, main loop unrolled. -+ */ -+ -+static inline void fast_imageblit32(const struct fb_image *image, -+ struct fb_info *p, u8 __iomem * dst1, -+ u32 fgcolor, u32 bgcolor) -+{ -+ u32 fgx = fgcolor, bgx = bgcolor; -+ u32 spitch = (image->width + 7) / 8; -+ u32 end_mask, eorx; -+ const char *s = image->data, *src; -+ u32 __iomem *dst; -+ const u32 *tab = NULL; -+ int i, j, k; -+ -+ tab = cfb_tab32; -+ -+ eorx = fgx ^ bgx; -+ k = image->width; -+ -+ for (i = image->height; i--;) { -+ dst = (u32 __iomem *) dst1; -+ src = s; -+ -+ j = k; -+ while (j >= 8) { -+ u8 bits = *src; -+ end_mask = tab(bits >> 7) & 1; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab(bits >> 6) & 1; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab(bits >> 5) & 1; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab(bits >> 4) & 1; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab(bits >> 3) & 1; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab(bits >> 2) & 1; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab(bits >> 1) & 1; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tabbits & 1; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ src++; -+ j -= 8; -+ } -+ if (j != 0) { -+ u32 bits = (u32) * src; -+ while (j > 1) { -+ end_mask = tab(bits >> 7) & 1; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ bits <<= 1; -+ j--; -+ } -+ end_mask = tab(bits >> 7) & 1; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst); -+ } -+ dst1 += p->fix.line_length; -+ s += spitch; -+ } -+} -+ - void cfb_imageblit(struct fb_info *p, const struct fb_image *image) - { - u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0; -@@ -294,11 +426,21 @@ void cfb_imageblit(struct fb_info *p, const struct fb_image *image) - bgcolor = image->bg_color; - } - -- if (32 % bpp == 0 && !start_index && !pitch_index && -- ((width & (32/bpp-1)) == 0) && -- bpp >= 8 && bpp <= 32) -- fast_imageblit(image, p, dst1, fgcolor, bgcolor); -- else -+ if (!start_index && !pitch_index) { -+ if (bpp == 32) -+ fast_imageblit32(image, p, dst1, fgcolor, -+ bgcolor); -+ else if (bpp == 16 && (width & 1) == 0) -+ fast_imageblit16(image, p, dst1, fgcolor, -+ bgcolor); -+ else if (bpp == 8 && (width & 3) == 0) -+ fast_imageblit(image, p, dst1, fgcolor, -+ bgcolor); -+ else -+ slow_imageblit(image, p, dst1, fgcolor, -+ bgcolor, -+ start_index, pitch_index); -+ } else - slow_imageblit(image, p, dst1, fgcolor, bgcolor, - start_index, pitch_index); - } else -diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c -index 00939ca2065a..098cd5dfc06f 100644 ---- a/drivers/video/fbdev/core/fbmem.c -+++ b/drivers/video/fbdev/core/fbmem.c -@@ -1085,6 +1085,30 @@ fb_blank(struct fb_info *info, int blank) +diff --git a/drivers/video/fbdev/core/fb_chrdev.c b/drivers/video/fbdev/core/fb_chrdev.c +index eadb81f53a82..df06a9ecba8d 100644 +--- a/drivers/video/fbdev/core/fb_chrdev.c ++++ b/drivers/video/fbdev/core/fb_chrdev.c +@@ -59,6 +59,30 @@ static ssize_t fb_write(struct file *file, const char __user *buf, size_t count, + return fb_io_write(info, buf, count, ppos); } - EXPORT_SYMBOL(fb_blank); +static int fb_copyarea_user(struct fb_info *info, + struct fb_copyarea *copy) @@ -178308,7 +233275,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { -@@ -1093,6 +1117,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, +@@ -67,6 +91,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, struct fb_fix_screeninfo fix; struct fb_cmap cmap_from; struct fb_cmap_user cmap; @@ -178316,7 +233283,7 @@ void __user *argp = (void __user *)arg; long ret = 0; -@@ -1168,6 +1193,15 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, +@@ -148,6 +173,15 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, unlock_fb_info(info); console_unlock(); break; @@ -178328,11 +233295,11 @@ + ret = fb_copyarea_user(info, ©); + break; + } -+ /* fall through */ ++ fallthrough; default: lock_fb_info(info); fb = info->fbops; -@@ -1313,6 +1347,7 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd, +@@ -287,6 +321,7 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd, case FBIOPAN_DISPLAY: case FBIOGET_CON2FBMAP: case FBIOPUT_CON2FBMAP: @@ -178340,12 +233307,77 @@ arg = (unsigned long) compat_ptr(arg); fallthrough; case FBIOBLANK: +diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c +index 1ae1d35a5942..4708c6e19a65 100644 +--- a/drivers/video/fbdev/core/fb_defio.c ++++ b/drivers/video/fbdev/core/fb_defio.c +@@ -313,7 +313,8 @@ static void fb_deferred_io_lastclose(struct fb_info *info) + struct page *page; + int i; + +- flush_delayed_work(&info->deferred_work); ++ if (!list_empty(&info->fbdefio->pagereflist)) ++ flush_delayed_work(&info->deferred_work); + + /* clear out the mapping that we setup */ + for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) { +diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c +index ee44a46a66be..e21782ba1ce2 100644 +--- a/drivers/video/fbdev/core/fbmem.c ++++ b/drivers/video/fbdev/core/fbmem.c +@@ -49,6 +49,7 @@ struct class *fb_class; + DEFINE_MUTEX(registration_lock); + struct fb_info *registered_fbFB_MAX __read_mostly; + int num_registered_fb __read_mostly; ++int min_dynamic_fb __read_mostly; + #define for_each_registered_fb(i) \ + for (i = 0; i < FB_MAX; i++) \ + if (!registered_fbi) {} else +@@ -938,10 +939,12 @@ static int do_register_framebuffer(struct fb_info *fb_info) + return -ENXIO; + + num_registered_fb++; +- for (i = 0 ; i < FB_MAX; i++) +- if (!registered_fbi) +- break; +- fb_info->node = i; ++ if (!fb_info->custom_fb_num || fb_info->node >= FB_MAX || registered_fbfb_info->node) { ++ for (i = min_dynamic_fb ; i < FB_MAX; i++) ++ if (!registered_fbi) ++ break; ++ fb_info->node = i; ++ } + refcount_set(&fb_info->count, 1); + mutex_init(&fb_info->lock); + mutex_init(&fb_info->mm_lock); +@@ -976,7 +979,7 @@ static int do_register_framebuffer(struct fb_info *fb_info) + + fb_var_to_videomode(&mode, &fb_info->var); + fb_add_videomode(&mode, &fb_info->modelist); +- registered_fbi = fb_info; ++ registered_fbfb_info->node = fb_info; + + #ifdef CONFIG_GUMSTIX_AM200EPD + { +@@ -1037,6 +1040,12 @@ static void do_unregister_framebuffer(struct fb_info *fb_info) + put_fb_info(fb_info); + } + ++void fb_set_lowest_dynamic_fb(int min_fb_dev) ++{ ++ min_dynamic_fb = min_fb_dev; ++} ++EXPORT_SYMBOL(fb_set_lowest_dynamic_fb); ++ + /** + * register_framebuffer - registers a frame buffer device + * @fb_info: frame buffer info structure diff --git a/drivers/video/fbdev/rpisense-fb.c b/drivers/video/fbdev/rpisense-fb.c new file mode 100644 -index 000000000000..325977def531 +index 000000000000..22db39bf0f07 --- /dev/null +++ b/drivers/video/fbdev/rpisense-fb.c -@@ -0,0 +1,296 @@ +@@ -0,0 +1,297 @@ +/* + * Raspberry Pi Sense HAT framebuffer driver + * http://raspberrypi.org @@ -178539,6 +233571,7 @@ + .fb_copyarea = rpisense_fb_copyarea, + .fb_imageblit = rpisense_fb_imageblit, + .fb_ioctl = rpisense_fb_ioctl, ++ .fb_mmap = fb_deferred_io_mmap, +}; + +static int rpisense_fb_probe(struct platform_device *pdev) @@ -178572,7 +233605,7 @@ + info->fix = rpisense_fb_fix; + info->var = rpisense_fb_var; + info->fbdefio = &rpisense_fb_defio; -+ info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; ++ info->flags = FBINFO_VIRTFB; + info->screen_base = rpisense_fb_param.vmem; + info->screen_size = rpisense_fb_param.vmemsize; + info->pseudo_palette = pseudo_palette; @@ -178642,6 +233675,19 @@ +MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>"); +MODULE_LICENSE("GPL"); + +diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c +index 5ae48e36fccb..1a4f90ea7d5a 100644 +--- a/drivers/video/fbdev/ssd1307fb.c ++++ b/drivers/video/fbdev/ssd1307fb.c +@@ -347,7 +347,7 @@ static int ssd1307fb_init(struct ssd1307fb_par *par) + + pwm_init_state(par->pwm, &pwmstate); + pwm_set_relative_duty_cycle(&pwmstate, 50, 100); +- pwm_apply_state(par->pwm, &pwmstate); ++ pwm_apply_might_sleep(par->pwm, &pwmstate); + + /* Enable the PWM */ + pwm_enable(par->pwm); diff --git a/drivers/video/logo/logo_linux_clut224.ppm b/drivers/video/logo/logo_linux_clut224.ppm index 3c14e43b82fe..7626beb6a5bb 100644 --- a/drivers/video/logo/logo_linux_clut224.ppm @@ -181133,7 +236179,7 @@ +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c -index d4632aace402..4832cd8c2596 100644 +index e45acb6d916e..68a1e48cd34e 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -30,7 +30,7 @@ static u8 w1_gpio_set_pullup(void *data, int delay) @@ -181145,8 +236191,150 @@ msleep(pdata->pullup_duration); /* * This will simply set the line as input since we are doing +@@ -76,6 +76,11 @@ static int w1_gpio_probe(struct platform_device *pdev) + enum gpiod_flags gflags = GPIOD_OUT_LOW_OPEN_DRAIN; + int err; + ++ master = devm_kzalloc(dev, sizeof(struct w1_bus_master), ++ GFP_KERNEL); ++ if (!master) ++ return -ENOMEM; ++ + if (of_have_populated_dt()) { + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) +@@ -90,6 +95,9 @@ static int w1_gpio_probe(struct platform_device *pdev) + if (of_property_present(np, "linux,open-drain")) + gflags = GPIOD_OUT_LOW; + ++ if (of_property_present(np, "raspberrypi,delay-needs-poll")) ++ master->delay_needs_poll = true; ++ + pdev->dev.platform_data = pdata; + } + pdata = dev_get_platdata(dev); +@@ -99,11 +107,6 @@ static int w1_gpio_probe(struct platform_device *pdev) + return -ENXIO; + } + +- master = devm_kzalloc(dev, sizeof(struct w1_bus_master), +- GFP_KERNEL); +- if (!master) +- return -ENOMEM; +- + pdata->gpiod = devm_gpiod_get_index(dev, NULL, 0, gflags); + if (IS_ERR(pdata->gpiod)) { + dev_err(dev, "gpio_request (pin) failed\n"); +diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c +index 5353cbd75126..a2d0669607a8 100644 +--- a/drivers/w1/w1.c ++++ b/drivers/w1/w1.c +@@ -733,8 +733,10 @@ int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) + atomic_set(&sl->refcnt, 1); + atomic_inc(&sl->master->refcnt); + dev->slave_count++; ++#if 0 + dev_info(&dev->dev, "Attaching one wire slave %02x.%012llx crc %02x\n", + rn->family, (unsigned long long)rn->id, rn->crc); ++#endif + + /* slave modules need to be loaded in a context with unlocked mutex */ + mutex_unlock(&dev->mutex); +diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c +index db3c9522a8a2..b495624984bd 100644 +--- a/drivers/w1/w1_io.c ++++ b/drivers/w1/w1_io.c +@@ -6,6 +6,7 @@ + #include <asm/io.h> + + #include <linux/delay.h> ++#include <linux/ktime.h> + #include <linux/moduleparam.h> + #include <linux/module.h> + +@@ -36,9 +37,21 @@ static u8 w1_crc8_table = { + 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53 + }; + +-static void w1_delay(unsigned long tm) ++static void w1_delay(struct w1_master *dev, unsigned long tm) + { +- udelay(tm * w1_delay_parm); ++ ktime_t start, delta; ++ ++ if (!dev->bus_master->delay_needs_poll) { ++ udelay(tm * w1_delay_parm); ++ return; ++ } ++ ++ start = ktime_get(); ++ delta = ktime_add(start, ns_to_ktime(1000 * tm * w1_delay_parm)); ++ do { ++ dev->bus_master->read_bit(dev->bus_master->data); ++ udelay(1); ++ } while (ktime_before(ktime_get(), delta)); + } + + static void w1_write_bit(struct w1_master *dev, int bit); +@@ -77,14 +90,14 @@ static void w1_write_bit(struct w1_master *dev, int bit) + + if (bit) { + dev->bus_master->write_bit(dev->bus_master->data, 0); +- w1_delay(6); ++ w1_delay(dev, 6); + dev->bus_master->write_bit(dev->bus_master->data, 1); +- w1_delay(64); ++ w1_delay(dev, 64); + } else { + dev->bus_master->write_bit(dev->bus_master->data, 0); +- w1_delay(60); ++ w1_delay(dev, 60); + dev->bus_master->write_bit(dev->bus_master->data, 1); +- w1_delay(10); ++ w1_delay(dev, 10); + } + + if(w1_disable_irqs) local_irq_restore(flags); +@@ -164,14 +177,14 @@ static u8 w1_read_bit(struct w1_master *dev) + /* sample timing is critical here */ + local_irq_save(flags); + dev->bus_master->write_bit(dev->bus_master->data, 0); +- w1_delay(6); ++ w1_delay(dev, 6); + dev->bus_master->write_bit(dev->bus_master->data, 1); +- w1_delay(9); ++ w1_delay(dev, 9); + + result = dev->bus_master->read_bit(dev->bus_master->data); + local_irq_restore(flags); + +- w1_delay(55); ++ w1_delay(dev, 55); + + return result & 0x1; + } +@@ -333,16 +346,16 @@ int w1_reset_bus(struct w1_master *dev) + * cpu for such a short amount of time AND get it back in + * the maximum amount of time. + */ +- w1_delay(500); ++ w1_delay(dev, 500); + dev->bus_master->write_bit(dev->bus_master->data, 1); +- w1_delay(70); ++ w1_delay(dev, 70); + + result = dev->bus_master->read_bit(dev->bus_master->data) & 0x1; + /* minimum 70 (above) + 430 = 500 us + * There aren't any timing requirements between a reset and + * the following transactions. Sleeping is safe here. + */ +- /* w1_delay(430); min required time */ ++ /* w1_delay(dev, 430); min required time */ + msleep(1); + } + diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c -index dec6ca019bea..de25e3682f03 100644 +index bb001c5d7f17..2ce96ba0ee39 100644 --- a/drivers/watchdog/bcm2835_wdt.c +++ b/drivers/watchdog/bcm2835_wdt.c @@ -32,13 +32,7 @@ @@ -181164,7 +236352,7 @@ #define SECS_TO_WDOG_TICKS(x) ((x) << 16) #define WDOG_TICKS_TO_SECS(x) ((x) >> 16) -@@ -97,9 +91,24 @@ static unsigned int bcm2835_wdt_get_timeleft(struct watchdog_device *wdog) +@@ -98,9 +92,24 @@ static unsigned int bcm2835_wdt_get_timeleft(struct watchdog_device *wdog) return WDOG_TICKS_TO_SECS(ret & PM_WDOG_TIME_SET); } @@ -181191,7 +236379,7 @@ /* use a timeout of 10 ticks (~150us) */ writel_relaxed(10 | PM_PASSWORD, wdt->base + PM_WDOG); -@@ -117,7 +126,15 @@ static int bcm2835_restart(struct watchdog_device *wdog, +@@ -118,7 +127,15 @@ static int bcm2835_restart(struct watchdog_device *wdog, { struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog); @@ -181208,7 +236396,7 @@ return 0; } -@@ -152,19 +169,9 @@ static struct watchdog_device bcm2835_wdt_wdd = { +@@ -153,19 +170,9 @@ static struct watchdog_device bcm2835_wdt_wdd = { static void bcm2835_power_off(void) { struct bcm2835_wdt *wdt = bcm2835_power_off_wdt; @@ -181230,594 +236418,215 @@ } static int bcm2835_wdt_probe(struct platform_device *pdev) -diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h -index d07c851d255b..5d34c1df03f3 100644 ---- a/include/drm/drm_atomic.h -+++ b/include/drm/drm_atomic.h -@@ -248,6 +248,26 @@ struct drm_private_state_funcs { - * drm_dev_register() - * 2/ all calls to drm_atomic_private_obj_fini() must be done after calling - * drm_dev_unregister() -+ * -+ * If that private object is used to store a state shared by multiple -+ * CRTCs, proper care must be taken to ensure that non-blocking commits are -+ * properly ordered to avoid a use-after-free issue. -+ * -+ * Indeed, assuming a sequence of two non-blocking &drm_atomic_commit on two -+ * different &drm_crtc using different &drm_plane and &drm_connector, so with no -+ * resources shared, there's no guarantee on which commit is going to happen -+ * first. However, the second &drm_atomic_commit will consider the first -+ * &drm_private_obj its old state, and will be in charge of freeing it whenever -+ * the second &drm_atomic_commit is done. -+ * -+ * If the first &drm_atomic_commit happens after it, it will consider its -+ * &drm_private_obj the new state and will be likely to access it, resulting in -+ * an access to a freed memory region. Drivers should store (and get a reference -+ * to) the &drm_crtc_commit structure in our private state in -+ * &drm_mode_config_helper_funcs.atomic_commit_setup, and then wait for that -+ * commit to complete as the first step of -+ * &drm_mode_config_helper_funcs.atomic_commit_tail, similar to -+ * drm_atomic_helper_wait_for_dependencies(). - */ - struct drm_private_obj { - /** -diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h -index 85df04c8e62f..dc7e3aef7f13 100644 ---- a/include/drm/drm_atomic_helper.h -+++ b/include/drm/drm_atomic_helper.h -@@ -147,10 +147,6 @@ int drm_atomic_helper_page_flip_target( - uint32_t flags, - uint32_t target, - struct drm_modeset_acquire_ctx *ctx); --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); +diff --git a/include/drm/drm_color_mgmt.h b/include/drm/drm_color_mgmt.h +index 6b5eec10c3db..5810aa8a9d87 100644 +--- a/include/drm/drm_color_mgmt.h ++++ b/include/drm/drm_color_mgmt.h +@@ -94,6 +94,9 @@ int drm_plane_create_color_properties(struct drm_plane *plane, + enum drm_color_encoding default_encoding, + enum drm_color_range default_range); ++int drm_plane_create_chroma_siting_properties(struct drm_plane *plane, ++ int32_t default_chroma_siting_h, int32_t default_chroma_siting_v); ++ /** - * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC + * enum drm_color_lut_tests - hw-specific LUT tests to perform + * diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h -index 928136556174..42cbacd1acb5 100644 +index d304ec8dd06b..5ba62fa5ef54 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h -@@ -1622,6 +1622,10 @@ int drm_connector_attach_scaling_mode_property(struct drm_connector *connector, - u32 scaling_mode_mask); - int drm_connector_attach_vrr_capable_property( - struct drm_connector *connector); -+int drm_connector_attach_colorspace_property(struct drm_connector *connector); -+int drm_connector_attach_hdr_output_metadata_property(struct drm_connector *connector); -+bool drm_connector_atomic_hdr_metadata_equal(struct drm_connector_state *old_state, -+ struct drm_connector_state *new_state); - int drm_mode_create_aspect_ratio_property(struct drm_device *dev); - int drm_mode_create_hdmi_colorspace_property(struct drm_connector *connector); - int drm_mode_create_dp_colorspace_property(struct drm_connector *connector); -diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h -index e97daf6ffbb1..1d0ace87a6e8 100644 ---- a/include/drm/drm_edid.h -+++ b/include/drm/drm_edid.h -@@ -371,8 +371,8 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, - const struct drm_display_mode *mode); - - void --drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, -- const struct drm_connector_state *conn_state); -+drm_hdmi_avi_infoframe_colorimetry(struct hdmi_avi_infoframe *frame, -+ const struct drm_connector_state *conn_state); - - void - drm_hdmi_avi_infoframe_bars(struct hdmi_avi_infoframe *frame, -diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h -index 4efec30f8bad..cbe613858a93 100644 ---- a/include/drm/drm_modeset_helper_vtables.h -+++ b/include/drm/drm_modeset_helper_vtables.h -@@ -336,8 +336,7 @@ struct drm_crtc_helper_funcs { - * - * This function is called in the check phase of an atomic update. The - * driver is not allowed to change anything outside of the free-standing -- * state objects passed-in or assembled in the overall &drm_atomic_state -- * update tracking structure. -+ * state object passed-in. - * - * Also beware that userspace can request its own custom modes, neither - * core nor helpers filter modes to the list of probe modes reported by -@@ -353,7 +352,7 @@ struct drm_crtc_helper_funcs { - * deadlock. - */ - int (*atomic_check)(struct drm_crtc *crtc, -- struct drm_crtc_state *state); -+ struct drm_atomic_state *state); - - /** - * @atomic_begin: -@@ -374,7 +373,7 @@ struct drm_crtc_helper_funcs { - * transitional plane helpers, but it is optional. - */ - void (*atomic_begin)(struct drm_crtc *crtc, -- struct drm_crtc_state *old_crtc_state); -+ struct drm_atomic_state *state); - /** - * @atomic_flush: - * -@@ -398,7 +397,7 @@ struct drm_crtc_helper_funcs { - * transitional plane helpers, but it is optional. - */ - void (*atomic_flush)(struct drm_crtc *crtc, -- struct drm_crtc_state *old_crtc_state); -+ struct drm_atomic_state *state); - - /** - * @atomic_enable: -@@ -417,14 +416,10 @@ struct drm_crtc_helper_funcs { - * @atomic_enable must be the inverse of @atomic_disable for atomic - * drivers. - * -- * Drivers can use the @old_crtc_state input parameter if the operations -- * needed to enable the CRTC don't depend solely on the new state but -- * also on the transition between the old state and the new state. -- * - * This function is optional. - */ - void (*atomic_enable)(struct drm_crtc *crtc, -- struct drm_crtc_state *old_crtc_state); -+ struct drm_atomic_state *state); - - /** - * @atomic_disable: -@@ -441,15 +436,10 @@ struct drm_crtc_helper_funcs { - * need to implement it if there's no need to disable anything at the - * CRTC level. - * -- * Comparing to @disable, this one provides the additional input -- * parameter @old_crtc_state which could be used to access the old -- * state. Atomic drivers should consider to use this one instead -- * of @disable. -- * - * This function is optional. +@@ -201,6 +201,13 @@ enum drm_connector_tv_mode { */ - void (*atomic_disable)(struct drm_crtc *crtc, -- struct drm_crtc_state *old_crtc_state); -+ struct drm_atomic_state *state); + DRM_MODE_TV_MODE_SECAM, ++ /** ++ * @DRM_MODE_TV_MODE_MONOCHROME: Use timings appropriate to ++ * the DRM mode, including equalizing pulses for a 525-line ++ * or 625-line mode, with no pedestal or color encoding. ++ */ ++ DRM_MODE_TV_MODE_MONOCHROME, ++ /** - * @get_scanout_position: -@@ -1054,9 +1044,8 @@ struct drm_connector_helper_funcs { - * NOTE: + * @DRM_MODE_TV_MODE_MAX: Number of analog TV output modes. * - * This function is called in the check phase of an atomic update. The -- * driver is not allowed to change anything outside of the free-standing -- * state objects passed-in or assembled in the overall &drm_atomic_state -- * update tracking structure. -+ * driver is not allowed to change anything outside of the -+ * &drm_atomic_state update tracking structure passed in. - * - * RETURNS: - * -@@ -1066,7 +1055,7 @@ struct drm_connector_helper_funcs { - * for this. +diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h +index c0aec0d4d664..4c44d3ed89b8 100644 +--- a/include/drm/drm_mipi_dsi.h ++++ b/include/drm/drm_mipi_dsi.h +@@ -113,29 +113,43 @@ struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node); + + /* DSI mode flags */ + +-/* video mode */ ++/* Video mode display. ++ * Not set denotes a command mode display. ++ */ + #define MIPI_DSI_MODE_VIDEO BIT(0) +-/* video burst mode */ ++/* Video burst mode. ++ * Link frequency to be configured via platform configuration. ++ * This should always be set in conjunction with MIPI_DSI_MODE_VIDEO. ++ * (DSI spec V1.1 8.11.4) ++ */ + #define MIPI_DSI_MODE_VIDEO_BURST BIT(1) +-/* video pulse mode */ ++/* Video pulse mode. ++ * Not set denotes sync event mode. (DSI spec V1.1 8.11.2) ++ */ + #define MIPI_DSI_MODE_VIDEO_SYNC_PULSE BIT(2) +-/* enable auto vertical count mode */ ++/* Enable auto vertical count mode */ + #define MIPI_DSI_MODE_VIDEO_AUTO_VERT BIT(3) +-/* enable hsync-end packets in vsync-pulse and v-porch area */ ++/* Enable hsync-end packets in vsync-pulse and v-porch area */ + #define MIPI_DSI_MODE_VIDEO_HSE BIT(4) +-/* disable hfront-porch area */ ++/* Transmit NULL packets or LP mode during hfront-porch area. ++ * Not set denotes sending a blanking packet instead. (DSI spec V1.1 8.11.1) ++ */ + #define MIPI_DSI_MODE_VIDEO_NO_HFP BIT(5) +-/* disable hback-porch area */ ++/* Transmit NULL packets or LP mode during hback-porch area. ++ * Not set denotes sending a blanking packet instead. (DSI spec V1.1 8.11.1) ++ */ + #define MIPI_DSI_MODE_VIDEO_NO_HBP BIT(6) +-/* disable hsync-active area */ ++/* Transmit NULL packets or LP mode during hsync-active area. ++ * Not set denotes sending a blanking packet instead. (DSI spec V1.1 8.11.1) ++ */ + #define MIPI_DSI_MODE_VIDEO_NO_HSA BIT(7) +-/* flush display FIFO on vsync pulse */ ++/* Flush display FIFO on vsync pulse */ + #define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8) +-/* disable EoT packets in HS mode */ ++/* Disable EoT packets in HS mode. (DSI spec V1.1 8.1) */ + #define MIPI_DSI_MODE_NO_EOT_PACKET BIT(9) +-/* device supports non-continuous clock behavior (DSI spec 5.6.1) */ ++/* Device supports non-continuous clock behavior (DSI spec V1.1 5.6.1) */ + #define MIPI_DSI_CLOCK_NON_CONTINUOUS BIT(10) +-/* transmit data in low power */ ++/* Transmit data in low power */ + #define MIPI_DSI_MODE_LPM BIT(11) + /* transmit data ending at the same time for all lanes within one hsync */ + #define MIPI_DSI_HS_PKT_END_ALIGNED BIT(12) +diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h +index 882a8a2aceba..744947bbeeb7 100644 +--- a/include/drm/drm_plane.h ++++ b/include/drm/drm_plane.h +@@ -178,6 +178,24 @@ struct drm_plane_state { */ - struct drm_encoder *(*atomic_best_encoder)(struct drm_connector *connector, -- struct drm_connector_state *connector_state); -+ struct drm_atomic_state *state); + enum drm_color_range color_range; ++ /** ++ * @chroma_siting_h: ++ * ++ * Location of chroma samples horizontally compared to luma ++ * 0 means chroma is sited with left luma ++ * 0x8000 is interstitial. 0x10000 is sited with right luma ++ */ ++ int32_t chroma_siting_h; ++ ++ /** ++ * @chroma_siting_v: ++ * ++ * Location of chroma samples vertically compared to luma ++ * 0 means chroma is sited with top luma ++ * 0x8000 is interstitial. 0x10000 is sited with bottom luma ++ */ ++ int32_t chroma_siting_v; ++ /** - * @atomic_check: -@@ -1107,15 +1096,15 @@ struct drm_connector_helper_funcs { - * - * This hook is to be used by drivers implementing writeback connectors - * that need a point when to commit the writeback job to the hardware. -- * The writeback_job to commit is available in -- * &drm_connector_state.writeback_job. -+ * The writeback_job to commit is available in the new connector state, -+ * in &drm_connector_state.writeback_job. - * - * This hook is optional. + * @fb_damage_clips: * - * This callback is used by the atomic modeset helpers. +@@ -763,6 +781,25 @@ struct drm_plane { + * scaling. */ - void (*atomic_commit)(struct drm_connector *connector, -- struct drm_connector_state *state); -+ struct drm_atomic_state *state); - - /** - * @prepare_writeback_job: -@@ -1406,6 +1395,27 @@ struct drm_mode_config_helper_funcs { - * drm_atomic_helper_commit_tail(). - */ - void (*atomic_commit_tail)(struct drm_atomic_state *state); + struct drm_property *scaling_filter_property; + + /** -+ * @atomic_commit_setup: -+ * -+ * This hook is used by the default atomic_commit() hook implemented in -+ * drm_atomic_helper_commit() together with the nonblocking helpers (see -+ * drm_atomic_helper_setup_commit()) to extend the DRM commit setup. It -+ * is not used by the atomic helpers. ++ * @chroma_siting_h_property: + * -+ * This function is called at the end of -+ * drm_atomic_helper_setup_commit(), so once the commit has been -+ * properly setup across the generic DRM object states. It allows -+ * drivers to do some additional commit tracking that isn't related to a -+ * CRTC, plane or connector, tracked in a &drm_private_obj structure. -+ * -+ * Note that the documentation of &drm_private_obj has more details on -+ * how one should implement this. -+ * -+ * This hook is optional. ++ * Optional "CHROMA_SITING_H" property for specifying ++ * chroma siting for YUV formats. ++ * See drm_plane_create_chroma_siting_properties(). + */ -+ int (*atomic_commit_setup)(struct drm_atomic_state *state); - }; - - #endif -diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h -index 33605c3f0eba..878256905791 100644 ---- a/include/drm/drm_panel.h -+++ b/include/drm/drm_panel.h -@@ -165,6 +165,14 @@ struct drm_panel { - */ - int connector_type; - ++ struct drm_property *chroma_siting_h_property; ++ + /** -+ * @orientation: ++ * @chroma_siting_v_property: + * -+ * Panel orientation at initialisation. This is used to initialise the -+ * drm_connector property for panel orientation. ++ * Optional "CHROMA_SITING_V" property for specifying ++ * chroma siting for YUV formats. ++ * See drm_plane_create_chroma_siting_properties(). + */ -+ enum drm_panel_orientation orientation; ++ struct drm_property *chroma_siting_v_property; + - /** - * @list: - * -diff --git a/include/drm/drm_probe_helper.h b/include/drm/drm_probe_helper.h -index 8d3ed2834d34..04c57564c397 100644 ---- a/include/drm/drm_probe_helper.h -+++ b/include/drm/drm_probe_helper.h -@@ -18,6 +18,7 @@ int drm_helper_probe_detect(struct drm_connector *connector, - void drm_kms_helper_poll_init(struct drm_device *dev); - void drm_kms_helper_poll_fini(struct drm_device *dev); - bool drm_helper_hpd_irq_event(struct drm_device *dev); -+bool drm_connector_helper_hpd_irq_event(struct drm_connector *connector); - void drm_kms_helper_hotplug_event(struct drm_device *dev); - - void drm_kms_helper_poll_disable(struct drm_device *dev); -diff --git a/include/drm/gud.h b/include/drm/gud.h + KABI_RESERVE(1) + KABI_RESERVE(2) + KABI_RESERVE(3) +diff --git a/include/dt-bindings/clock/rp1.h b/include/dt-bindings/clock/rp1.h new file mode 100644 -index 000000000000..0b46b54fe56e +index 000000000000..27cbb6e130da --- /dev/null -+++ b/include/drm/gud.h -@@ -0,0 +1,333 @@ -+/* SPDX-License-Identifier: MIT */ -+/* -+ * Copyright 2020 Noralf Trønnes -+ */ -+ -+#ifndef __LINUX_GUD_H -+#define __LINUX_GUD_H -+ -+#include <linux/types.h> -+ -+/* -+ * struct gud_display_descriptor_req - Display descriptor -+ * @magic: Magic value GUD_DISPLAY_MAGIC -+ * @version: Protocol version -+ * @flags: Flags -+ * - STATUS_ON_SET: Always do a status request after a SET request. -+ * This is used by the Linux gadget driver since it has -+ * no way to control the status stage of a control OUT -+ * request that has a payload. -+ * - FULL_UPDATE: Always send the entire framebuffer when flushing changes. -+ * The GUD_REQ_SET_BUFFER request will not be sent -+ * before each bulk transfer, it will only be sent if the -+ * previous bulk transfer had failed. This gives the device -+ * a chance to reset its state machine if needed. -+ * This flag can not be used in combination with compression. -+ * @compression: Supported compression types -+ * - GUD_COMPRESSION_LZ4: LZ4 lossless compression. -+ * @max_buffer_size: Maximum buffer size the device can handle (optional). -+ * This is useful for devices that don't have a big enough -+ * buffer to decompress the entire framebuffer in one go. -+ * @min_width: Minimum pixel width the controller can handle -+ * @max_width: Maximum width -+ * @min_height: Minimum height -+ * @max_height: Maximum height -+ * -+ * Devices that have only one display mode will have min_width == max_width -+ * and min_height == max_height. -+ */ -+struct gud_display_descriptor_req { -+ __le32 magic; -+#define GUD_DISPLAY_MAGIC 0x1d50614d -+ __u8 version; -+ __le32 flags; -+#define GUD_DISPLAY_FLAG_STATUS_ON_SET BIT(0) -+#define GUD_DISPLAY_FLAG_FULL_UPDATE BIT(1) -+ __u8 compression; -+#define GUD_COMPRESSION_LZ4 BIT(0) -+ __le32 max_buffer_size; -+ __le32 min_width; -+ __le32 max_width; -+ __le32 min_height; -+ __le32 max_height; -+} __packed; -+ -+/* -+ * struct gud_property_req - Property -+ * @prop: Property -+ * @val: Value -+ */ -+struct gud_property_req { -+ __le16 prop; -+ __le64 val; -+} __packed; -+ -+/* -+ * struct gud_display_mode_req - Display mode -+ * @clock: Pixel clock in kHz -+ * @hdisplay: Horizontal display size -+ * @hsync_start: Horizontal sync start -+ * @hsync_end: Horizontal sync end -+ * @htotal: Horizontal total size -+ * @vdisplay: Vertical display size -+ * @vsync_start: Vertical sync start -+ * @vsync_end: Vertical sync end -+ * @vtotal: Vertical total size -+ * @flags: Bits 0-13 are the same as in the RandR protocol and also what DRM uses. -+ * The deprecated bits are reused for internal protocol flags leaving us -+ * free to follow DRM for the other bits in the future. -+ * - FLAG_PREFERRED: Set on the preferred display mode. -+ */ -+struct gud_display_mode_req { -+ __le32 clock; -+ __le16 hdisplay; -+ __le16 hsync_start; -+ __le16 hsync_end; -+ __le16 htotal; -+ __le16 vdisplay; -+ __le16 vsync_start; -+ __le16 vsync_end; -+ __le16 vtotal; -+ __le32 flags; -+#define GUD_DISPLAY_MODE_FLAG_PHSYNC BIT(0) -+#define GUD_DISPLAY_MODE_FLAG_NHSYNC BIT(1) -+#define GUD_DISPLAY_MODE_FLAG_PVSYNC BIT(2) -+#define GUD_DISPLAY_MODE_FLAG_NVSYNC BIT(3) -+#define GUD_DISPLAY_MODE_FLAG_INTERLACE BIT(4) -+#define GUD_DISPLAY_MODE_FLAG_DBLSCAN BIT(5) -+#define GUD_DISPLAY_MODE_FLAG_CSYNC BIT(6) -+#define GUD_DISPLAY_MODE_FLAG_PCSYNC BIT(7) -+#define GUD_DISPLAY_MODE_FLAG_NCSYNC BIT(8) -+#define GUD_DISPLAY_MODE_FLAG_HSKEW BIT(9) -+/* BCast and PixelMultiplex are deprecated */ -+#define GUD_DISPLAY_MODE_FLAG_DBLCLK BIT(12) -+#define GUD_DISPLAY_MODE_FLAG_CLKDIV2 BIT(13) -+#define GUD_DISPLAY_MODE_FLAG_USER_MASK \ -+ (GUD_DISPLAY_MODE_FLAG_PHSYNC | GUD_DISPLAY_MODE_FLAG_NHSYNC | \ -+ GUD_DISPLAY_MODE_FLAG_PVSYNC | GUD_DISPLAY_MODE_FLAG_NVSYNC | \ -+ GUD_DISPLAY_MODE_FLAG_INTERLACE | GUD_DISPLAY_MODE_FLAG_DBLSCAN | \ -+ GUD_DISPLAY_MODE_FLAG_CSYNC | GUD_DISPLAY_MODE_FLAG_PCSYNC | \ -+ GUD_DISPLAY_MODE_FLAG_NCSYNC | GUD_DISPLAY_MODE_FLAG_HSKEW | \ -+ GUD_DISPLAY_MODE_FLAG_DBLCLK | GUD_DISPLAY_MODE_FLAG_CLKDIV2) -+/* Internal protocol flags */ -+#define GUD_DISPLAY_MODE_FLAG_PREFERRED BIT(10) -+} __packed; -+ -+/* -+ * struct gud_connector_descriptor_req - Connector descriptor -+ * @connector_type: Connector type (GUD_CONNECTOR_TYPE_*). -+ * If the host doesn't support the type it should fall back to PANEL. -+ * @flags: Flags -+ * - POLL_STATUS: Connector status can change (polled every 10 seconds) -+ * - INTERLACE: Interlaced modes are supported -+ * - DOUBLESCAN: Doublescan modes are supported -+ */ -+struct gud_connector_descriptor_req { -+ __u8 connector_type; -+#define GUD_CONNECTOR_TYPE_PANEL 0 -+#define GUD_CONNECTOR_TYPE_VGA 1 -+#define GUD_CONNECTOR_TYPE_COMPOSITE 2 -+#define GUD_CONNECTOR_TYPE_SVIDEO 3 -+#define GUD_CONNECTOR_TYPE_COMPONENT 4 -+#define GUD_CONNECTOR_TYPE_DVI 5 -+#define GUD_CONNECTOR_TYPE_DISPLAYPORT 6 -+#define GUD_CONNECTOR_TYPE_HDMI 7 -+ __le32 flags; -+#define GUD_CONNECTOR_FLAGS_POLL_STATUS BIT(0) -+#define GUD_CONNECTOR_FLAGS_INTERLACE BIT(1) -+#define GUD_CONNECTOR_FLAGS_DOUBLESCAN BIT(2) -+} __packed; -+ -+/* -+ * struct gud_set_buffer_req - Set buffer transfer info -+ * @x: X position of rectangle -+ * @y: Y position -+ * @width: Pixel width of rectangle -+ * @height: Pixel height -+ * @length: Buffer length in bytes -+ * @compression: Transfer compression -+ * @compressed_length: Compressed buffer length -+ * -+ * This request is issued right before the bulk transfer. -+ * @x, @y, @width and @height specifies the rectangle where the buffer should be -+ * placed inside the framebuffer. -+ */ -+struct gud_set_buffer_req { -+ __le32 x; -+ __le32 y; -+ __le32 width; -+ __le32 height; -+ __le32 length; -+ __u8 compression; -+ __le32 compressed_length; -+} __packed; -+ -+/* -+ * struct gud_state_req - Display state -+ * @mode: Display mode -+ * @format: Pixel format GUD_PIXEL_FORMAT_* -+ * @connector: Connector index -+ * @properties: Array of properties -+ * -+ * The entire state is transferred each time there's a change. -+ */ -+struct gud_state_req { -+ struct gud_display_mode_req mode; -+ __u8 format; -+ __u8 connector; -+ struct gud_property_req properties; -+} __packed; -+ -+/* List of supported connector properties: */ -+ -+/* Margins in pixels to deal with overscan, range 0-100 */ -+#define GUD_PROPERTY_TV_LEFT_MARGIN 1 -+#define GUD_PROPERTY_TV_RIGHT_MARGIN 2 -+#define GUD_PROPERTY_TV_TOP_MARGIN 3 -+#define GUD_PROPERTY_TV_BOTTOM_MARGIN 4 -+#define GUD_PROPERTY_TV_MODE 5 -+/* Brightness in percent, range 0-100 */ -+#define GUD_PROPERTY_TV_BRIGHTNESS 6 -+/* Contrast in percent, range 0-100 */ -+#define GUD_PROPERTY_TV_CONTRAST 7 -+/* Flicker reduction in percent, range 0-100 */ -+#define GUD_PROPERTY_TV_FLICKER_REDUCTION 8 -+/* Overscan in percent, range 0-100 */ -+#define GUD_PROPERTY_TV_OVERSCAN 9 -+/* Saturation in percent, range 0-100 */ -+#define GUD_PROPERTY_TV_SATURATION 10 -+/* Hue in percent, range 0-100 */ -+#define GUD_PROPERTY_TV_HUE 11 -+ -+/* -+ * Backlight brightness is in the range 0-100 inclusive. The value represents the human perceptual -+ * brightness and not a linear PWM value. 0 is minimum brightness which should not turn the -+ * backlight completely off. The DPMS connector property should be used to control power which will -+ * trigger a GUD_REQ_SET_DISPLAY_ENABLE request. -+ * -+ * This does not map to a DRM property, it is used with the backlight device. -+ */ -+#define GUD_PROPERTY_BACKLIGHT_BRIGHTNESS 12 -+ -+/* List of supported properties that are not connector propeties: */ -+ -+/* -+ * Plane rotation. Should return the supported bitmask on -+ * GUD_REQ_GET_PROPERTIES. GUD_ROTATION_0 is mandatory. -+ * -+ * Note: This is not display rotation so 90/270 will need scaling to make it fit (unless squared). -+ */ -+#define GUD_PROPERTY_ROTATION 50 -+ #define GUD_ROTATION_0 BIT(0) -+ #define GUD_ROTATION_90 BIT(1) -+ #define GUD_ROTATION_180 BIT(2) -+ #define GUD_ROTATION_270 BIT(3) -+ #define GUD_ROTATION_REFLECT_X BIT(4) -+ #define GUD_ROTATION_REFLECT_Y BIT(5) -+ #define GUD_ROTATION_MASK (GUD_ROTATION_0 | GUD_ROTATION_90 | \ -+ GUD_ROTATION_180 | GUD_ROTATION_270 | \ -+ GUD_ROTATION_REFLECT_X | GUD_ROTATION_REFLECT_Y) -+ -+/* USB Control requests: */ -+ -+/* Get status from the last GET/SET control request. Value is u8. */ -+#define GUD_REQ_GET_STATUS 0x00 -+ /* Status values: */ -+ #define GUD_STATUS_OK 0x00 -+ #define GUD_STATUS_BUSY 0x01 -+ #define GUD_STATUS_REQUEST_NOT_SUPPORTED 0x02 -+ #define GUD_STATUS_PROTOCOL_ERROR 0x03 -+ #define GUD_STATUS_INVALID_PARAMETER 0x04 -+ #define GUD_STATUS_ERROR 0x05 -+ -+/* Get display descriptor as a &gud_display_descriptor_req */ -+#define GUD_REQ_GET_DESCRIPTOR 0x01 -+ -+/* Get supported pixel formats as a byte array of GUD_PIXEL_FORMAT_* */ -+#define GUD_REQ_GET_FORMATS 0x40 -+ #define GUD_FORMATS_MAX_NUM 32 -+ /* R1 is a 1-bit monochrome transfer format presented to userspace as XRGB8888 */ -+ #define GUD_PIXEL_FORMAT_R1 0x01 -+ #define GUD_PIXEL_FORMAT_XRGB1111 0x20 -+ #define GUD_PIXEL_FORMAT_RGB565 0x40 -+ #define GUD_PIXEL_FORMAT_XRGB8888 0x80 -+ #define GUD_PIXEL_FORMAT_ARGB8888 0x81 -+ -+/* -+ * Get supported properties that are not connector propeties as a &gud_property_req array. -+ * gud_property_req.val often contains the initial value for the property. -+ */ -+#define GUD_REQ_GET_PROPERTIES 0x41 -+ #define GUD_PROPERTIES_MAX_NUM 32 -+ -+/* Connector requests have the connector index passed in the wValue field */ -+ -+/* Get connector descriptors as an array of &gud_connector_descriptor_req */ -+#define GUD_REQ_GET_CONNECTORS 0x50 -+ #define GUD_CONNECTORS_MAX_NUM 32 -+ -+/* -+ * Get properties supported by the connector as a &gud_property_req array. -+ * gud_property_req.val often contains the initial value for the property. -+ */ -+#define GUD_REQ_GET_CONNECTOR_PROPERTIES 0x51 -+ #define GUD_CONNECTOR_PROPERTIES_MAX_NUM 32 -+ -+/* -+ * Issued when there's a TV_MODE property present. -+ * Gets an array of the supported TV_MODE names each entry of length -+ * GUD_CONNECTOR_TV_MODE_NAME_LEN. Names must be NUL-terminated. -+ */ -+#define GUD_REQ_GET_CONNECTOR_TV_MODE_VALUES 0x52 -+ #define GUD_CONNECTOR_TV_MODE_NAME_LEN 16 -+ #define GUD_CONNECTOR_TV_MODE_MAX_NUM 16 -+ -+/* When userspace checks connector status, this is issued first, not used for poll requests. */ -+#define GUD_REQ_SET_CONNECTOR_FORCE_DETECT 0x53 -+ -+/* -+ * Get connector status. Value is u8. -+ * -+ * Userspace will get a HOTPLUG uevent if one of the following is true: -+ * - Connection status has changed since last -+ * - CHANGED is set -+ */ -+#define GUD_REQ_GET_CONNECTOR_STATUS 0x54 -+ #define GUD_CONNECTOR_STATUS_DISCONNECTED 0x00 -+ #define GUD_CONNECTOR_STATUS_CONNECTED 0x01 -+ #define GUD_CONNECTOR_STATUS_UNKNOWN 0x02 -+ #define GUD_CONNECTOR_STATUS_CONNECTED_MASK 0x03 -+ #define GUD_CONNECTOR_STATUS_CHANGED BIT(7) -+ ++++ b/include/dt-bindings/clock/rp1.h +@@ -0,0 +1,56 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Display modes can be fetched as either EDID data or an array of &gud_display_mode_req. -+ * -+ * If GUD_REQ_GET_CONNECTOR_MODES returns zero, EDID is used to create display modes. -+ * If both display modes and EDID are returned, EDID is just passed on to userspace -+ * in the EDID connector property. ++ * Copyright (C) 2021 Raspberry Pi Ltd. + */ + -+/* Get &gud_display_mode_req array of supported display modes */ -+#define GUD_REQ_GET_CONNECTOR_MODES 0x55 -+ #define GUD_CONNECTOR_MAX_NUM_MODES 128 -+ -+/* Get Extended Display Identification Data */ -+#define GUD_REQ_GET_CONNECTOR_EDID 0x56 -+ #define GUD_CONNECTOR_MAX_EDID_LEN 2048 -+ -+/* Set buffer properties before bulk transfer as &gud_set_buffer_req */ -+#define GUD_REQ_SET_BUFFER 0x60 -+ -+/* Check display configuration as &gud_state_req */ -+#define GUD_REQ_SET_STATE_CHECK 0x61 -+ -+/* Apply the previous STATE_CHECK configuration */ -+#define GUD_REQ_SET_STATE_COMMIT 0x62 -+ -+/* Enable/disable the display controller, value is u8: 0/1 */ -+#define GUD_REQ_SET_CONTROLLER_ENABLE 0x63 -+ -+/* Enable/disable display/output (DPMS), value is u8: 0/1 */ -+#define GUD_REQ_SET_DISPLAY_ENABLE 0x64 -+ -+#endif ++#define RP1_PLL_SYS_CORE 0 ++#define RP1_PLL_AUDIO_CORE 1 ++#define RP1_PLL_VIDEO_CORE 2 ++ ++#define RP1_PLL_SYS 3 ++#define RP1_PLL_AUDIO 4 ++#define RP1_PLL_VIDEO 5 ++ ++#define RP1_PLL_SYS_PRI_PH 6 ++#define RP1_PLL_SYS_SEC_PH 7 ++#define RP1_PLL_AUDIO_PRI_PH 8 ++ ++#define RP1_PLL_SYS_SEC 9 ++#define RP1_PLL_AUDIO_SEC 10 ++#define RP1_PLL_VIDEO_SEC 11 ++ ++#define RP1_CLK_SYS 12 ++#define RP1_CLK_SLOW_SYS 13 ++#define RP1_CLK_DMA 14 ++#define RP1_CLK_UART 15 ++#define RP1_CLK_ETH 16 ++#define RP1_CLK_PWM0 17 ++#define RP1_CLK_PWM1 18 ++#define RP1_CLK_AUDIO_IN 19 ++#define RP1_CLK_AUDIO_OUT 20 ++#define RP1_CLK_I2S 21 ++#define RP1_CLK_MIPI0_CFG 22 ++#define RP1_CLK_MIPI1_CFG 23 ++#define RP1_CLK_PCIE_AUX 24 ++#define RP1_CLK_USBH0_MICROFRAME 25 ++#define RP1_CLK_USBH1_MICROFRAME 26 ++#define RP1_CLK_USBH0_SUSPEND 27 ++#define RP1_CLK_USBH1_SUSPEND 28 ++#define RP1_CLK_ETH_TSU 29 ++#define RP1_CLK_ADC 30 ++#define RP1_CLK_SDIO_TIMER 31 ++#define RP1_CLK_SDIO_ALT_SRC 32 ++#define RP1_CLK_GP0 33 ++#define RP1_CLK_GP1 34 ++#define RP1_CLK_GP2 35 ++#define RP1_CLK_GP3 36 ++#define RP1_CLK_GP4 37 ++#define RP1_CLK_GP5 38 ++#define RP1_CLK_VEC 39 ++#define RP1_CLK_DPI 40 ++#define RP1_CLK_MIPI0_DPI 41 ++#define RP1_CLK_MIPI1_DPI 42 ++ ++/* Extra PLL output channels - RP1B0 only */ ++#define RP1_PLL_VIDEO_PRI_PH 43 ++#define RP1_PLL_AUDIO_TERN 44 diff --git a/include/dt-bindings/gpio/gpio-fsm.h b/include/dt-bindings/gpio/gpio-fsm.h new file mode 100644 index 000000000000..eb40cfdc71df @@ -181845,11 +236654,252 @@ +#define GF_SW(x) GF_IO(GF_SOFT, (x)) + +#endif +diff --git a/include/dt-bindings/mfd/rp1.h b/include/dt-bindings/mfd/rp1.h +new file mode 100644 +index 000000000000..80bbfd61b270 +--- /dev/null ++++ b/include/dt-bindings/mfd/rp1.h +@@ -0,0 +1,235 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * This header provides constants for the PY MFD. ++ */ ++ ++#ifndef _RP1_H ++#define _RP1_H ++ ++/* Address map */ ++#define RP1_SYSINFO_BASE 0x000000 ++#define RP1_TBMAN_BASE 0x004000 ++#define RP1_SYSCFG_BASE 0x008000 ++#define RP1_OTP_BASE 0x00c000 ++#define RP1_POWER_BASE 0x010000 ++#define RP1_RESETS_BASE 0x014000 ++#define RP1_CLOCKS_BANK_DEFAULT_BASE 0x018000 ++#define RP1_CLOCKS_BANK_VIDEO_BASE 0x01c000 ++#define RP1_PLL_SYS_BASE 0x020000 ++#define RP1_PLL_AUDIO_BASE 0x024000 ++#define RP1_PLL_VIDEO_BASE 0x028000 ++#define RP1_UART0_BASE 0x030000 ++#define RP1_UART1_BASE 0x034000 ++#define RP1_UART2_BASE 0x038000 ++#define RP1_UART3_BASE 0x03c000 ++#define RP1_UART4_BASE 0x040000 ++#define RP1_UART5_BASE 0x044000 ++#define RP1_SPI8_BASE 0x04c000 ++#define RP1_SPI0_BASE 0x050000 ++#define RP1_SPI1_BASE 0x054000 ++#define RP1_SPI2_BASE 0x058000 ++#define RP1_SPI3_BASE 0x05c000 ++#define RP1_SPI4_BASE 0x060000 ++#define RP1_SPI5_BASE 0x064000 ++#define RP1_SPI6_BASE 0x068000 ++#define RP1_SPI7_BASE 0x06c000 ++#define RP1_I2C0_BASE 0x070000 ++#define RP1_I2C1_BASE 0x074000 ++#define RP1_I2C2_BASE 0x078000 ++#define RP1_I2C3_BASE 0x07c000 ++#define RP1_I2C4_BASE 0x080000 ++#define RP1_I2C5_BASE 0x084000 ++#define RP1_I2C6_BASE 0x088000 ++#define RP1_AUDIO_IN_BASE 0x090000 ++#define RP1_AUDIO_OUT_BASE 0x094000 ++#define RP1_PWM0_BASE 0x098000 ++#define RP1_PWM1_BASE 0x09c000 ++#define RP1_I2S0_BASE 0x0a0000 ++#define RP1_I2S1_BASE 0x0a4000 ++#define RP1_I2S2_BASE 0x0a8000 ++#define RP1_TIMER_BASE 0x0ac000 ++#define RP1_SDIO0_APBS_BASE 0x0b0000 ++#define RP1_SDIO1_APBS_BASE 0x0b4000 ++#define RP1_BUSFABRIC_MONITOR_BASE 0x0c0000 ++#define RP1_BUSFABRIC_AXISHIM_BASE 0x0c4000 ++#define RP1_ADC_BASE 0x0c8000 ++#define RP1_IO_BANK0_BASE 0x0d0000 ++#define RP1_IO_BANK1_BASE 0x0d4000 ++#define RP1_IO_BANK2_BASE 0x0d8000 ++#define RP1_SYS_RIO0_BASE 0x0e0000 ++#define RP1_SYS_RIO1_BASE 0x0e4000 ++#define RP1_SYS_RIO2_BASE 0x0e8000 ++#define RP1_PADS_BANK0_BASE 0x0f0000 ++#define RP1_PADS_BANK1_BASE 0x0f4000 ++#define RP1_PADS_BANK2_BASE 0x0f8000 ++#define RP1_PADS_ETH_BASE 0x0fc000 ++#define RP1_ETH_IP_BASE 0x100000 ++#define RP1_ETH_CFG_BASE 0x104000 ++#define RP1_PCIE_APBS_BASE 0x108000 ++#define RP1_MIPI0_CSIDMA_BASE 0x110000 ++#define RP1_MIPI0_CSIHOST_BASE 0x114000 ++#define RP1_MIPI0_DSIDMA_BASE 0x118000 ++#define RP1_MIPI0_DSIHOST_BASE 0x11c000 ++#define RP1_MIPI0_MIPICFG_BASE 0x120000 ++#define RP1_MIPI0_ISP_BASE 0x124000 ++#define RP1_MIPI1_CSIDMA_BASE 0x128000 ++#define RP1_MIPI1_CSIHOST_BASE 0x12c000 ++#define RP1_MIPI1_DSIDMA_BASE 0x130000 ++#define RP1_MIPI1_DSIHOST_BASE 0x134000 ++#define RP1_MIPI1_MIPICFG_BASE 0x138000 ++#define RP1_MIPI1_ISP_BASE 0x13c000 ++#define RP1_VIDEO_OUT_CFG_BASE 0x140000 ++#define RP1_VIDEO_OUT_VEC_BASE 0x144000 ++#define RP1_VIDEO_OUT_DPI_BASE 0x148000 ++#define RP1_XOSC_BASE 0x150000 ++#define RP1_WATCHDOG_BASE 0x154000 ++#define RP1_DMA_TICK_BASE 0x158000 ++#define RP1_SDIO_CLOCKS_BASE 0x15c000 ++#define RP1_USBHOST0_APBS_BASE 0x160000 ++#define RP1_USBHOST1_APBS_BASE 0x164000 ++#define RP1_ROSC0_BASE 0x168000 ++#define RP1_ROSC1_BASE 0x16c000 ++#define RP1_VBUSCTRL_BASE 0x170000 ++#define RP1_TICKS_BASE 0x174000 ++#define RP1_PIO_APBS_BASE 0x178000 ++#define RP1_SDIO0_AHBLS_BASE 0x180000 ++#define RP1_SDIO1_AHBLS_BASE 0x184000 ++#define RP1_DMA_BASE 0x188000 ++#define RP1_RAM_BASE 0x1c0000 ++#define RP1_RAM_SIZE 0x020000 ++#define RP1_USBHOST0_AXIS_BASE 0x200000 ++#define RP1_USBHOST1_AXIS_BASE 0x300000 ++#define RP1_EXAC_BASE 0x400000 ++ ++/* Interrupts */ ++ ++#define RP1_INT_IO_BANK0 0 ++#define RP1_INT_IO_BANK1 1 ++#define RP1_INT_IO_BANK2 2 ++#define RP1_INT_AUDIO_IN 3 ++#define RP1_INT_AUDIO_OUT 4 ++#define RP1_INT_PWM0 5 ++#define RP1_INT_ETH 6 ++#define RP1_INT_I2C0 7 ++#define RP1_INT_I2C1 8 ++#define RP1_INT_I2C2 9 ++#define RP1_INT_I2C3 10 ++#define RP1_INT_I2C4 11 ++#define RP1_INT_I2C5 12 ++#define RP1_INT_I2C6 13 ++#define RP1_INT_I2S0 14 ++#define RP1_INT_I2S1 15 ++#define RP1_INT_I2S2 16 ++#define RP1_INT_SDIO0 17 ++#define RP1_INT_SDIO1 18 ++#define RP1_INT_SPI0 19 ++#define RP1_INT_SPI1 20 ++#define RP1_INT_SPI2 21 ++#define RP1_INT_SPI3 22 ++#define RP1_INT_SPI4 23 ++#define RP1_INT_SPI5 24 ++#define RP1_INT_UART0 25 ++#define RP1_INT_TIMER_0 26 ++#define RP1_INT_TIMER_1 27 ++#define RP1_INT_TIMER_2 28 ++#define RP1_INT_TIMER_3 29 ++#define RP1_INT_USBHOST0 30 ++#define RP1_INT_USBHOST0_0 31 ++#define RP1_INT_USBHOST0_1 32 ++#define RP1_INT_USBHOST0_2 33 ++#define RP1_INT_USBHOST0_3 34 ++#define RP1_INT_USBHOST1 35 ++#define RP1_INT_USBHOST1_0 36 ++#define RP1_INT_USBHOST1_1 37 ++#define RP1_INT_USBHOST1_2 38 ++#define RP1_INT_USBHOST1_3 39 ++#define RP1_INT_DMA 40 ++#define RP1_INT_PWM1 41 ++#define RP1_INT_UART1 42 ++#define RP1_INT_UART2 43 ++#define RP1_INT_UART3 44 ++#define RP1_INT_UART4 45 ++#define RP1_INT_UART5 46 ++#define RP1_INT_MIPI0 47 ++#define RP1_INT_MIPI1 48 ++#define RP1_INT_VIDEO_OUT 49 ++#define RP1_INT_PIO_0 50 ++#define RP1_INT_PIO_1 51 ++#define RP1_INT_ADC_FIFO 52 ++#define RP1_INT_PCIE_OUT 53 ++#define RP1_INT_SPI6 54 ++#define RP1_INT_SPI7 55 ++#define RP1_INT_SPI8 56 ++#define RP1_INT_SYSCFG 58 ++#define RP1_INT_CLOCKS_DEFAULT 59 ++#define RP1_INT_VBUSCTRL 60 ++#define RP1_INT_PROC_MISC 57 ++#define RP1_INT_END 61 ++ ++/* DMA peripherals (for pacing) */ ++#define RP1_DMA_I2C0_RX 0x0 ++#define RP1_DMA_I2C0_TX 0x1 ++#define RP1_DMA_I2C1_RX 0x2 ++#define RP1_DMA_I2C1_TX 0x3 ++#define RP1_DMA_I2C2_RX 0x4 ++#define RP1_DMA_I2C2_TX 0x5 ++#define RP1_DMA_I2C3_RX 0x6 ++#define RP1_DMA_I2C3_TX 0x7 ++#define RP1_DMA_I2C4_RX 0x8 ++#define RP1_DMA_I2C4_TX 0x9 ++#define RP1_DMA_I2C5_RX 0xa ++#define RP1_DMA_I2C5_TX 0xb ++#define RP1_DMA_SPI0_RX 0xc ++#define RP1_DMA_SPI0_TX 0xd ++#define RP1_DMA_SPI1_RX 0xe ++#define RP1_DMA_SPI1_TX 0xf ++#define RP1_DMA_SPI2_RX 0x10 ++#define RP1_DMA_SPI2_TX 0x11 ++#define RP1_DMA_SPI3_RX 0x12 ++#define RP1_DMA_SPI3_TX 0x13 ++#define RP1_DMA_SPI4_RX 0x14 ++#define RP1_DMA_SPI4_TX 0x15 ++#define RP1_DMA_SPI5_RX 0x16 ++#define RP1_DMA_SPI5_TX 0x17 ++#define RP1_DMA_PWM0 0x18 ++#define RP1_DMA_UART0_RX 0x19 ++#define RP1_DMA_UART0_TX 0x1a ++#define RP1_DMA_AUDIO_IN_CH0 0x1b ++#define RP1_DMA_AUDIO_IN_CH1 0x1c ++#define RP1_DMA_AUDIO_OUT 0x1d ++#define RP1_DMA_PWM1 0x1e ++#define RP1_DMA_I2S0_RX 0x1f ++#define RP1_DMA_I2S0_TX 0x20 ++#define RP1_DMA_I2S1_RX 0x21 ++#define RP1_DMA_I2S1_TX 0x22 ++#define RP1_DMA_I2S2_RX 0x23 ++#define RP1_DMA_I2S2_TX 0x24 ++#define RP1_DMA_UART1_RX 0x25 ++#define RP1_DMA_UART1_TX 0x26 ++#define RP1_DMA_UART2_RX 0x27 ++#define RP1_DMA_UART2_TX 0x28 ++#define RP1_DMA_UART3_RX 0x29 ++#define RP1_DMA_UART3_TX 0x2a ++#define RP1_DMA_UART4_RX 0x2b ++#define RP1_DMA_UART4_TX 0x2c ++#define RP1_DMA_UART5_RX 0x2d ++#define RP1_DMA_UART5_TX 0x2e ++#define RP1_DMA_ADC 0x2f ++#define RP1_DMA_DMA_TICK_TICK0 0x30 ++#define RP1_DMA_DMA_TICK_TICK1 0x31 ++#define RP1_DMA_SPI6_RX 0x32 ++#define RP1_DMA_SPI6_TX 0x33 ++#define RP1_DMA_SPI7_RX 0x34 ++#define RP1_DMA_SPI7_TX 0x35 ++#define RP1_DMA_SPI8_RX 0x36 ++#define RP1_DMA_SPI8_TX 0x37 ++#define RP1_DMA_PIO_CH0_TX 0x38 ++#define RP1_DMA_PIO_CH0_RX 0x39 ++#define RP1_DMA_PIO_CH1_TX 0x3a ++#define RP1_DMA_PIO_CH1_RX 0x3b ++#define RP1_DMA_PIO_CH2_TX 0x3c ++#define RP1_DMA_PIO_CH2_RX 0x3d ++#define RP1_DMA_PIO_CH3_TX 0x3e ++#define RP1_DMA_PIO_CH3_RX 0x3f ++ ++#endif diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h -index 54665952d6ad..92948c26da2a 100644 +index c55810a43541..c5e6adc35cc9 100644 --- a/include/linux/brcmphy.h +++ b/include/linux/brcmphy.h -@@ -22,6 +22,7 @@ +@@ -23,6 +23,7 @@ #define PHY_ID_BCM5411 0x00206070 #define PHY_ID_BCM5421 0x002060e0 #define PHY_ID_BCM54210E 0x600d84a0 @@ -182299,46 +237349,70 @@ +#endif + +#endif /* _VC_MEM_H */ -diff --git a/include/linux/clk.h b/include/linux/clk.h -index 7fd6a1febcf4..ab53a0873c8d 100644 ---- a/include/linux/clk.h -+++ b/include/linux/clk.h -@@ -15,6 +15,7 @@ - - struct device; - struct clk; -+struct clk_request; - struct device_node; - struct of_phandle_args; - -@@ -743,6 +744,9 @@ int clk_save_context(void); - */ - void clk_restore_context(void); - -+struct clk_request *clk_request_start(struct clk *clk, unsigned long rate); -+void clk_request_done(struct clk_request *req); -+ - #else /* !CONFIG_HAVE_CLK */ - - static inline struct clk *clk_get(struct device *dev, const char *id) -diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h -index 9850d59d6f1c..c8ec982ff498 100644 ---- a/include/linux/hdmi.h -+++ b/include/linux/hdmi.h -@@ -156,7 +156,7 @@ enum hdmi_content_type { - }; - - enum hdmi_metadata_type { -- HDMI_STATIC_METADATA_TYPE1 = 1, -+ HDMI_STATIC_METADATA_TYPE1 = 0, - }; - - enum hdmi_eotf { +diff --git a/include/linux/fb.h b/include/linux/fb.h +index ab2a9f4163c7..703dd9cd4bd2 100644 +--- a/include/linux/fb.h ++++ b/include/linux/fb.h +@@ -504,6 +504,7 @@ struct fb_info { + void *par; + + bool skip_vt_switch; /* no VT switch on suspend/resume required */ ++ bool custom_fb_num; /* Use value in node as the preferred node number */ + KABI_RESERVE(1) + KABI_RESERVE(2) + KABI_RESERVE(3) +@@ -596,6 +597,7 @@ extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf, + .fb_imageblit = sys_imageblit + + /* fbmem.c */ ++extern void fb_set_lowest_dynamic_fb(int min_fb_dev); + extern int register_framebuffer(struct fb_info *fb_info); + extern void unregister_framebuffer(struct fb_info *fb_info); + extern int fb_prepare_logo(struct fb_info *fb_info, int rotate); +diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h +index d6e38a500833..70c233440cdf 100644 +--- a/include/linux/gpio/driver.h ++++ b/include/linux/gpio/driver.h +@@ -677,6 +677,7 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev, + #define BGPIOF_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */ + #define BGPIOF_NO_OUTPUT BIT(5) /* only input */ + #define BGPIOF_NO_SET_ON_INPUT BIT(6) ++#define BGPIOF_REG_DIRECT BIT(7) /* ignore shadow registers */ + + int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq); +diff --git a/include/linux/iommu.h b/include/linux/iommu.h +index 98acb1d50bd9..a0804d0f1f5e 100644 +--- a/include/linux/iommu.h ++++ b/include/linux/iommu.h +@@ -693,16 +693,20 @@ struct iommu_domain_ops { + int (*set_dev_pasid)(struct iommu_domain *domain, struct device *dev, + ioasid_t pasid); + ++ int (*map)(struct iommu_domain *domain, unsigned long iova, ++ phys_addr_t paddr, size_t size, int prot, gfp_t gfp); + int (*map_pages)(struct iommu_domain *domain, unsigned long iova, + phys_addr_t paddr, size_t pgsize, size_t pgcount, + int prot, gfp_t gfp, size_t *mapped); ++ size_t (*unmap)(struct iommu_domain *domain, unsigned long iova, ++ size_t size, struct iommu_iotlb_gather *iotlb_gather); + size_t (*unmap_pages)(struct iommu_domain *domain, unsigned long iova, + size_t pgsize, size_t pgcount, + struct iommu_iotlb_gather *iotlb_gather); + + void (*flush_iotlb_all)(struct iommu_domain *domain); +- int (*iotlb_sync_map)(struct iommu_domain *domain, unsigned long iova, +- size_t size); ++ void (*iotlb_sync_map)(struct iommu_domain *domain, unsigned long iova, ++ size_t size); + void (*iotlb_sync)(struct iommu_domain *domain, + struct iommu_iotlb_gather *iotlb_gather); + int (*cache_invalidate_user)(struct iommu_domain *domain, diff --git a/include/linux/leds.h b/include/linux/leds.h -index 6a8d6409c993..aefab0783075 100644 +index aa16dc2a8230..9c7ad6eada2c 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h -@@ -79,6 +79,9 @@ struct led_classdev { +@@ -115,6 +115,9 @@ struct led_classdev { #define LED_BRIGHT_HW_CHANGED BIT(21) #define LED_RETAIN_AT_SHUTDOWN BIT(22) #define LED_INIT_DEFAULT_TRIGGER BIT(23) @@ -182348,18 +237422,6 @@ /* set_brightness_work / blink_timer flags, atomic, private. */ unsigned long work_flags; -diff --git a/include/linux/mfd/bcm2835-pm.h b/include/linux/mfd/bcm2835-pm.h -index ed37dc40e82a..f70a810c55f7 100644 ---- a/include/linux/mfd/bcm2835-pm.h -+++ b/include/linux/mfd/bcm2835-pm.h -@@ -9,6 +9,7 @@ struct bcm2835_pm { - struct device *dev; - void __iomem *base; - void __iomem *asb; -+ void __iomem *rpivid_asb; - }; - - #endif /* BCM2835_MFD_PM_H */ diff --git a/include/linux/mfd/rpisense/core.h b/include/linux/mfd/rpisense/core.h new file mode 100644 index 000000000000..4856aa3c8b06 @@ -182512,18 +237574,68 @@ #define PHY_ARDENNES_MMD_DEV_3_PHY_CFG (0x806A) #define PHY_ARDENNES_MMD_DEV_3_PHY_CFG_ZD_DLY_EN_ (0x2000) diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h -index 42df06c6b19c..e7f45a2b0c72 100644 +index 0fe6576eb81f..155f90ad4ead 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h -@@ -271,6 +271,8 @@ struct mmc_card { - #define MMC_QUIRK_TRIM_BROKEN (1<<12) /* Skip trim */ - #define MMC_QUIRK_BROKEN_HPI (1<<13) /* Disable broken HPI support */ - +@@ -299,6 +299,7 @@ struct mmc_card { + #define MMC_QUIRK_BROKEN_SD_DISCARD (1<<14) /* Disable broken SD discard support */ + #define MMC_QUIRK_BROKEN_SD_CACHE (1<<15) /* Disable broken SD cache support */ + #define MMC_QUIRK_BROKEN_CACHE_FLUSH (1<<16) /* Don't flush cache until the write has occurred */ +#define MMC_QUIRK_ERASE_BROKEN (1<<31) /* Skip erase */ -+ + + bool written_flag; /* Indicates eMMC has been written since power on */ bool reenable_cmdq; /* Re-enable Command Queue */ +@@ -322,6 +323,7 @@ struct mmc_card { + struct sd_switch_caps sw_caps; /* switch (CMD6) caps */ + struct sd_ext_reg ext_power; /* SD extension reg for PM */ + struct sd_ext_reg ext_perf; /* SD extension reg for PERF */ ++ u8 *ext_reg_buf; /* 512 byte block for extension register R/W */ + + unsigned int sdio_funcs; /* number of SDIO functions */ + atomic_t sdio_funcs_probed; /* number of probed SDIO funcs */ +diff --git a/include/linux/mmc/sd.h b/include/linux/mmc/sd.h +index 6727576a8755..52f2c7a90a13 100644 +--- a/include/linux/mmc/sd.h ++++ b/include/linux/mmc/sd.h +@@ -29,6 +29,9 @@ + #define SD_APP_OP_COND 41 /* bcr 31:0 OCR R3 */ + #define SD_APP_SEND_SCR 51 /* adtc R1 */ + ++ /* class 1 */ ++#define SD_CMDQ_TASK_MGMT 43 /* ac See below R1b */ ++ + /* class 11 */ + #define SD_READ_EXTR_SINGLE 48 /* adtc 31:0 R1 */ + #define SD_WRITE_EXTR_SINGLE 49 /* adtc 31:0 R1 */ +@@ -60,6 +63,15 @@ + * 7:0 Check Pattern (0xAA) + */ - unsigned int erase_size; /* erase size in sectors */ ++/* ++ * SD_CMDQ_TASK_MGMT argument format: ++ * ++ * 31:21 Reserved (0) ++ * 20:16 Task ID ++ * 15:4 Reserved (0) ++ * 3:0 Operation - 0x1 = abort all tasks, 0x2 = abort Task ID ++ */ ++ + /* + * SCR field definitions + */ +diff --git a/include/linux/module.h b/include/linux/module.h +index 4db2878d9e42..bf726cea4035 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -513,7 +513,7 @@ struct module { + unsigned int num_bpf_raw_events; + struct bpf_raw_event_map *bpf_raw_events; + #endif +-#ifdef CONFIG_DEBUG_INFO_BTF_MODULES ++#if 1 + unsigned int btf_data_size; + void *btf_data; + #endif diff --git a/include/linux/platform_data/dma-bcm2708.h b/include/linux/platform_data/dma-bcm2708.h new file mode 100644 index 000000000000..6ca874d332a8 @@ -182673,11 +237785,191 @@ +#endif /* CONFIG_DMA_BCM2708 || CONFIG_DMA_BCM2708_MODULE */ + +#endif /* _PLAT_BCM2708_DMA_H */ +diff --git a/include/linux/pwm.h b/include/linux/pwm.h +index fe0f38ce1bde..4bfbd25ade06 100644 +--- a/include/linux/pwm.h ++++ b/include/linux/pwm.h +@@ -95,8 +95,8 @@ struct pwm_device { + * @state: state to fill with the current PWM state + * + * The returned PWM state represents the state that was applied by a previous call to +- * pwm_apply_state(). Drivers may have to slightly tweak that state before programming it to +- * hardware. If pwm_apply_state() was never called, this returns either the current hardware ++ * pwm_apply_might_sleep(). Drivers may have to slightly tweak that state before programming it to ++ * hardware. If pwm_apply_might_sleep() was never called, this returns either the current hardware + * state (if supported) or the default settings. + */ + static inline void pwm_get_state(const struct pwm_device *pwm, +@@ -160,20 +160,20 @@ static inline void pwm_get_args(const struct pwm_device *pwm, + } + + /** +- * pwm_init_state() - prepare a new state to be applied with pwm_apply_state() ++ * pwm_init_state() - prepare a new state to be applied with pwm_apply_might_sleep() + * @pwm: PWM device + * @state: state to fill with the prepared PWM state + * + * This functions prepares a state that can later be tweaked and applied +- * to the PWM device with pwm_apply_state(). This is a convenient function ++ * to the PWM device with pwm_apply_might_sleep(). This is a convenient function + * that first retrieves the current PWM state and the replaces the period + * and polarity fields with the reference values defined in pwm->args. + * Once the function returns, you can adjust the ->enabled and ->duty_cycle +- * fields according to your needs before calling pwm_apply_state(). ++ * fields according to your needs before calling pwm_apply_might_sleep(). + * + * ->duty_cycle is initially set to zero to avoid cases where the current + * ->duty_cycle value exceed the pwm_args->period one, which would trigger +- * an error if the user calls pwm_apply_state() without adjusting ->duty_cycle ++ * an error if the user calls pwm_apply_might_sleep() without adjusting ->duty_cycle + * first. + */ + static inline void pwm_init_state(const struct pwm_device *pwm, +@@ -229,7 +229,7 @@ pwm_get_relative_duty_cycle(const struct pwm_state *state, unsigned int scale) + * + * pwm_init_state(pwm, &state); + * pwm_set_relative_duty_cycle(&state, 50, 100); +- * pwm_apply_state(pwm, &state); ++ * pwm_apply_might_sleep(pwm, &state); + * + * This functions returns -EINVAL if @duty_cycle and/or @scale are + * inconsistent (@scale == 0 or @duty_cycle > @scale). +@@ -289,6 +289,7 @@ struct pwm_ops { + * @npwm: number of PWMs controlled by this chip + * @of_xlate: request a PWM device given a device tree PWM specifier + * @of_pwm_n_cells: number of cells expected in the device tree PWM specifier ++ * @atomic: can the driver's ->apply() be called in atomic context + * @list: list node for internal use + * @pwms: array of PWM devices allocated by the framework + */ +@@ -301,6 +302,7 @@ struct pwm_chip { + struct pwm_device * (*of_xlate)(struct pwm_chip *chip, + const struct of_phandle_args *args); + unsigned int of_pwm_n_cells; ++ bool atomic; + + /* only used internally by the PWM framework */ + struct list_head list; +@@ -309,7 +311,8 @@ struct pwm_chip { + + #if IS_ENABLED(CONFIG_PWM) + /* PWM user APIs */ +-int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state); ++int pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state); ++int pwm_apply_atomic(struct pwm_device *pwm, const struct pwm_state *state); + int pwm_adjust_config(struct pwm_device *pwm); + + /** +@@ -337,7 +340,7 @@ static inline int pwm_config(struct pwm_device *pwm, int duty_ns, + + state.duty_cycle = duty_ns; + state.period = period_ns; +- return pwm_apply_state(pwm, &state); ++ return pwm_apply_might_sleep(pwm, &state); + } + + /** +@@ -358,7 +361,7 @@ static inline int pwm_enable(struct pwm_device *pwm) + return 0; + + state.enabled = true; +- return pwm_apply_state(pwm, &state); ++ return pwm_apply_might_sleep(pwm, &state); + } + + /** +@@ -377,7 +380,18 @@ static inline void pwm_disable(struct pwm_device *pwm) + return; + + state.enabled = false; +- pwm_apply_state(pwm, &state); ++ pwm_apply_might_sleep(pwm, &state); ++} ++ ++/** ++ * pwm_might_sleep() - is pwm_apply_atomic() supported? ++ * @pwm: PWM device ++ * ++ * Returns: false if pwm_apply_atomic() can be called from atomic context. ++ */ ++static inline bool pwm_might_sleep(struct pwm_device *pwm) ++{ ++ return !pwm->chip->atomic; + } + + /* PWM provider APIs */ +@@ -408,16 +422,27 @@ struct pwm_device *devm_fwnode_pwm_get(struct device *dev, + struct fwnode_handle *fwnode, + const char *con_id); + #else +-static inline int pwm_apply_state(struct pwm_device *pwm, +- const struct pwm_state *state) ++static inline bool pwm_might_sleep(struct pwm_device *pwm) ++{ ++ return true; ++} ++ ++static inline int pwm_apply_might_sleep(struct pwm_device *pwm, ++ const struct pwm_state *state) + { + might_sleep(); +- return -ENOTSUPP; ++ return -EOPNOTSUPP; ++} ++ ++static inline int pwm_apply_atomic(struct pwm_device *pwm, ++ const struct pwm_state *state) ++{ ++ return -EOPNOTSUPP; + } + + static inline int pwm_adjust_config(struct pwm_device *pwm) + { +- return -ENOTSUPP; ++ return -EOPNOTSUPP; + } + + static inline int pwm_config(struct pwm_device *pwm, int duty_ns, +@@ -536,7 +561,7 @@ static inline void pwm_apply_args(struct pwm_device *pwm) + state.period = pwm->args.period; + state.usage_power = false; + +- pwm_apply_state(pwm, &state); ++ pwm_apply_might_sleep(pwm, &state); + } + + struct pwm_lookup { +diff --git a/include/linux/rp1_platform.h b/include/linux/rp1_platform.h +new file mode 100644 +index 000000000000..f805dbe1ed9b +--- /dev/null ++++ b/include/linux/rp1_platform.h +@@ -0,0 +1,20 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (c) 2021-2022 Raspberry Pi Ltd. ++ * All rights reserved. ++ */ ++ ++#ifndef _RP1_PLATFORM_H ++#define _RP1_PLATFORM_H ++ ++#include <vdso/bits.h> ++ ++#define RP1_B0_CHIP_ID 0x10001927 ++#define RP1_C0_CHIP_ID 0x20001927 ++ ++#define RP1_PLATFORM_ASIC BIT(1) ++#define RP1_PLATFORM_FPGA BIT(0) ++ ++void rp1_get_platform(u32 *chip_id, u32 *platform); ++ ++#endif diff --git a/include/linux/usb.h b/include/linux/usb.h -index d6a41841b93e..32be892f53cf 100644 +index a21074861f91..4a521591a357 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h -@@ -1838,6 +1838,8 @@ extern int usb_clear_halt(struct usb_device *dev, int pipe); +@@ -1888,6 +1888,8 @@ extern int usb_clear_halt(struct usb_device *dev, int pipe); extern int usb_reset_configuration(struct usb_device *dev); extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate); extern void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr); @@ -182687,10 +237979,10 @@ /* this request isn't really synchronous, but it belongs with the others */ extern int usb_driver_set_configuration(struct usb_device *udev, int config); diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h -index 3dbb42c637c1..a60b7fc02fce 100644 +index 61d4f0b793dc..d3c789ac5a05 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h -@@ -382,6 +382,11 @@ struct hc_driver { +@@ -372,6 +372,11 @@ struct hc_driver { * or bandwidth constraints. */ void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *); @@ -182702,7 +237994,7 @@ /* Returns the hardware-chosen device address */ int (*address_device)(struct usb_hcd *, struct usb_device *udev); /* prepares the hardware to send commands to the device */ -@@ -443,6 +448,8 @@ extern void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *, struct urb *); +@@ -436,6 +441,8 @@ extern void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *, struct urb *); extern void usb_hcd_unmap_urb_for_dma(struct usb_hcd *, struct urb *); extern void usb_hcd_flush_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); @@ -182711,103 +238003,29 @@ extern void usb_hcd_disable_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); extern void usb_hcd_reset_endpoint(struct usb_device *udev, -diff --git a/include/linux/usb/r8152.h b/include/linux/usb/r8152.h -new file mode 100644 -index 000000000000..20d88b1defc3 ---- /dev/null -+++ b/include/linux/usb/r8152.h -@@ -0,0 +1,37 @@ -+/* SPDX-License-Identifier: GPL-2.0-only */ -+/* -+ * Copyright (c) 2020 Realtek Semiconductor Corp. All rights reserved. -+ */ -+ -+#ifndef __LINUX_R8152_H -+#define __LINUX_R8152_H -+ -+#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 MCU_TYPE_PLA 0x0100 -+#define MCU_TYPE_USB 0x0000 -+ -+/* 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 -+ -+#if IS_REACHABLE(CONFIG_USB_RTL8152) -+extern u8 rtl8152_get_version(struct usb_interface *intf); -+#endif -+ -+#endif /* __LINUX_R8152_H */ -diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h -index a3b650ab00f6..6a4901d7caf3 100644 ---- a/include/media/hevc-ctrls.h -+++ b/include/media/hevc-ctrls.h -@@ -19,6 +19,7 @@ - #define V4L2_CID_MPEG_VIDEO_HEVC_SPS (V4L2_CID_MPEG_BASE + 1008) - #define V4L2_CID_MPEG_VIDEO_HEVC_PPS (V4L2_CID_MPEG_BASE + 1009) - #define V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS (V4L2_CID_MPEG_BASE + 1010) -+#define V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX (V4L2_CID_MPEG_BASE + 1011) - #define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (V4L2_CID_MPEG_BASE + 1015) - #define V4L2_CID_MPEG_VIDEO_HEVC_START_CODE (V4L2_CID_MPEG_BASE + 1016) - -@@ -26,6 +27,7 @@ - #define V4L2_CTRL_TYPE_HEVC_SPS 0x0120 - #define V4L2_CTRL_TYPE_HEVC_PPS 0x0121 - #define V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS 0x0122 -+#define V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX 0x0123 - - enum v4l2_mpeg_video_hevc_decode_mode { - V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED, -@@ -166,6 +168,10 @@ struct v4l2_ctrl_hevc_slice_params { - __u32 bit_size; - __u32 data_bit_offset; - -+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ -+ __u32 slice_segment_addr; -+ __u32 num_entry_point_offsets; -+ - /* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */ - __u8 nal_unit_type; - __u8 nuh_temporal_id_plus1; -@@ -201,6 +207,8 @@ struct v4l2_ctrl_hevc_slice_params { - - __u8 padding; - -+ __u32 entry_point_offset_minus1256; -+ - /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ - struct v4l2_hevc_dpb_entry dpbV4L2_HEVC_DPB_ENTRIES_NUM_MAX; - -@@ -210,4 +218,13 @@ struct v4l2_ctrl_hevc_slice_params { - __u64 flags; - }; - -+struct v4l2_ctrl_hevc_scaling_matrix { -+ __u8 scaling_list_4x4616; -+ __u8 scaling_list_8x8664; -+ __u8 scaling_list_16x16664; -+ __u8 scaling_list_32x32264; -+ __u8 scaling_list_dc_coef_16x166; -+ __u8 scaling_list_dc_coef_32x322; -+}; +diff --git a/include/linux/w1.h b/include/linux/w1.h +index 9a2a0ef39018..11b7cce7f667 100644 +--- a/include/linux/w1.h ++++ b/include/linux/w1.h +@@ -121,6 +121,9 @@ typedef void (*w1_slave_found_callback)(struct w1_master *, u64); + * @dev_id: Optional device id string, which w1 slaves could use for + * creating names, which then give a connection to the w1 master + * ++ * @delay_needs_poll: work around jitter introduced with GPIO controllers ++ * accessed over PCIe (RP1) ++ * + * Note: read_bit and write_bit are very low level functions and should only + * be used with hardware that doesn't really support 1-wire operations, + * like a parallel/serial port. +@@ -155,6 +158,8 @@ struct w1_bus_master { + u8, w1_slave_found_callback); + + char *dev_id; + - #endif ++ bool delay_needs_poll; + }; + + /** diff --git a/include/media/media-request.h b/include/media/media-request.h index 3cd25a2717ce..0de5c2c94188 100644 --- a/include/media/media-request.h @@ -182838,30 +238056,232 @@ static inline struct media_request * media_request_get_by_fd(struct media_device *mdev, int request_fd) { -diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h -index c20e2dc6d432..396fb88266be 100644 ---- a/include/media/v4l2-mediabus.h -+++ b/include/media/v4l2-mediabus.h -@@ -92,6 +92,14 @@ - V4L2_MBUS_CSI2_CHANNEL_1 | \ - V4L2_MBUS_CSI2_CHANNEL_2 | \ - V4L2_MBUS_CSI2_CHANNEL_3) -+/* -+ * Number of lanes in use, 0 == use all available lanes (default) -+ * -+ * This is a temporary fix for devices that need to reduce the number of active -+ * lanes for certain modes, until g_mbus_config() can be replaced with a better -+ * solution. +diff --git a/include/media/raspberrypi/pisp_common.h b/include/media/raspberrypi/pisp_common.h +new file mode 100644 +index 000000000000..96303983bab2 +--- /dev/null ++++ b/include/media/raspberrypi/pisp_common.h +@@ -0,0 +1,65 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Raspberry Pi PiSP common configuration definitions. ++ * ++ * Copyright (C) 2021 - Raspberry Pi (Trading) Ltd. ++ * + */ -+#define V4L2_MBUS_CSI2_LANE_MASK (0xf << 10) - - /** - * enum v4l2_mbus_type - media bus type ++#ifndef _PISP_COMMON_H_ ++#define _PISP_COMMON_H_ ++ ++#include <linux/types.h> ++ ++#include "pisp_types.h" ++ ++struct pisp_bla_config { ++ uint16_t black_level_r; ++ uint16_t black_level_gr; ++ uint16_t black_level_gb; ++ uint16_t black_level_b; ++ uint16_t output_black_level; ++ uint8_t pad2; ++}; ++ ++struct pisp_wbg_config { ++ uint16_t gain_r; ++ uint16_t gain_g; ++ uint16_t gain_b; ++ uint8_t pad2; ++}; ++ ++struct pisp_compress_config { ++ /* value subtracted from incoming data */ ++ uint16_t offset; ++ uint8_t pad; ++ /* 1 => Companding; 2 => Delta (recommended); 3 => Combined (for HDR) */ ++ uint8_t mode; ++}; ++ ++struct pisp_decompress_config { ++ /* value added to reconstructed data */ ++ uint16_t offset; ++ uint8_t pad; ++ /* 1 => Companding; 2 => Delta (recommended); 3 => Combined (for HDR) */ ++ uint8_t mode; ++}; ++ ++enum pisp_axi_flags { ++ /* round down bursts to end at a 32-byte boundary, to align following bursts */ ++ PISP_AXI_FLAG_ALIGN = 128, ++ /* for FE writer: force WSTRB high, to pad output to 16-byte boundary */ ++ PISP_AXI_FLAG_PAD = 64, ++ /* for FE writer: Use Output FIFO level to trigger "panic" */ ++ PISP_AXI_FLAG_PANIC = 32 ++}; ++ ++struct pisp_axi_config { ++ /* burst length minus one, which must be in the range 0:15; OR'd with flags */ ++ uint8_t maxlen_flags; ++ /* { prot2:0, cache3:0 } fields, echoed on AXI bus */ ++ uint8_t cache_prot; ++ /* QoS field(s) (4x4 bits for FE writer; 4 bits for other masters) */ ++ uint16_t qos; ++}; ++ ++#endif /* _PISP_COMMON_H_ */ +diff --git a/include/media/raspberrypi/pisp_types.h b/include/media/raspberrypi/pisp_types.h +new file mode 100644 +index 000000000000..10e03bff1c18 +--- /dev/null ++++ b/include/media/raspberrypi/pisp_types.h +@@ -0,0 +1,144 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Raspberry Pi PiSP common types. ++ * ++ * Copyright (C) 2021 - Raspberry Pi (Trading) Ltd. ++ * ++ */ ++#ifndef _PISP_TYPES_H_ ++#define _PISP_TYPES_H_ ++ ++/* This definition must match the format description in the hardware exactly! */ ++struct pisp_image_format_config { ++ /* size in pixels */ ++ uint16_t width, height; ++ /* must match struct pisp_image_format below */ ++ uint32_t format; ++ int32_t stride; ++ /* some planar image formats will need a second stride */ ++ int32_t stride2; ++}; ++ ++static_assert(sizeof(struct pisp_image_format_config) == 16); ++ ++enum pisp_bayer_order { ++ /* ++ * Note how bayer_order&1 tells you if G is on the even pixels of the ++ * checkerboard or not, and bayer_order&2 tells you if R is on the even ++ * rows or is swapped with B. Note that if the top (of the 8) bits is ++ * set, this denotes a monochrome or greyscale image, and the lower bits ++ * should all be ignored. ++ */ ++ PISP_BAYER_ORDER_RGGB = 0, ++ PISP_BAYER_ORDER_GBRG = 1, ++ PISP_BAYER_ORDER_BGGR = 2, ++ PISP_BAYER_ORDER_GRBG = 3, ++ PISP_BAYER_ORDER_GREYSCALE = 128 ++}; ++ ++enum pisp_image_format { ++ /* ++ * Precise values are mostly tbd. Generally these will be portmanteau ++ * values comprising bit fields and flags. This format must be shared ++ * throughout the PiSP. ++ */ ++ PISP_IMAGE_FORMAT_BPS_8 = 0x00000000, ++ PISP_IMAGE_FORMAT_BPS_10 = 0x00000001, ++ PISP_IMAGE_FORMAT_BPS_12 = 0x00000002, ++ PISP_IMAGE_FORMAT_BPS_16 = 0x00000003, ++ PISP_IMAGE_FORMAT_BPS_MASK = 0x00000003, ++ ++ PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED = 0x00000000, ++ PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR = 0x00000010, ++ PISP_IMAGE_FORMAT_PLANARITY_PLANAR = 0x00000020, ++ PISP_IMAGE_FORMAT_PLANARITY_MASK = 0x00000030, ++ ++ PISP_IMAGE_FORMAT_SAMPLING_444 = 0x00000000, ++ PISP_IMAGE_FORMAT_SAMPLING_422 = 0x00000100, ++ PISP_IMAGE_FORMAT_SAMPLING_420 = 0x00000200, ++ PISP_IMAGE_FORMAT_SAMPLING_MASK = 0x00000300, ++ ++ PISP_IMAGE_FORMAT_ORDER_NORMAL = 0x00000000, ++ PISP_IMAGE_FORMAT_ORDER_SWAPPED = 0x00001000, ++ ++ PISP_IMAGE_FORMAT_SHIFT_0 = 0x00000000, ++ PISP_IMAGE_FORMAT_SHIFT_1 = 0x00010000, ++ PISP_IMAGE_FORMAT_SHIFT_2 = 0x00020000, ++ PISP_IMAGE_FORMAT_SHIFT_3 = 0x00030000, ++ PISP_IMAGE_FORMAT_SHIFT_4 = 0x00040000, ++ PISP_IMAGE_FORMAT_SHIFT_5 = 0x00050000, ++ PISP_IMAGE_FORMAT_SHIFT_6 = 0x00060000, ++ PISP_IMAGE_FORMAT_SHIFT_7 = 0x00070000, ++ PISP_IMAGE_FORMAT_SHIFT_8 = 0x00080000, ++ PISP_IMAGE_FORMAT_SHIFT_MASK = 0x000f0000, ++ ++ PISP_IMAGE_FORMAT_UNCOMPRESSED = 0x00000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_1 = 0x01000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_2 = 0x02000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_3 = 0x03000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MASK = 0x03000000, ++ ++ PISP_IMAGE_FORMAT_HOG_SIGNED = 0x04000000, ++ PISP_IMAGE_FORMAT_HOG_UNSIGNED = 0x08000000, ++ PISP_IMAGE_FORMAT_INTEGRAL_IMAGE = 0x10000000, ++ PISP_IMAGE_FORMAT_WALLPAPER_ROLL = 0x20000000, ++ PISP_IMAGE_FORMAT_THREE_CHANNEL = 0x40000000, ++ ++ /* Lastly a few specific instantiations of the above. */ ++ PISP_IMAGE_FORMAT_SINGLE_16 = PISP_IMAGE_FORMAT_BPS_16, ++ PISP_IMAGE_FORMAT_THREE_16 = ++ PISP_IMAGE_FORMAT_BPS_16 | PISP_IMAGE_FORMAT_THREE_CHANNEL ++}; ++ ++#define PISP_IMAGE_FORMAT_bps_8(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_8) ++#define PISP_IMAGE_FORMAT_bps_10(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_10) ++#define PISP_IMAGE_FORMAT_bps_12(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_12) ++#define PISP_IMAGE_FORMAT_bps_16(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_16) ++#define PISP_IMAGE_FORMAT_bps(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_BPS_MASK) ? \ ++ 8 + (2 << (((fmt)&PISP_IMAGE_FORMAT_BPS_MASK) - 1)) : \ ++ 8) ++#define PISP_IMAGE_FORMAT_shift(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_SHIFT_MASK) / PISP_IMAGE_FORMAT_SHIFT_1) ++#define PISP_IMAGE_FORMAT_three_channel(fmt) \ ++ ((fmt)&PISP_IMAGE_FORMAT_THREE_CHANNEL) ++#define PISP_IMAGE_FORMAT_single_channel(fmt) \ ++ (!((fmt)&PISP_IMAGE_FORMAT_THREE_CHANNEL)) ++#define PISP_IMAGE_FORMAT_compressed(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_COMPRESSION_MASK) != \ ++ PISP_IMAGE_FORMAT_UNCOMPRESSED) ++#define PISP_IMAGE_FORMAT_sampling_444(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_444) ++#define PISP_IMAGE_FORMAT_sampling_422(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_422) ++#define PISP_IMAGE_FORMAT_sampling_420(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_420) ++#define PISP_IMAGE_FORMAT_order_normal(fmt) \ ++ (!((fmt)&PISP_IMAGE_FORMAT_ORDER_SWAPPED)) ++#define PISP_IMAGE_FORMAT_order_swapped(fmt) \ ++ ((fmt)&PISP_IMAGE_FORMAT_ORDER_SWAPPED) ++#define PISP_IMAGE_FORMAT_interleaved(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED) ++#define PISP_IMAGE_FORMAT_semiplanar(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR) ++#define PISP_IMAGE_FORMAT_planar(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_PLANAR) ++#define PISP_IMAGE_FORMAT_wallpaper(fmt) \ ++ ((fmt)&PISP_IMAGE_FORMAT_WALLPAPER_ROLL) ++#define PISP_IMAGE_FORMAT_HOG(fmt) \ ++ ((fmt) & \ ++ (PISP_IMAGE_FORMAT_HOG_SIGNED | PISP_IMAGE_FORMAT_HOG_UNSIGNED)) ++ ++#define PISP_WALLPAPER_WIDTH 128 // in bytes ++ ++#endif /* _PISP_TYPES_H_ */ diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h -index bbb3f26fbde9..7a4aa9cb28c9 100644 +index 4b6a9d2ea372..a40c1b3e24b8 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h -@@ -901,6 +901,21 @@ int vb2_core_streamon(struct vb2_queue *q, unsigned int type); +@@ -925,6 +925,21 @@ int vb2_core_streamon(struct vb2_queue *q, unsigned int type); */ int vb2_core_streamoff(struct vb2_queue *q, unsigned int type); @@ -182884,7 +238304,7 @@ * vb2_core_expbuf() - Export a buffer as a file descriptor. * @q: pointer to &struct vb2_queue with videobuf2 queue. diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h -index fdfef7fe40df..b2c462446cf7 100644 +index 73cac8d0287e..b4bc8b675607 100644 --- a/include/soc/bcm2835/raspberrypi-firmware.h +++ b/include/soc/bcm2835/raspberrypi-firmware.h @@ -36,6 +36,8 @@ struct rpi_firmware_property_tag_header { @@ -182904,7 +238324,7 @@ RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030, RPI_FIRMWARE_GET_THROTTLED = 0x00030046, RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047, -@@ -89,8 +92,12 @@ enum rpi_firmware_property_tag { +@@ -89,8 +92,11 @@ enum rpi_firmware_property_tag { RPI_FIRMWARE_GET_PERIPH_REG = 0x00030045, RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045, RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049, @@ -182914,11 +238334,10 @@ RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058, + RPI_FIRMWARE_GET_REBOOT_FLAGS = 0x00030064, + RPI_FIRMWARE_SET_REBOOT_FLAGS = 0x00038064, -+ RPI_FIRMWARE_NOTIFY_DISPLAY_DONE = 0x00030066, + RPI_FIRMWARE_NOTIFY_DISPLAY_DONE = 0x00030066, /* Dispmanx TAGS */ - RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001, -@@ -104,9 +111,16 @@ enum rpi_firmware_property_tag { +@@ -105,9 +111,16 @@ enum rpi_firmware_property_tag { RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 0x00040009, RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a, RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b, @@ -182935,7 +238354,7 @@ RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003, RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004, RPI_FIRMWARE_FRAMEBUFFER_TEST_DEPTH = 0x00044005, -@@ -115,26 +129,39 @@ enum rpi_firmware_property_tag { +@@ -116,22 +129,33 @@ enum rpi_firmware_property_tag { RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 0x00044009, RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a, RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b, @@ -182969,112 +238388,34 @@ RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, }; - -+#define GET_DISPLAY_SETTINGS_PAYLOAD_SIZE 64 -+ - #if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE) - int rpi_firmware_property(struct rpi_firmware *fw, - u32 tag, void *data, size_t len); -diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h -index b55970859a13..4fc733c8c570 100644 ---- a/include/sound/hdmi-codec.h -+++ b/include/sound/hdmi-codec.h -@@ -34,6 +34,11 @@ struct hdmi_codec_daifmt { - unsigned int frame_clk_inv:1; - unsigned int bit_clk_master:1; - unsigned int frame_clk_master:1; -+ /* bit_fmt could be standard PCM format or -+ * IEC958 encoded format. ALSA IEC958 plugin will pass -+ * IEC958_SUBFRAME format to the underneath driver. -+ */ -+ snd_pcm_format_t bit_fmt; +@@ -152,9 +176,12 @@ enum rpi_firmware_clk_id { + RPI_FIRMWARE_M2MC_CLK_ID, + RPI_FIRMWARE_PIXEL_BVB_CLK_ID, + RPI_FIRMWARE_VEC_CLK_ID, ++ RPI_FIRMWARE_DISP_CLK_ID, + RPI_FIRMWARE_NUM_CLK_ID, }; - /* -@@ -60,12 +65,22 @@ struct hdmi_codec_ops { - - /* - * Configures HDMI-encoder for audio stream. -- * Mandatory -+ * Having either prepare or hw_params is mandatory. - */ - int (*hw_params)(struct device *dev, void *data, - struct hdmi_codec_daifmt *fmt, - struct hdmi_codec_params *hparms); - -+ /* -+ * Configures HDMI-encoder for audio stream. Can be called -+ * multiple times for each setup. -+ * -+ * Having either prepare or hw_params is mandatory. -+ */ -+ int (*prepare)(struct device *dev, void *data, -+ struct hdmi_codec_daifmt *fmt, -+ struct hdmi_codec_params *hparms); -+ - /* - * Shuts down the audio stream. - * Mandatory -diff --git a/include/sound/pcm_iec958.h b/include/sound/pcm_iec958.h -index 0939aa45e2fe..64e84441cde1 100644 ---- a/include/sound/pcm_iec958.h -+++ b/include/sound/pcm_iec958.h -@@ -4,6 +4,14 @@ - - #include <linux/types.h> - -+int snd_pcm_create_iec958_consumer_default(u8 *cs, size_t len); -+ -+int snd_pcm_fill_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, -+ size_t len); -+ -+int snd_pcm_fill_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, -+ u8 *cs, size_t len); ++#define GET_DISPLAY_SETTINGS_PAYLOAD_SIZE 64 + - int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, - size_t len); - -diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h -index 5498d7a6556a..3aeab2680295 100644 ---- a/include/uapi/drm/drm_fourcc.h -+++ b/include/uapi/drm/drm_fourcc.h -@@ -287,6 +287,13 @@ extern "C" { - */ - #define DRM_FORMAT_Q401 fourcc_code('Q', '4', '0', '1') + /** + * struct rpi_firmware_clk_rate_request - Firmware Request for a rate + * @id: ID of the clock being queried +diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h +index 3dfc0af8756a..8d2ee7df3b50 100644 +--- a/include/uapi/drm/v3d_drm.h ++++ b/include/uapi/drm/v3d_drm.h +@@ -319,6 +319,10 @@ struct drm_v3d_submit_tfu { -+/* -+ * 2 plane YCbCr MSB aligned, 3 pixels packed into 4 bytes. -+ * index 0 = Y plane, 31:0 x:Y2:Y1:Y0 2:10:10:10 little endian -+ * index 1 = Cr:Cb plane, 63:0 x:Cr2:Cb2:Cr1:x:Cb1:Cr0:Cb0 2:10:10:10:2:10:10:10 little endian -+ */ -+#define DRM_FORMAT_P030 fourcc_code('P', '0', '3', '0') /* 2x2 subsampled Cr:Cb plane 10 bits per channel packed */ + /* Pointer to an array of ioctl extensions*/ + __u64 extensions; + - /* - * 3 plane YCbCr - * index 0: Y plane, 7:0 Y -@@ -777,6 +784,10 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier) - * and UV. Some SAND-using hardware stores UV in a separate tiled - * image from Y to reduce the column height, which is not supported - * with these modifiers. -+ * -+ * The DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT modifier is also -+ * supported for DRM_FORMAT_P030 where the columns remain as 128 bytes -+ * wide, but as this is a 10 bpp format that translates to 96 pixels. - */ - - #define DRM_FORMAT_MOD_BROADCOM_SAND32_COL_HEIGHT(v) \ -diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h -index 863eda048265..8bc13daec0a3 100644 ---- a/include/uapi/drm/drm_mode.h -+++ b/include/uapi/drm/drm_mode.h -@@ -367,6 +367,7 @@ enum drm_mode_subconnector { - #define DRM_MODE_CONNECTOR_DPI 17 - #define DRM_MODE_CONNECTOR_WRITEBACK 18 - #define DRM_MODE_CONNECTOR_SPI 19 -+#define DRM_MODE_CONNECTOR_USB 20 - - struct drm_mode_get_connector { ++ struct { ++ __u32 ioc; ++ } v71; + }; + /* Submits a compute shader for dispatch. This job will block on any diff --git a/include/uapi/linux/bcm2835-isp.h b/include/uapi/linux/bcm2835-isp.h new file mode 100644 index 000000000000..c50e3ca81565 @@ -183429,7 +238770,7 @@ + +#endif /* __BCM2835_ISP_H_ */ diff --git a/include/uapi/linux/fb.h b/include/uapi/linux/fb.h -index 4c14e8be7267..3c6f12b76214 100644 +index 3a49913d006c..d9960887cf9e 100644 --- a/include/uapi/linux/fb.h +++ b/include/uapi/linux/fb.h @@ -35,6 +35,12 @@ @@ -183459,48 +238800,24 @@ __u32 dx; /* screen-relative */ __u32 dy; diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h -index 84fa53ffb13f..33574f0fb793 100644 +index a03c543cb072..7fbeb5a95f45 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h -@@ -34,19 +34,22 @@ - - #define MEDIA_BUS_FMT_FIXED 0x0001 - --/* RGB - next is 0x101d */ -+/* RGB - next is 0x1021 */ - #define MEDIA_BUS_FMT_RGB444_1X12 0x1016 - #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 - #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 - #define MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE 0x1003 - #define MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE 0x1004 - #define MEDIA_BUS_FMT_RGB565_1X16 0x1017 -+#define MEDIA_BUS_FMT_RGB565_1X24_CPADHI 0x1020 - #define MEDIA_BUS_FMT_BGR565_2X8_BE 0x1005 - #define MEDIA_BUS_FMT_BGR565_2X8_LE 0x1006 - #define MEDIA_BUS_FMT_RGB565_2X8_BE 0x1007 - #define MEDIA_BUS_FMT_RGB565_2X8_LE 0x1008 -+#define MEDIA_BUS_FMT_BGR666_1X18 0x101f - #define MEDIA_BUS_FMT_RGB666_1X18 0x1009 - #define MEDIA_BUS_FMT_RBG888_1X24 0x100e -+#define MEDIA_BUS_FMT_BGR666_1X24_CPADHI 0x101e - #define MEDIA_BUS_FMT_RGB666_1X24_CPADHI 0x1015 - #define MEDIA_BUS_FMT_RGB666_1X7X3_SPWG 0x1010 - #define MEDIA_BUS_FMT_BGR888_1X24 0x1013 -@@ -156,4 +159,7 @@ - /* HSV - next is 0x6002 */ - #define MEDIA_BUS_FMT_AHSV8888_1X32 0x6001 +@@ -173,4 +173,7 @@ + */ + #define MEDIA_BUS_FMT_METADATA_FIXED 0x7001 +/* Sensor ancillary metadata formats - next is 0x7002 */ -+#define MEDIA_BUS_FMT_SENSOR_DATA 0x7001 ++#define MEDIA_BUS_FMT_SENSOR_DATA 0x7002 + #endif /* __LINUX_MEDIA_BUS_FORMAT_H */ diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h -index a184c4939438..773e24a1427d 100644 +index c3604a0a3e30..cfd6998a5b5a 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h -@@ -198,6 +198,10 @@ enum v4l2_colorfx { +@@ -203,6 +203,10 @@ enum v4l2_colorfx { */ - #define V4L2_CID_USER_ATMEL_ISC_BASE (V4L2_CID_USER_BASE + 0x10c0) + #define V4L2_CID_USER_ASPEED_BASE (V4L2_CID_USER_BASE + 0x11a0) +/* The base for the bcm2835-isp driver controls. + * We reserve 16 controls for this driver. */ @@ -183509,7 +238826,7 @@ /* MPEG-class control IDs */ /* The MPEG controls are applicable to all codec controls * and the 'MPEG' part of the define is historical */ -@@ -886,6 +890,7 @@ enum v4l2_auto_n_preset_white_balance { +@@ -1004,6 +1008,7 @@ enum v4l2_auto_n_preset_white_balance { V4L2_WHITE_BALANCE_FLASH = 7, V4L2_WHITE_BALANCE_CLOUDY = 8, V4L2_WHITE_BALANCE_SHADE = 9, @@ -183517,16 +238834,8 @@ }; #define V4L2_CID_WIDE_DYNAMIC_RANGE (V4L2_CID_CAMERA_CLASS_BASE+21) -@@ -1078,6 +1083,7 @@ enum v4l2_jpeg_chroma_subsampling { - #define V4L2_CID_TEST_PATTERN_BLUE (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 6) - #define V4L2_CID_TEST_PATTERN_GREENB (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 7) - #define V4L2_CID_UNIT_CELL_SIZE (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 8) -+#define V4L2_CID_NOTIFY_GAINS (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 9) - - - /* Image processing controls */ diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h -index 534eaa4d39bc..53d526dbe004 100644 +index 78260e5d9985..d728b0a01d5f 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -82,6 +82,11 @@ @@ -183541,40 +238850,86 @@ /* * E N U M S */ -@@ -575,6 +580,8 @@ struct v4l2_pix_format { +@@ -584,6 +589,10 @@ struct v4l2_pix_format { + #define V4L2_PIX_FMT_BGR48_12 v4l2_fourcc('B', '3', '1', '2') /* 48 BGR 12-bit per component */ + #define V4L2_PIX_FMT_ABGR64_12 v4l2_fourcc('B', '4', '1', '2') /* 64 BGRA 12-bit per component */ + ++/* RGB formats (6 bytes per pixel) */ ++#define V4L2_PIX_FMT_BGR48 v4l2_fourcc('B', 'G', 'R', '6') /* 16 BGR-16-16-16 */ ++#define V4L2_PIX_FMT_RGB48 v4l2_fourcc('R', 'G', 'B', '6') /* 16 RGB-16-16-16 */ ++ + /* Grey formats */ + #define V4L2_PIX_FMT_GREY v4l2_fourcc('G', 'R', 'E', 'Y') /* 8 Greyscale */ + #define V4L2_PIX_FMT_Y4 v4l2_fourcc('Y', '0', '4', ' ') /* 4 Greyscale */ +@@ -598,6 +607,8 @@ struct v4l2_pix_format { /* Grey bit-packed formats */ #define V4L2_PIX_FMT_Y10BPACK v4l2_fourcc('Y', '1', '0', 'B') /* 10 Greyscale bit-packed */ #define V4L2_PIX_FMT_Y10P v4l2_fourcc('Y', '1', '0', 'P') /* 10 Greyscale, MIPI RAW10 packed */ +#define V4L2_PIX_FMT_Y12P v4l2_fourcc('Y', '1', '2', 'P') /* 12 Greyscale, MIPI RAW12 packed */ +#define V4L2_PIX_FMT_Y14P v4l2_fourcc('Y', '1', '4', 'P') /* 14 Greyscale, MIPI RAW12 packed */ + #define V4L2_PIX_FMT_IPU3_Y10 v4l2_fourcc('i', 'p', '3', 'y') /* IPU3 packed 10-bit greyscale */ /* Palette formats */ - #define V4L2_PIX_FMT_PAL8 v4l2_fourcc('P', 'A', 'L', '8') /* 8 8-bit palette */ -@@ -740,6 +747,10 @@ struct v4l2_pix_format { - #define V4L2_PIX_FMT_INZI v4l2_fourcc('I', 'N', 'Z', 'I') /* Intel Planar Greyscale 10-bit and Depth 16-bit */ - #define V4L2_PIX_FMT_SUNXI_TILED_NV12 v4l2_fourcc('S', 'T', '1', '2') /* Sunxi Tiled NV12 Format */ - #define V4L2_PIX_FMT_CNF4 v4l2_fourcc('C', 'N', 'F', '4') /* Intel 4-bit packed depth confidence information */ +@@ -804,6 +815,10 @@ struct v4l2_pix_format { + #define V4L2_PIX_FMT_QC08C v4l2_fourcc('Q', '0', '8', 'C') /* Qualcomm 8-bit compressed */ + #define V4L2_PIX_FMT_QC10C v4l2_fourcc('Q', '1', '0', 'C') /* Qualcomm 10-bit compressed */ + #define V4L2_PIX_FMT_AJPG v4l2_fourcc('A', 'J', 'P', 'G') /* Aspeed JPEG */ +#define V4L2_PIX_FMT_NV12_COL128 v4l2_fourcc('N', 'C', '1', '2') /* 12 Y/CbCr 4:2:0 128 pixel wide column */ +#define V4L2_PIX_FMT_NV12_10_COL128 v4l2_fourcc('N', 'C', '3', '0') + /* Y/CbCr 4:2:0 10bpc, 3x10 packed as 4 bytes in + * a 128 bytes / 96 pixel wide column */ - /* 10bit raw bayer packed, 32 bytes for every 25 pixels, last LSB 6 bits unused */ + /* 10bit raw packed, 32 bytes for every 25 pixels, last LSB 6 bits unused */ #define V4L2_PIX_FMT_IPU3_SBGGR10 v4l2_fourcc('i', 'p', '3', 'b') /* IPU3 packed 10-bit BGGR bayer */ -@@ -769,6 +780,8 @@ struct v4l2_pix_format { +@@ -811,6 +826,19 @@ struct v4l2_pix_format { + #define V4L2_PIX_FMT_IPU3_SGRBG10 v4l2_fourcc('i', 'p', '3', 'G') /* IPU3 packed 10-bit GRBG bayer */ + #define V4L2_PIX_FMT_IPU3_SRGGB10 v4l2_fourcc('i', 'p', '3', 'r') /* IPU3 packed 10-bit RGGB bayer */ + ++/* The pixel format for all our buffers (the precise format is found in the config buffer). */ ++#define V4L2_PIX_FMT_RPI_BE v4l2_fourcc('R', 'P', 'B', 'P') ++#define V4L2_PIX_FMT_PISP_COMP1_RGGB v4l2_fourcc('P', 'C', '1', 'R') ++#define V4L2_PIX_FMT_PISP_COMP1_GRBG v4l2_fourcc('P', 'C', '1', 'G') ++#define V4L2_PIX_FMT_PISP_COMP1_GBRG v4l2_fourcc('P', 'C', '1', 'g') ++#define V4L2_PIX_FMT_PISP_COMP1_BGGR v4l2_fourcc('P', 'C', '1', 'B') ++#define V4L2_PIX_FMT_PISP_COMP1_MONO v4l2_fourcc('P', 'C', '1', 'M') ++#define V4L2_PIX_FMT_PISP_COMP2_RGGB v4l2_fourcc('P', 'C', '2', 'R') ++#define V4L2_PIX_FMT_PISP_COMP2_GRBG v4l2_fourcc('P', 'C', '2', 'G') ++#define V4L2_PIX_FMT_PISP_COMP2_GBRG v4l2_fourcc('P', 'C', '2', 'g') ++#define V4L2_PIX_FMT_PISP_COMP2_BGGR v4l2_fourcc('P', 'C', '2', 'B') ++#define V4L2_PIX_FMT_PISP_COMP2_MONO v4l2_fourcc('P', 'C', '2', 'M') ++ + /* SDR formats - used only for Software Defined Radio devices */ + #define V4L2_SDR_FMT_CU8 v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */ + #define V4L2_SDR_FMT_CU16LE v4l2_fourcc('C', 'U', '1', '6') /* IQ u16le */ +@@ -833,11 +861,23 @@ struct v4l2_pix_format { #define V4L2_META_FMT_UVC v4l2_fourcc('U', 'V', 'C', 'H') /* UVC Payload Header metadata */ #define V4L2_META_FMT_D4XX v4l2_fourcc('D', '4', 'X', 'X') /* D4XX Payload Header metadata */ #define V4L2_META_FMT_VIVID v4l2_fourcc('V', 'I', 'V', 'D') /* Vivid Metadata */ +#define V4L2_META_FMT_SENSOR_DATA v4l2_fourcc('S', 'E', 'N', 'S') /* Sensor Ancillary metadata */ +#define V4L2_META_FMT_BCM2835_ISP_STATS v4l2_fourcc('B', 'S', 'T', 'A') /* BCM2835 ISP image statistics output */ + /* Vendor specific - used for RK_ISP1 camera sub-system */ + #define V4L2_META_FMT_RK_ISP1_PARAMS v4l2_fourcc('R', 'K', '1', 'P') /* Rockchip ISP1 3A Parameters */ + #define V4L2_META_FMT_RK_ISP1_STAT_3A v4l2_fourcc('R', 'K', '1', 'S') /* Rockchip ISP1 3A Statistics */ + ++/* The metadata format identifier for our configuration buffers. */ ++/* The metadata format identifier for BE configuration buffers. */ ++#define V4L2_META_FMT_RPI_BE_CFG v4l2_fourcc('R', 'P', 'B', 'C') ++ ++/* The metadata format identifier for FE configuration buffers. */ ++#define V4L2_META_FMT_RPI_FE_CFG v4l2_fourcc('R', 'P', 'F', 'C') ++ ++/* The metadata format identifier for FE configuration buffers. */ ++#define V4L2_META_FMT_RPI_FE_STATS v4l2_fourcc('R', 'P', 'F', 'S') ++ /* priv field value to indicates that subsequent fields are valid. */ #define V4L2_PIX_FMT_PRIV_MAGIC 0xfeedcafe + diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c -index 57f4e19df8c6..ba2f699d62cc 100644 +index dd8eed3c6e31..7b717aa93c47 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c -@@ -5865,6 +5865,9 @@ int __init cgroup_init_early(void) +@@ -6170,6 +6170,9 @@ int __init cgroup_init_early(void) return 0; } @@ -183584,9 +238939,9 @@ /** * cgroup_init - cgroup initialization * -@@ -5903,6 +5906,12 @@ int __init cgroup_init(void) +@@ -6203,6 +6206,12 @@ int __init cgroup_init(void) - mutex_unlock(&cgroup_mutex); + cgroup_unlock(); + /* + * Apply an implicit disable, knowing that an explicit enable will @@ -183597,7 +238952,7 @@ for_each_subsys(ss, ssid) { if (ss->early_init) { struct cgroup_subsys_state *css = -@@ -6461,6 +6470,10 @@ static int __init cgroup_disable(char *str) +@@ -6861,6 +6870,10 @@ static int __init cgroup_disable(char *str) strcmp(token, ss->legacy_name)) continue; @@ -183608,7 +238963,7 @@ static_branch_disable(cgroup_subsys_enabled_keyi); pr_info("Disabling %s control group subsystem\n", ss->name); -@@ -6470,6 +6483,31 @@ static int __init cgroup_disable(char *str) +@@ -6879,6 +6892,31 @@ static int __init cgroup_disable(char *str) } __setup("cgroup_disable=", cgroup_disable); @@ -183641,10 +238996,10 @@ static int __init enable_cgroup_debug(char *str) diff --git a/kernel/resource.c b/kernel/resource.c -index 817545ff80b9..375a43d99b28 100644 +index e3f5680a564c..ded9cf87d603 100644 --- a/kernel/resource.c +++ b/kernel/resource.c -@@ -214,6 +214,12 @@ static int __release_resource(struct resource *old, bool release_child) +@@ -200,6 +200,12 @@ static int __release_resource(struct resource *old, bool release_child) { struct resource *tmp, **p, *chd; @@ -183658,130 +239013,81 @@ for (;;) { tmp = *p; diff --git a/mm/page_alloc.c b/mm/page_alloc.c -index 97eb298a0f57..04d75394eabe 100644 +index fafdbf5ae169..d00b0e3b3669 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c -@@ -8887,8 +8887,6 @@ int alloc_contig_range(unsigned long start, unsigned long end, - - /* Make sure the range is really isolated. */ - if (test_pages_isolated(outer_start, end, 0)) { -- pr_info_ratelimited("%s: %lx, %lx) PFNs busy\n", -- __func__, outer_start, end); - ret = -EBUSY; - goto done; - } -diff --git a/mm/zswap.c b/mm/zswap.c -index 358f48b173dc..030254e040b5 100644 ---- a/mm/zswap.c -+++ b/mm/zswap.c -@@ -648,8 +648,9 @@ static struct zswap_pool *zswap_pool_create(char *type, char *compressor) - return NULL; - } - --static __init struct zswap_pool *__zswap_pool_create_fallback(void) -+static bool zswap_try_pool_create(void) - { -+ struct zswap_pool *pool; - bool has_comp, has_zpool; +@@ -206,6 +206,27 @@ EXPORT_SYMBOL(node_states); - has_comp = crypto_has_acomp(zswap_compressor, 0, 0); -@@ -685,9 +686,21 @@ static __init struct zswap_pool *__zswap_pool_create_fallback(void) - } + gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK; - if (!has_comp || !has_zpool) -- return NULL; -+ return false; ++#define ALLOC_IN_CMA_THRESHOLD_MAX 16 ++#define ALLOC_IN_CMA_THRESHOLD_DEFAULT 12 + -+ pool = zswap_pool_create(zswap_zpool_type, zswap_compressor); - -- return zswap_pool_create(zswap_zpool_type, zswap_compressor); -+ if (pool) { -+ pr_info("loaded using pool %s/%s\n", pool->tfm_name, -+ zpool_get_type(pool->zpool)); -+ list_add(&pool->list, &zswap_pools); -+ zswap_has_pool = true; -+ } else { -+ pr_err("pool creation failed\n"); -+ zswap_enabled = false; -+ } ++static unsigned long _alloc_in_cma_threshold __read_mostly ++ = ALLOC_IN_CMA_THRESHOLD_DEFAULT; + -+ return zswap_enabled; - } - - static void zswap_pool_destroy(struct zswap_pool *pool) -@@ -860,16 +873,19 @@ static int zswap_zpool_param_set(const char *val, - static int zswap_enabled_param_set(const char *val, - const struct kernel_param *kp) - { -+ int ret; ++static int __init alloc_in_cma_threshold_setup(char *buf) ++{ ++ unsigned long res; + - if (zswap_init_failed) { - pr_err("can't enable, initialization failed\n"); - return -ENODEV; - } -- if (!zswap_has_pool && zswap_init_started) { -- pr_err("can't enable, no pool configured\n"); -- return -ENODEV; -- } - -- return param_set_bool(val, kp); -+ ret = param_set_bool(val, kp); -+ if (!ret && zswap_enabled && zswap_init_started && !zswap_has_pool) -+ if (!zswap_try_pool_create()) -+ ret = -ENODEV; ++ if (kstrtoul(buf, 10, &res) < 0 || ++ res > ALLOC_IN_CMA_THRESHOLD_MAX) { ++ pr_err("Bad alloc_cma_threshold value\n"); ++ return 0; ++ } ++ _alloc_in_cma_threshold = res; ++ pr_info("Setting alloc_in_cma_threshold to %lu\n", res); ++ return 0; ++} ++early_param("alloc_in_cma_threshold", alloc_in_cma_threshold_setup); + -+ return ret; - } - - /********************************* -@@ -1439,7 +1455,6 @@ static void __exit zswap_debugfs_exit(void) { } - **********************************/ - static int __init init_zswap(void) + /* + * A cached value of the page's pageblock's migratetype, used when the page is + * put on a pcplist. Used to avoid the pageblock migratetype lookup when +@@ -2120,12 +2141,13 @@ __rmqueue(struct zone *zone, unsigned int order, int migratetype, + if (IS_ENABLED(CONFIG_CMA)) { + /* + * Balance movable allocations between regular and CMA areas by +- * allocating from CMA when over half of the zone's free memory +- * is in the CMA area. ++ * allocating from CMA when over more than a given proportion of ++ * the zone's free memory is in the CMA area. + */ + if (alloc_flags & ALLOC_CMA && + zone_page_state(zone, NR_FREE_CMA_PAGES) > +- zone_page_state(zone, NR_FREE_PAGES) / 2) { ++ zone_page_state(zone, NR_FREE_PAGES) / ALLOC_IN_CMA_THRESHOLD_MAX ++ * _alloc_in_cma_threshold) { + page = __rmqueue_cma_fallback(zone, order); + if (page) + return page; +diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c +index fef9ab95ad3d..d136f94eaa0e 100644 +--- a/net/bluetooth/hci_sync.c ++++ b/net/bluetooth/hci_sync.c +@@ -4681,6 +4681,7 @@ static const struct { + */ + static int hci_dev_setup_sync(struct hci_dev *hdev) { -- struct zswap_pool *pool; - int ret; - - zswap_init_started = true; -@@ -1463,29 +1478,19 @@ static int __init init_zswap(void) - if (ret) - goto hp_fail; - -- pool = __zswap_pool_create_fallback(); -- if (pool) { -- pr_info("loaded using pool %s/%s\n", pool->tfm_name, -- zpool_get_type(pool->zpool)); -- list_add(&pool->list, &zswap_pools); -- zswap_has_pool = true; -- } else { -- pr_err("pool creation failed\n"); -- zswap_enabled = false; -- } -- - shrink_wq = create_workqueue("zswap-shrink"); - if (!shrink_wq) -- goto fallback_fail; -+ goto hp_fail; - - frontswap_register_ops(&zswap_frontswap_ops); - if (zswap_debugfs_init()) - pr_warn("debugfs initialization failed\n"); -+ -+ if (zswap_enabled) -+ zswap_try_pool_create(); -+ - return 0; ++ struct fwnode_handle *fwnode = dev_fwnode(hdev->dev.parent); + int ret = 0; + bool invalid_bdaddr; + size_t i; +@@ -4709,7 +4710,8 @@ static int hci_dev_setup_sync(struct hci_dev *hdev) + test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); + if (!ret) { + if (test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks) && +- !bacmp(&hdev->public_addr, BDADDR_ANY)) ++ !bacmp(&hdev->public_addr, BDADDR_ANY) && ++ (invalid_bdaddr || !fwnode_property_present(fwnode, "fallback-bd-address"))) + hci_dev_get_bd_addr_from_property(hdev); --fallback_fail: -- if (pool) -- zswap_pool_destroy(pool); - hp_fail: - cpuhp_remove_state(CPUHP_MM_ZSWP_MEM_PREPARE); - dstmem_fail: + if (invalid_bdaddr && bacmp(&hdev->public_addr, BDADDR_ANY) && diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c -index 31a01aa6f139..4dc15fe4473d 100644 +index 37f95ea8c7db..a40808483730 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c -@@ -883,16 +883,9 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, +@@ -885,16 +885,9 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT) smp->method = JUST_WORKS; @@ -183800,7 +239106,7 @@ return 0; } -@@ -2201,7 +2194,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) +@@ -2221,7 +2214,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) if (err) return SMP_UNSPECIFIED; @@ -183809,7 +239115,7 @@ if (hcon->out) { sc_dhkey_check(smp); SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK); -@@ -2216,9 +2209,6 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) +@@ -2236,9 +2229,6 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) confirm_hint = 0; confirm: @@ -183819,12 +239125,1444 @@ err = mgmt_user_confirm_request(hcon->hdev, &hcon->dst, hcon->type, hcon->dst_type, passkey, confirm_hint); if (err) +diff --git a/net/wireless/certs/debian.hex b/net/wireless/certs/debian.hex +new file mode 100644 +index 000000000000..c5ab03f8c500 +--- /dev/null ++++ b/net/wireless/certs/debian.hex +@@ -0,0 +1,1426 @@ ++0x30, ++0x82, ++0x02, ++0xbd, ++0x30, ++0x82, ++0x01, ++0xa5, ++0x02, ++0x14, ++0x57, ++0x7e, ++0x02, ++0x1c, ++0xb9, ++0x80, ++0xe0, ++0xe8, ++0x20, ++0x82, ++0x1b, ++0xa7, ++0xb5, ++0x4b, ++0x49, ++0x61, ++0xb8, ++0xb4, ++0xfa, ++0xdf, ++0x30, ++0x0d, ++0x06, ++0x09, ++0x2a, ++0x86, ++0x48, ++0x86, ++0xf7, ++0x0d, ++0x01, ++0x01, ++0x0b, ++0x05, ++0x00, ++0x30, ++0x1a, ++0x31, ++0x18, ++0x30, ++0x16, ++0x06, ++0x03, ++0x55, ++0x04, ++0x03, ++0x0c, ++0x0f, ++0x62, ++0x65, ++0x6e, ++0x68, ++0x40, ++0x64, ++0x65, ++0x62, ++0x69, ++0x61, ++0x6e, ++0x2e, ++0x6f, ++0x72, ++0x67, ++0x30, ++0x20, ++0x17, ++0x0d, ++0x32, ++0x30, ++0x30, ++0x31, ++0x33, ++0x30, ++0x31, ++0x33, ++0x32, ++0x36, ++0x31, ++0x33, ++0x5a, ++0x18, ++0x0f, ++0x32, ++0x31, ++0x32, ++0x30, ++0x30, ++0x31, ++0x30, ++0x36, ++0x31, ++0x33, ++0x32, ++0x36, ++0x31, ++0x33, ++0x5a, ++0x30, ++0x1a, ++0x31, ++0x18, ++0x30, ++0x16, ++0x06, ++0x03, ++0x55, ++0x04, ++0x03, ++0x0c, ++0x0f, ++0x62, ++0x65, ++0x6e, ++0x68, ++0x40, ++0x64, ++0x65, ++0x62, ++0x69, ++0x61, ++0x6e, ++0x2e, ++0x6f, ++0x72, ++0x67, ++0x30, ++0x82, ++0x01, ++0x22, ++0x30, ++0x0d, ++0x06, ++0x09, ++0x2a, ++0x86, ++0x48, ++0x86, ++0xf7, ++0x0d, ++0x01, ++0x01, ++0x01, ++0x05, ++0x00, ++0x03, ++0x82, ++0x01, ++0x0f, ++0x00, ++0x30, ++0x82, ++0x01, ++0x0a, ++0x02, ++0x82, ++0x01, ++0x01, ++0x00, ++0x9d, ++0xe1, ++0x77, ++0xa0, ++0x24, ++0xa0, ++0xd5, ++0x79, ++0x65, ++0x3a, ++0x07, ++0x90, ++0xc9, ++0xf6, ++0xa5, ++0xa6, ++0x1f, ++0x84, ++0x1c, ++0x23, ++0x07, ++0x4b, ++0x4f, ++0xa5, ++0x03, ++0xc6, ++0x0f, ++0xf7, ++0x54, ++0xd5, ++0x8b, ++0x7e, ++0x79, ++0x81, ++0x00, ++0xd2, ++0xe9, ++0x3d, ++0xf4, ++0x97, ++0xfe, ++0x84, ++0xcd, ++0x55, ++0xbd, ++0xc9, ++0x8f, ++0x21, ++0x57, ++0x88, ++0x06, ++0x39, ++0x90, ++0x66, ++0x41, ++0x26, ++0x79, ++0x2c, ++0xca, ++0x3f, ++0x95, ++0x87, ++0x01, ++0x11, ++0x2f, ++0x2f, ++0xb0, ++0xe1, ++0x0b, ++0x43, ++0xfc, ++0x5f, ++0x2f, ++0x4f, ++0x67, ++0x04, ++0xdb, ++0x4d, ++0xb7, ++0x72, ++0x4d, ++0xd1, ++0xc5, ++0x76, ++0x73, ++0x4d, ++0x91, ++0x69, ++0xb0, ++0x71, ++0x17, ++0x36, ++0xea, ++0xab, ++0x0a, ++0x3a, ++0xcd, ++0x95, ++0x9b, ++0x76, ++0x1b, ++0x8e, ++0x21, ++0x17, ++0x8f, ++0xc5, ++0x02, ++0xbf, ++0x24, ++0xc7, ++0xc0, ++0x40, ++0xb1, ++0x3b, ++0xc4, ++0x80, ++0x7c, ++0x71, ++0xa5, ++0x51, ++0xdc, ++0xf7, ++0x3a, ++0x58, ++0x7f, ++0xb1, ++0x07, ++0x81, ++0x8a, ++0x10, ++0xd1, ++0xf6, ++0x93, ++0x17, ++0x71, ++0xe0, ++0xfa, ++0x51, ++0x79, ++0x15, ++0xd4, ++0xd7, ++0x8f, ++0xad, ++0xbd, ++0x6f, ++0x38, ++0xe1, ++0x26, ++0x7d, ++0xbc, ++0xf0, ++0x3e, ++0x80, ++0x89, ++0xb4, ++0xec, ++0x8e, ++0x69, ++0x90, ++0xdb, ++0x97, ++0x8a, ++0xf0, ++0x23, ++0x23, ++0x83, ++0x82, ++0x3b, ++0x6a, ++0xb1, ++0xac, ++0xeb, ++0xe7, ++0x99, ++0x74, ++0x2a, ++0x35, ++0x8e, ++0xa9, ++0x64, ++0xfd, ++0x46, ++0x9e, ++0xe8, ++0xe5, ++0x48, ++0x61, ++0x31, ++0x6e, ++0xe6, ++0xfc, ++0x19, ++0x18, ++0x54, ++0xc3, ++0x1b, ++0x4f, ++0xd6, ++0x00, ++0x44, ++0x87, ++0x1c, ++0x37, ++0x45, ++0xea, ++0xf5, ++0xc9, ++0xcb, ++0x0f, ++0x0c, ++0x55, ++0xec, ++0xcf, ++0x6a, ++0xc2, ++0x45, ++0x26, ++0x23, ++0xa2, ++0x31, ++0x52, ++0x4d, ++0xee, ++0x21, ++0x7d, ++0xfd, ++0x58, ++0x72, ++0xc2, ++0x28, ++0xc5, ++0x8e, ++0xa9, ++0xd0, ++0xee, ++0x01, ++0x77, ++0x08, ++0xa5, ++0xf0, ++0x22, ++0x2b, ++0x47, ++0x79, ++0x2b, ++0xcf, ++0x9a, ++0x46, ++0xb5, ++0x8f, ++0xfd, ++0x64, ++0xa2, ++0xb5, ++0xed, ++0x02, ++0x03, ++0x01, ++0x00, ++0x01, ++0x30, ++0x0d, ++0x06, ++0x09, ++0x2a, ++0x86, ++0x48, ++0x86, ++0xf7, ++0x0d, ++0x01, ++0x01, ++0x0b, ++0x05, ++0x00, ++0x03, ++0x82, ++0x01, ++0x01, ++0x00, ++0x20, ++0x44, ++0xfe, ++0xa9, ++0x9e, ++0xdd, ++0x9b, ++0xea, ++0xce, ++0x25, ++0x75, ++0x08, ++0xf0, ++0x2b, ++0x53, ++0xf7, ++0x5a, ++0x36, ++0x1c, ++0x4a, ++0x23, ++0x7f, ++0xd0, ++0x41, ++0x3c, ++0x12, ++0x2b, ++0xb9, ++0x80, ++0x4e, ++0x8a, ++0x15, ++0x5d, ++0x1f, ++0x40, ++0xa7, ++0x26, ++0x28, ++0x32, ++0xc3, ++0x5b, ++0x06, ++0x28, ++0x2d, ++0x3d, ++0x08, ++0x09, ++0x1e, ++0x01, ++0xe9, ++0x67, ++0xe3, ++0x33, ++0xe6, ++0x15, ++0x45, ++0x39, ++0xee, ++0x17, ++0x83, ++0xdb, ++0x42, ++0xff, ++0x7f, ++0x35, ++0xf4, ++0xac, ++0x16, ++0xdb, ++0xba, ++0xb8, ++0x1a, ++0x20, ++0x21, ++0x41, ++0xff, ++0xf3, ++0x92, ++0xff, ++0x65, ++0x6e, ++0x29, ++0x16, ++0xd0, ++0xbf, ++0x8d, ++0xdf, ++0x48, ++0x2c, ++0x73, ++0x36, ++0x7f, ++0x22, ++0xe6, ++0xee, ++0x78, ++0xb4, ++0x63, ++0x83, ++0x0e, ++0x39, ++0xeb, ++0xaf, ++0x10, ++0x2a, ++0x90, ++0xd3, ++0xfc, ++0xe6, ++0xc3, ++0x8f, ++0x97, ++0x5b, ++0x76, ++0xbf, ++0x9b, ++0xf5, ++0x98, ++0xd2, ++0x53, ++0x06, ++0x8b, ++0xf8, ++0xa4, ++0x04, ++0x9b, ++0x1b, ++0x62, ++0x6a, ++0x9d, ++0xac, ++0xe6, ++0x4b, ++0x0d, ++0xc9, ++0xd7, ++0x56, ++0x63, ++0x15, ++0x01, ++0x38, ++0x8c, ++0xbe, ++0xf1, ++0x44, ++0xc4, ++0x38, ++0x27, ++0xe0, ++0xcf, ++0x72, ++0xd6, ++0x3d, ++0xe4, ++0xf7, ++0x4b, ++0x3b, ++0xd2, ++0xb1, ++0x0c, ++0xd5, ++0x83, ++0x6d, ++0x1e, ++0x10, ++0x04, ++0x69, ++0x29, ++0x88, ++0x69, ++0xe0, ++0x7d, ++0xd7, ++0xdb, ++0xb4, ++0x59, ++0x72, ++0x8d, ++0x9d, ++0x3c, ++0x43, ++0xaf, ++0xc6, ++0x7d, ++0xb7, ++0x21, ++0x15, ++0x52, ++0x8a, ++0xe9, ++0x9b, ++0x6b, ++0x2e, ++0xe8, ++0x27, ++0x3c, ++0x3f, ++0x2d, ++0x84, ++0xfb, ++0x9a, ++0x22, ++0x0a, ++0x9f, ++0x6a, ++0x25, ++0xe6, ++0x39, ++0xe4, ++0x74, ++0x73, ++0xb6, ++0x2a, ++0x70, ++0xaa, ++0x1d, ++0xcb, ++0xcc, ++0xd4, ++0xa0, ++0x1b, ++0x26, ++0x71, ++0x63, ++0x04, ++0xc5, ++0x12, ++0x21, ++0x48, ++0xba, ++0x92, ++0x27, ++0x06, ++0xa8, ++0x3e, ++0x6d, ++0xa1, ++0x43, ++0xa5, ++0xd2, ++0x2a, ++0xf7, ++0xca, ++0xc4, ++0x26, ++0xe8, ++0x5b, ++0x1f, ++0xe4, ++0xdc, ++0x89, ++0xdc, ++0x1f, ++0x04, ++0x79, ++0x3f, ++0x30, ++0x82, ++0x02, ++0xcd, ++0x30, ++0x82, ++0x01, ++0xb5, ++0x02, ++0x14, ++0x3a, ++0xbb, ++0xc6, ++0xec, ++0x14, ++0x6e, ++0x09, ++0xd1, ++0xb6, ++0x01, ++0x6a, ++0xb9, ++0xd6, ++0xcf, ++0x71, ++0xdd, ++0x23, ++0x3f, ++0x03, ++0x28, ++0x30, ++0x0d, ++0x06, ++0x09, ++0x2a, ++0x86, ++0x48, ++0x86, ++0xf7, ++0x0d, ++0x01, ++0x01, ++0x0b, ++0x05, ++0x00, ++0x30, ++0x22, ++0x31, ++0x20, ++0x30, ++0x1e, ++0x06, ++0x03, ++0x55, ++0x04, ++0x03, ++0x0c, ++0x17, ++0x72, ++0x6f, ++0x6d, ++0x61, ++0x69, ++0x6e, ++0x2e, ++0x70, ++0x65, ++0x72, ++0x69, ++0x65, ++0x72, ++0x40, ++0x67, ++0x6d, ++0x61, ++0x69, ++0x6c, ++0x2e, ++0x63, ++0x6f, ++0x6d, ++0x30, ++0x20, ++0x17, ++0x0d, ++0x32, ++0x30, ++0x30, ++0x32, ++0x32, ++0x34, ++0x31, ++0x39, ++0x30, ++0x31, ++0x34, ++0x34, ++0x5a, ++0x18, ++0x0f, ++0x32, ++0x31, ++0x32, ++0x30, ++0x30, ++0x31, ++0x33, ++0x31, ++0x31, ++0x39, ++0x30, ++0x31, ++0x34, ++0x34, ++0x5a, ++0x30, ++0x22, ++0x31, ++0x20, ++0x30, ++0x1e, ++0x06, ++0x03, ++0x55, ++0x04, ++0x03, ++0x0c, ++0x17, ++0x72, ++0x6f, ++0x6d, ++0x61, ++0x69, ++0x6e, ++0x2e, ++0x70, ++0x65, ++0x72, ++0x69, ++0x65, ++0x72, ++0x40, ++0x67, ++0x6d, ++0x61, ++0x69, ++0x6c, ++0x2e, ++0x63, ++0x6f, ++0x6d, ++0x30, ++0x82, ++0x01, ++0x22, ++0x30, ++0x0d, ++0x06, ++0x09, ++0x2a, ++0x86, ++0x48, ++0x86, ++0xf7, ++0x0d, ++0x01, ++0x01, ++0x01, ++0x05, ++0x00, ++0x03, ++0x82, ++0x01, ++0x0f, ++0x00, ++0x30, ++0x82, ++0x01, ++0x0a, ++0x02, ++0x82, ++0x01, ++0x01, ++0x00, ++0xf0, ++0xb8, ++0x4f, ++0x3f, ++0x70, ++0x78, ++0xf8, ++0x74, ++0x45, ++0xa2, ++0x28, ++0xaf, ++0x04, ++0x75, ++0x04, ++0xa3, ++0xf3, ++0xa7, ++0xc7, ++0x04, ++0xac, ++0xb6, ++0xe1, ++0xfc, ++0xe1, ++0xc0, ++0x3d, ++0xe0, ++0x26, ++0x90, ++0x8a, ++0x45, ++0x60, ++0xc4, ++0x75, ++0xf3, ++0x1a, ++0x33, ++0x37, ++0x56, ++0x7d, ++0x30, ++0x07, ++0x75, ++0x0e, ++0xa6, ++0x79, ++0x06, ++0x95, ++0x9d, ++0x17, ++0x3c, ++0x09, ++0xa9, ++0x7f, ++0xab, ++0x95, ++0x5d, ++0xed, ++0xe0, ++0x75, ++0x26, ++0x2f, ++0x65, ++0x65, ++0xcd, ++0x61, ++0xb1, ++0x33, ++0x27, ++0x67, ++0x41, ++0xa1, ++0x01, ++0x13, ++0xe9, ++0x13, ++0x6a, ++0x6d, ++0x4e, ++0x98, ++0xe1, ++0x9e, ++0x7b, ++0x0b, ++0x5b, ++0x44, ++0xef, ++0x68, ++0x5a, ++0x6f, ++0x7d, ++0x97, ++0xa1, ++0x33, ++0x22, ++0x97, ++0x12, ++0x21, ++0x09, ++0x8f, ++0x90, ++0xe0, ++0x25, ++0x94, ++0xdd, ++0x8a, ++0x3a, ++0xf7, ++0x4a, ++0x60, ++0x04, ++0x26, ++0x6d, ++0x00, ++0x82, ++0xe4, ++0xcf, ++0x64, ++0x1c, ++0x79, ++0x15, ++0x24, ++0xf2, ++0x42, ++0x86, ++0xf5, ++0x10, ++0x86, ++0xac, ++0x20, ++0x88, ++0x90, ++0x87, ++0xdf, ++0x8c, ++0x37, ++0x7c, ++0xbf, ++0x35, ++0xd5, ++0x6f, ++0x9f, ++0x77, ++0xc3, ++0xcd, ++0x69, ++0x25, ++0x06, ++0xc2, ++0x65, ++0x51, ++0x71, ++0x89, ++0x7f, ++0x6e, ++0x4d, ++0xe5, ++0xd5, ++0x8a, ++0x36, ++0x1a, ++0xad, ++0xc1, ++0x18, ++0xd6, ++0x14, ++0x42, ++0x87, ++0xf0, ++0x93, ++0x83, ++0xf1, ++0x99, ++0x74, ++0xc4, ++0x13, ++0xaa, ++0x3b, ++0x66, ++0x85, ++0x6f, ++0xe0, ++0xbc, ++0x5f, ++0xb6, ++0x40, ++0xa6, ++0x41, ++0x06, ++0x0a, ++0xba, ++0x0e, ++0xe9, ++0x32, ++0x44, ++0x10, ++0x39, ++0x53, ++0xcd, ++0xbf, ++0xf3, ++0xd3, ++0x26, ++0xf6, ++0xb6, ++0x2b, ++0x40, ++0x2e, ++0xb9, ++0x88, ++0xc1, ++0xf4, ++0xe3, ++0xa0, ++0x28, ++0x77, ++0x4f, ++0xba, ++0xa8, ++0xca, ++0x9c, ++0x05, ++0xba, ++0x88, ++0x96, ++0x99, ++0x54, ++0x89, ++0xa2, ++0x8d, ++0xf3, ++0x73, ++0xa1, ++0x8c, ++0x4a, ++0xa8, ++0x71, ++0xee, ++0x2e, ++0xd2, ++0x83, ++0x14, ++0x48, ++0xbd, ++0x98, ++0xc6, ++0xce, ++0xdc, ++0xa8, ++0xa3, ++0x97, ++0x2e, ++0x40, ++0x16, ++0x2f, ++0x02, ++0x03, ++0x01, ++0x00, ++0x01, ++0x30, ++0x0d, ++0x06, ++0x09, ++0x2a, ++0x86, ++0x48, ++0x86, ++0xf7, ++0x0d, ++0x01, ++0x01, ++0x0b, ++0x05, ++0x00, ++0x03, ++0x82, ++0x01, ++0x01, ++0x00, ++0x76, ++0x5d, ++0x03, ++0x3d, ++0xb6, ++0x96, ++0x00, ++0x1b, ++0x6e, ++0x0c, ++0xdd, ++0xbb, ++0xc8, ++0xdf, ++0xbc, ++0xeb, ++0x6c, ++0x01, ++0x40, ++0x1a, ++0x2b, ++0x07, ++0x60, ++0xa1, ++0x1a, ++0xe1, ++0x43, ++0x57, ++0xfa, ++0xbe, ++0xde, ++0xbb, ++0x8f, ++0x73, ++0xf3, ++0x92, ++0xa2, ++0xaa, ++0x83, ++0x01, ++0xc1, ++0x17, ++0xe4, ++0x9d, ++0x09, ++0x41, ++0xe0, ++0x32, ++0x33, ++0x97, ++0x4b, ++0xf2, ++0xdc, ++0x0f, ++0x8b, ++0xa8, ++0xb8, ++0x5a, ++0x04, ++0x86, ++0xf6, ++0x71, ++0xa1, ++0x97, ++0xd0, ++0x54, ++0x56, ++0x10, ++0x8e, ++0x54, ++0x99, ++0x0d, ++0x2a, ++0xa9, ++0xaf, ++0x1b, ++0x55, ++0x59, ++0x06, ++0x2b, ++0xa4, ++0x5f, ++0xb1, ++0x54, ++0xa6, ++0xec, ++0xc7, ++0xd6, ++0x43, ++0xee, ++0x86, ++0x2c, ++0x9b, ++0x18, ++0x9d, ++0x8f, ++0x00, ++0x82, ++0xc1, ++0x88, ++0x61, ++0x16, ++0x85, ++0x3c, ++0x17, ++0x56, ++0xfe, ++0x6a, ++0xa0, ++0x7a, ++0x68, ++0xc5, ++0x7b, ++0x3d, ++0x3c, ++0xb6, ++0x13, ++0x18, ++0x99, ++0x6d, ++0x74, ++0x65, ++0x13, ++0x67, ++0xb7, ++0xfc, ++0x5a, ++0x44, ++0x48, ++0x72, ++0xa0, ++0x73, ++0xb8, ++0xff, ++0x02, ++0x9d, ++0x7c, ++0x5b, ++0xf9, ++0x7c, ++0x75, ++0x0a, ++0x3c, ++0x81, ++0x80, ++0x3c, ++0x41, ++0xf2, ++0xd5, ++0xfa, ++0x3d, ++0x1f, ++0xe3, ++0xda, ++0x8c, ++0xa5, ++0x17, ++0x1f, ++0x53, ++0x1a, ++0x75, ++0xad, ++0x4e, ++0x11, ++0x1c, ++0x07, ++0xec, ++0x0a, ++0x69, ++0xfd, ++0x33, ++0xfa, ++0x32, ++0x7e, ++0x66, ++0xf5, ++0x29, ++0xe8, ++0x4d, ++0x8a, ++0xfa, ++0x0d, ++0x4b, ++0x68, ++0xc3, ++0x95, ++0x11, ++0xba, ++0x6f, ++0x1e, ++0x07, ++0x8c, ++0x85, ++0xc7, ++0xc7, ++0xc9, ++0xc1, ++0x30, ++0xa3, ++0x70, ++0xb0, ++0xa1, ++0xe0, ++0xd5, ++0x85, ++0x15, ++0x94, ++0x77, ++0xc1, ++0x1c, ++0x91, ++0xf1, ++0x5f, ++0x50, ++0xcd, ++0x2c, ++0x57, ++0x4b, ++0x22, ++0x4f, ++0xee, ++0x95, ++0xd7, ++0xa7, ++0xa4, ++0x59, ++0x62, ++0xae, ++0xb9, ++0xbf, ++0xd7, ++0x63, ++0x5a, ++0x04, ++0xfc, ++0x24, ++0x11, ++0xae, ++0x34, ++0x4b, ++0xf4, ++0x0c, ++0x9f, ++0x0b, ++0x59, ++0x7d, ++0x27, ++0x39, ++0x54, ++0x69, ++0x4f, ++0xfd, ++0x6e, ++0x44, ++0x9f, ++0x21, diff --git a/scripts/Makefile.dtbinst b/scripts/Makefile.dtbinst -index 50d580d77ae9..079b83308011 100644 +index 4405d5b67578..9d8f14e3c732 100644 --- a/scripts/Makefile.dtbinst +++ b/scripts/Makefile.dtbinst -@@ -18,9 +18,10 @@ include scripts/Kbuild.include - include $(src)/Makefile +@@ -18,9 +18,10 @@ include $(srctree)/scripts/Kbuild.include + include $(kbuild-file) dtbs := $(addprefix $(dst)/, $(dtb-y) $(if $(CONFIG_OF_ALL_DTBS),$(dtb-))) +dtbos := $(addprefix $(dst)/, $(dtbo-y) $(if $(CONFIG_OF_ALL_DTBS),$(dtb-))) @@ -183835,31 +240573,29 @@ @: quiet_cmd_dtb_install = INSTALL $@ -@@ -29,6 +30,9 @@ quiet_cmd_dtb_install = INSTALL $@ - $(dst)/%.dtb: $(obj)/%.dtb - $(call cmd,dtb_install) +@@ -34,6 +35,6 @@ $(dst)/%.dtbo: $(obj)/%.dtbo -+$(dst)/%.dtbo: $(obj)/%.dtbo -+ $(call cmd,dtb_install) -+ PHONY += $(subdirs) $(subdirs): - $(Q)$(MAKE) $(dtbinst)=$@ dst=$(patsubst $(obj)/%,$(dst)/%,$@) +- $(Q)$(MAKE) $(dtbinst)=$@ dst=$(if $(CONFIG_ARCH_WANT_FLAT_DTB_INSTALL),$(dst),$(patsubst $(obj)/%,$(dst)/%,$@)) ++ $(Q)$(MAKE) $(dtbinst)=$@ dst=$(if $(if $(subst $(obj)/overlays,,$@),$(CONFIG_ARCH_WANT_FLAT_DTB_INSTALL),),$(dst),$(patsubst $(obj)/%,$(dst)/%,$@)) + + .PHONY: $(PHONY) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib -index 94133708889d..43758c8d4b68 100644 +index 68d0134bdbf9..116cfae5fa07 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib -@@ -281,6 +281,7 @@ DTC_FLAGS += -Wno-interrupt_provider +@@ -346,6 +346,7 @@ DTC_FLAGS += -Wno-interrupt_provider \ + # Disable noisy checks by default ifeq ($(findstring 1,$(KBUILD_EXTRA_WARN)),) DTC_FLAGS += -Wno-unit_address_vs_reg \ - -Wno-unit_address_format \ + -Wno-gpios_property \ -Wno-avoid_unnecessary_addr_size \ -Wno-alias_paths \ -Wno-graph_child_address \ -@@ -341,6 +342,24 @@ endef - $(obj)/%.dt.yaml: $(src)/%.dts $(DTC) $(DT_TMP_SCHEMA) FORCE - $(call if_changed_rule,dtc,yaml) +@@ -421,6 +422,24 @@ $(obj)/%.dtb: $(src)/%.dts $(DTC) $(DT_TMP_SCHEMA) FORCE + $(obj)/%.dtbo: $(src)/%.dtso $(DTC) FORCE + $(call if_changed_dep,dtc) +quiet_cmd_dtco = DTCO $@ +cmd_dtco = mkdir -p $(dir ${dtc-tmp}) ; \ @@ -183882,212 +240618,37 @@ dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp) # Bzip2 -diff --git a/sound/core/pcm_iec958.c b/sound/core/pcm_iec958.c -index f9a211cc1f2c..a60908efe159 100644 ---- a/sound/core/pcm_iec958.c -+++ b/sound/core/pcm_iec958.c -@@ -9,41 +9,68 @@ - #include <sound/pcm_params.h> - #include <sound/pcm_iec958.h> - --static int create_iec958_consumer(uint rate, uint sample_width, -- u8 *cs, size_t len) -+int snd_pcm_create_iec958_consumer_default(u8 *cs, size_t len) - { -- unsigned int fs, ws; -- - if (len < 4) - return -EINVAL; - -- switch (rate) { -- case 32000: -- fs = IEC958_AES3_CON_FS_32000; -- break; -- case 44100: -- fs = IEC958_AES3_CON_FS_44100; -- break; -- case 48000: -- fs = IEC958_AES3_CON_FS_48000; -- break; -- case 88200: -- fs = IEC958_AES3_CON_FS_88200; -- break; -- case 96000: -- fs = IEC958_AES3_CON_FS_96000; -- break; -- case 176400: -- fs = IEC958_AES3_CON_FS_176400; -- break; -- case 192000: -- fs = IEC958_AES3_CON_FS_192000; -- break; -- default: -+ memset(cs, 0, len); -+ -+ cs0 = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; -+ cs1 = IEC958_AES1_CON_GENERAL; -+ cs2 = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC; -+ cs3 = IEC958_AES3_CON_CLOCK_1000PPM | IEC958_AES3_CON_FS_NOTID; -+ -+ if (len > 4) -+ cs4 = IEC958_AES4_CON_WORDLEN_NOTID; -+ -+ return len; -+} -+EXPORT_SYMBOL(snd_pcm_create_iec958_consumer_default); -+ -+static int fill_iec958_consumer(uint rate, uint sample_width, -+ u8 *cs, size_t len) -+{ -+ if (len < 4) - return -EINVAL; -+ -+ if ((cs3 & IEC958_AES3_CON_FS) == IEC958_AES3_CON_FS_NOTID) { -+ unsigned int fs; -+ -+ switch (rate) { -+ case 32000: -+ fs = IEC958_AES3_CON_FS_32000; -+ break; -+ case 44100: -+ fs = IEC958_AES3_CON_FS_44100; -+ break; -+ case 48000: -+ fs = IEC958_AES3_CON_FS_48000; -+ break; -+ case 88200: -+ fs = IEC958_AES3_CON_FS_88200; -+ break; -+ case 96000: -+ fs = IEC958_AES3_CON_FS_96000; -+ break; -+ case 176400: -+ fs = IEC958_AES3_CON_FS_176400; -+ break; -+ case 192000: -+ fs = IEC958_AES3_CON_FS_192000; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ cs3 &= ~IEC958_AES3_CON_FS; -+ cs3 |= fs; - } - -- if (len > 4) { -+ if (len > 4 && -+ (cs4 & IEC958_AES4_CON_WORDLEN) == IEC958_AES4_CON_WORDLEN_NOTID) { -+ unsigned int ws; -+ - switch (sample_width) { - case 16: - ws = IEC958_AES4_CON_WORDLEN_20_16; -@@ -64,20 +91,29 @@ static int create_iec958_consumer(uint rate, uint sample_width, - default: - return -EINVAL; - } -- } - -- memset(cs, 0, len); -+ cs4 &= ~IEC958_AES4_CON_WORDLEN; -+ cs4 |= ws; -+ } - -- cs0 = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; -- cs1 = IEC958_AES1_CON_GENERAL; -- cs2 = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC; -- cs3 = IEC958_AES3_CON_CLOCK_1000PPM | fs; -+ return len; -+} - -- if (len > 4) -- cs4 = ws; -+int snd_pcm_fill_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, -+ u8 *cs, size_t len) -+{ -+ return fill_iec958_consumer(params_rate(params), params_width(params), cs, len); -+} -+EXPORT_SYMBOL(snd_pcm_fill_iec958_consumer_hw_params); - -- return len; -+int snd_pcm_fill_iec958_consumer(struct snd_pcm_runtime *runtime, -+ u8 *cs, size_t len) -+{ -+ return fill_iec958_consumer(runtime->rate, -+ snd_pcm_format_width(runtime->format), -+ cs, len); - } -+EXPORT_SYMBOL(snd_pcm_fill_iec958_consumer); - - /** - * snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status -@@ -95,9 +131,13 @@ static int create_iec958_consumer(uint rate, uint sample_width, - int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, - size_t len) - { -- return create_iec958_consumer(runtime->rate, -- snd_pcm_format_width(runtime->format), -- cs, len); -+ int ret; -+ -+ ret = snd_pcm_create_iec958_consumer_default(cs, len); -+ if (ret < 0) -+ return ret; -+ -+ return snd_pcm_fill_iec958_consumer(runtime, cs, len); - } - EXPORT_SYMBOL(snd_pcm_create_iec958_consumer); - -@@ -117,7 +157,12 @@ EXPORT_SYMBOL(snd_pcm_create_iec958_consumer); - int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, - u8 *cs, size_t len) - { -- return create_iec958_consumer(params_rate(params), params_width(params), -- cs, len); -+ int ret; -+ -+ ret = snd_pcm_create_iec958_consumer_default(cs, len); -+ if (ret < 0) -+ return ret; -+ -+ return fill_iec958_consumer(params_rate(params), params_width(params), cs, len); - } - EXPORT_SYMBOL(snd_pcm_create_iec958_consumer_hw_params); diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index 4218057b0874..c85714895f1e 100644 +index 4218057b0874..d27ba79e1208 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -26,3 +26,301 @@ config SND_BCM63XX_I2S_WHISTLER +@@ -26,3 +26,272 @@ config SND_BCM63XX_I2S_WHISTLER DSL/PON chips (bcm63158, bcm63178) If you don't know what to do here, say N + +config SND_BCM2708_SOC_CHIPDIP_DAC + tristate "Support for the ChipDip DAC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + help + Say Y or M if you want to add support for the ChipDip DAC soundcard + +config SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD + tristate "Support for Google voiceHAT soundcard" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_VOICEHAT + select SND_RPI_SIMPLE_SOUNDCARD + help + Say Y or M if you want to add support for voiceHAT soundcard. + +config SND_BCM2708_SOC_HIFIBERRY_DAC -+ tristate "Support for HifiBerry DAC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ++ tristate "Support for HifiBerry DAC and DAC8X" + select SND_SOC_PCM5102A + select SND_RPI_SIMPLE_SOUNDCARD + help -+ Say Y or M if you want to add support for HifiBerry DAC. ++ Say Y or M if you want to add support for HifiBerry DAC and DAC8X. ++ Note: DAC8X only works on PI5 + +config SND_BCM2708_SOC_HIFIBERRY_DACPLUS + tristate "Support for HifiBerry DAC+" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x + select SND_SOC_TPA6130A2 + select COMMON_CLK_HIFIBERRY_DACPRO @@ -184096,7 +240657,6 @@ + +config SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD + tristate "Support for HifiBerry DAC+ HD" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM179X_I2C + select COMMON_CLK_HIFIBERRY_DACPLUSHD + help @@ -184104,7 +240664,6 @@ + +config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC + tristate "Support for HifiBerry DAC+ADC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x_I2C + select SND_SOC_DMIC + select COMMON_CLK_HIFIBERRY_DACPRO @@ -184113,7 +240672,6 @@ + +config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO + tristate "Support for HifiBerry DAC+ADC PRO" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x_I2C + select SND_SOC_PCM186X_I2C + select SND_SOC_TPA6130A2 @@ -184123,29 +240681,25 @@ + +config SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP + tristate "Support for HifiBerry DAC+DSP" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_RPI_SIMPLE_SOUNDCARD + help + Say Y or M if you want to add support for HifiBerry DSP-DAC. + +config SND_BCM2708_SOC_HIFIBERRY_DIGI + tristate "Support for HifiBerry Digi" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_WM8804 + help + Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board. + +config SND_BCM2708_SOC_HIFIBERRY_AMP + tristate "Support for the HifiBerry Amp" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_TAS5713 + select SND_RPI_SIMPLE_SOUNDCARD + help + Say Y or M if you want to add support for the HifiBerry Amp amplifier board. + -+ config SND_BCM2708_SOC_PIFI_40 ++config SND_BCM2708_SOC_PIFI_40 + tristate "Support for the PiFi-40 amp" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_TAS571X + select SND_PIFI_40 + help @@ -184153,7 +240707,6 @@ + +config SND_BCM2708_SOC_RPI_CIRRUS + tristate "Support for Cirrus Logic Audio Card" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_WM5102 + select SND_SOC_WM8804 + help @@ -184162,7 +240715,6 @@ + +config SND_BCM2708_SOC_RPI_DAC + tristate "Support for RPi-DAC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM1794A + select SND_RPI_SIMPLE_SOUNDCARD + help @@ -184170,14 +240722,12 @@ + +config SND_BCM2708_SOC_RPI_PROTO + tristate "Support for Rpi-PROTO" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -+ select SND_SOC_WM8731 ++ select SND_SOC_WM8731_I2C + help + Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731). + +config SND_BCM2708_SOC_JUSTBOOM_BOTH + tristate "Support for simultaneous JustBoom Digi and JustBoom DAC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_WM8804 + select SND_SOC_PCM512x + help @@ -184189,14 +240739,12 @@ + +config SND_BCM2708_SOC_JUSTBOOM_DAC + tristate "Support for JustBoom DAC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x + help + Say Y or M if you want to add support for JustBoom DAC. + +config SND_BCM2708_SOC_JUSTBOOM_DIGI + tristate "Support for JustBoom Digi" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_WM8804 + select SND_RPI_WM8804_SOUNDCARD + help @@ -184204,21 +240752,18 @@ + +config SND_BCM2708_SOC_IQAUDIO_CODEC + tristate "Support for IQaudIO-CODEC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_DA7213 + help + Say Y or M if you want to add support for IQaudIO-CODEC. + +config SND_BCM2708_SOC_IQAUDIO_DAC + tristate "Support for IQaudIO-DAC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x_I2C + help + Say Y or M if you want to add support for IQaudIO-DAC. + +config SND_BCM2708_SOC_IQAUDIO_DIGI + tristate "Support for IQAudIO Digi" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_WM8804 + select SND_RPI_WM8804_SOUNDCARD + help @@ -184226,14 +240771,12 @@ + +config SND_BCM2708_SOC_I_SABRE_Q2M + tristate "Support for Audiophonics I-Sabre Q2M DAC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_I_SABRE_CODEC + help + Say Y or M if you want to add support for Audiophonics I-SABRE Q2M DAC + +config SND_BCM2708_SOC_ADAU1977_ADC + tristate "Support for ADAU1977 ADC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_ADAU1977_I2C + select SND_RPI_SIMPLE_SOUNDCARD + help @@ -184241,35 +240784,30 @@ + +config SND_AUDIOINJECTOR_PI_SOUNDCARD + tristate "Support for audioinjector.net Pi add on soundcard" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -+ select SND_SOC_WM8731 ++ select SND_SOC_WM8731_I2C + help + Say Y or M if you want to add support for audioinjector.net Pi Hat + +config SND_AUDIOINJECTOR_OCTO_SOUNDCARD + tristate "Support for audioinjector.net Octo channel (Hat) soundcard" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_CS42XX8_I2C + help + Say Y or M if you want to add support for audioinjector.net octo add on + +config SND_AUDIOINJECTOR_ISOLATED_SOUNDCARD + tristate "Support for audioinjector.net isolated DAC and ADC soundcard" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_CS4271_I2C + help + Say Y or M if you want to add support for audioinjector.net isolated soundcard + +config SND_AUDIOSENSE_PI + tristate "Support for AudioSense Add-On Soundcard" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_TLV320AIC32X4_I2C + help + Say Y or M if you want to add support for tlv320aic32x4 add-on + +config SND_DIGIDAC1_SOUNDCARD + tristate "Support for Red Rocks Audio DigiDAC1" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_WM8804 + select SND_SOC_WM8741 + help @@ -184277,42 +240815,37 @@ + +config SND_BCM2708_SOC_DIONAUDIO_LOCO + tristate "Support for Dion Audio LOCO DAC-AMP" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM5102a + help + Say Y or M if you want to add support for Dion Audio LOCO. + +config SND_BCM2708_SOC_DIONAUDIO_LOCO_V2 + tristate "Support for Dion Audio LOCO-V2 DAC-AMP" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM5122 + help + Say Y or M if you want to add support for Dion Audio LOCO-V2. + +config SND_BCM2708_SOC_ALLO_PIANO_DAC + tristate "Support for Allo Piano DAC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x_I2C + help + Say Y or M if you want to add support for Allo Piano DAC. + +config SND_BCM2708_SOC_ALLO_PIANO_DAC_PLUS + tristate "Support for Allo Piano DAC Plus" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x_I2C + help + Say Y or M if you want to add support for Allo Piano DAC Plus. + +config SND_BCM2708_SOC_ALLO_BOSS_DAC + tristate "Support for Allo Boss DAC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x_I2C ++ select COMMON_CLK_HIFIBERRY_DACPRO + help + Say Y or M if you want to add support for Allo Boss DAC. + +config SND_BCM2708_SOC_ALLO_BOSS2_DAC + tristate "Support for Allo Boss2 DAC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + depends on I2C + select REGMAP_I2C + select SND_AUDIO_GRAPH_CARD @@ -184321,7 +240854,6 @@ + +config SND_BCM2708_SOC_ALLO_DIGIONE + tristate "Support for Allo DigiOne" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_WM8804 + select SND_RPI_WM8804_SOUNDCARD + help @@ -184329,7 +240861,6 @@ + +config SND_BCM2708_SOC_ALLO_KATANA_DAC + tristate "Support for Allo Katana DAC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + depends on I2C + select REGMAP_I2C + select SND_AUDIO_GRAPH_CARD @@ -184338,14 +240869,12 @@ + +config SND_BCM2708_SOC_FE_PI_AUDIO + tristate "Support for Fe-Pi-Audio" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_SGTL5000 + help + Say Y or M if you want to add support for Fe-Pi-Audio. + +config SND_PISOUND + tristate "Support for Blokas Labs pisound" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_RAWMIDI + help + Say Y or M if you want to add support for Blokas Labs pisound. @@ -184360,11 +240889,17 @@ + help + Say Y or M if you want to add support for the Raspberry Pi + generic driver for WM8804 based soundcards. ++ ++config SND_DACBERRY400 ++ tristate "Support for DACBERRY400 Soundcard" ++ select SND_SOC_TLV320AIC3X_I2C ++ help ++ Say Y or M if you want to add support for tlv320aic3x add-on diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 7c2d7899603b..1efb734f1c86 100644 +index 7c2d7899603b..46d1ece070a3 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -12,4 +12,71 @@ obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o +@@ -12,4 +12,73 @@ obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o # BCM63XX Platform Support snd-soc-63xx-objs := bcm63xx-i2s-whistler.o bcm63xx-pcm-whistler.o @@ -184406,6 +240941,7 @@ +snd-soc-rpi-wm8804-soundcard-objs := rpi-wm8804-soundcard.o +snd-soc-pifi-40-objs := pifi-40.o +snd-soc-chipdip-dac-objs := chipdip-dac.o ++snd-soc-dacberry400-objs := dacberry400.o + +obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o +obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o @@ -184438,12 +240974,13 @@ +obj-$(CONFIG_SND_RPI_WM8804_SOUNDCARD) += snd-soc-rpi-wm8804-soundcard.o +obj-$(CONFIG_SND_BCM2708_SOC_PIFI_40) += snd-soc-pifi-40.o +obj-$(CONFIG_SND_BCM2708_SOC_CHIPDIP_DAC) += snd-soc-chipdip-dac.o ++obj-$(CONFIG_SND_DACBERRY400) += snd-soc-dacberry400.o diff --git a/sound/soc/bcm/allo-boss-dac.c b/sound/soc/bcm/allo-boss-dac.c new file mode 100644 -index 000000000000..22564e895bba +index 000000000000..cd817730ab40 --- /dev/null +++ b/sound/soc/bcm/allo-boss-dac.c -@@ -0,0 +1,456 @@ +@@ -0,0 +1,468 @@ +/* + * ALSA ASoC Machine Driver for Allo Boss DAC + * @@ -184720,24 +241257,35 @@ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int channels = params_channels(params); -+ int width = snd_pcm_format_physical_width(params_format(params)); ++ int width = snd_pcm_format_width(params_format(params)); ++ struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; ++ struct snd_soc_card *card = rtd->card; + -+ if (snd_soc_allo_boss_master) { -+ struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; ++ /* Mute before changing sample rate */ ++ snd_allo_boss_gpio_mute(card); + -+ snd_allo_boss_set_sclk(component, -+ params_rate(params)); ++ if (snd_soc_allo_boss_master) { ++ snd_allo_boss_set_sclk(component, params_rate(params)); + -+ ret = snd_allo_boss_update_rate_den( -+ substream, params); ++ ret = snd_allo_boss_update_rate_den(substream, params); + if (ret) -+ return ret; ++ goto error; + } + + ret = snd_soc_dai_set_bclk_ratio(asoc_rtd_to_cpu(rtd, 0), channels * width); ++ + if (ret) -+ return ret; ++ goto error; ++ + ret = snd_soc_dai_set_bclk_ratio(asoc_rtd_to_codec(rtd, 0), channels * width); ++ ++ if (ret) ++ goto error; ++ ++ /* Unmute after setting parameters or having an error */ ++error: ++ snd_allo_boss_gpio_unmute(card); ++ + return ret; +} + @@ -184876,7 +241424,8 @@ +static int snd_allo_boss_remove(struct platform_device *pdev) +{ + snd_allo_boss_gpio_mute(&snd_allo_boss); -+ return snd_soc_unregister_card(&snd_allo_boss); ++ snd_soc_unregister_card(&snd_allo_boss); ++ return 0; +} + +static const struct of_device_id snd_allo_boss_of_match = { @@ -184902,10 +241451,10 @@ +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/allo-boss2-dac.c b/sound/soc/bcm/allo-boss2-dac.c new file mode 100644 -index 000000000000..5ad7f16964aa +index 000000000000..20dededd9196 --- /dev/null +++ b/sound/soc/bcm/allo-boss2-dac.c -@@ -0,0 +1,1133 @@ +@@ -0,0 +1,1130 @@ +/* + * Driver for the ALLO KATANA CODEC + * @@ -185526,30 +242075,30 @@ + case CS43130_ASP_PCM_DAI: + case CS43130_ASP_DOP_DAI: + regmap_write(cs43130->regmap, CS43130_ASP_DEN_1, -+ (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >> ++ (clk_gen->v.denominator & CS43130_SP_M_LSB_DATA_MASK) >> + CS43130_SP_M_LSB_DATA_SHIFT); + regmap_write(cs43130->regmap, CS43130_ASP_DEN_2, -+ (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >> ++ (clk_gen->v.denominator & CS43130_SP_M_MSB_DATA_MASK) >> + CS43130_SP_M_MSB_DATA_SHIFT); + regmap_write(cs43130->regmap, CS43130_ASP_NUM_1, -+ (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >> ++ (clk_gen->v.numerator & CS43130_SP_N_LSB_DATA_MASK) >> + CS43130_SP_N_LSB_DATA_SHIFT); + regmap_write(cs43130->regmap, CS43130_ASP_NUM_2, -+ (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >> ++ (clk_gen->v.numerator & CS43130_SP_N_MSB_DATA_MASK) >> + CS43130_SP_N_MSB_DATA_SHIFT); + break; + case CS43130_XSP_DOP_DAI: + regmap_write(cs43130->regmap, CS43130_XSP_DEN_1, -+ (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >> ++ (clk_gen->v.denominator & CS43130_SP_M_LSB_DATA_MASK) >> + CS43130_SP_M_LSB_DATA_SHIFT); + regmap_write(cs43130->regmap, CS43130_XSP_DEN_2, -+ (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >> ++ (clk_gen->v.denominator & CS43130_SP_M_MSB_DATA_MASK) >> + CS43130_SP_M_MSB_DATA_SHIFT); + regmap_write(cs43130->regmap, CS43130_XSP_NUM_1, -+ (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >> ++ (clk_gen->v.numerator & CS43130_SP_N_LSB_DATA_MASK) >> + CS43130_SP_N_LSB_DATA_SHIFT); + regmap_write(cs43130->regmap, CS43130_XSP_NUM_2, -+ (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >> ++ (clk_gen->v.numerator & CS43130_SP_N_MSB_DATA_MASK) >> + CS43130_SP_N_MSB_DATA_SHIFT); + break; + default: @@ -185863,7 +242412,6 @@ + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, -+ .non_legacy_dai_naming = 1, +}; + +static const struct regmap_config cs43130_regmap = { @@ -185937,8 +242485,7 @@ +} + + -+static int allo_cs43130_component_probe(struct i2c_client *i2c, -+ const struct i2c_device_id *id) ++static int allo_cs43130_component_probe(struct i2c_client *i2c) +{ + struct regmap *regmap; + struct regmap_config config = cs43130_regmap; @@ -186006,10 +242553,9 @@ + return 0; +} + -+static int allo_cs43130_component_remove(struct i2c_client *i2c) ++static void allo_cs43130_component_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_component(&i2c->dev); -+ return 0; +} + +static const struct i2c_device_id allo_cs43130_component_id = { @@ -186041,10 +242587,10 @@ +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/allo-katana-codec.c b/sound/soc/bcm/allo-katana-codec.c new file mode 100644 -index 000000000000..b0aebd40fe5e +index 000000000000..88d312adfbe4 --- /dev/null +++ b/sound/soc/bcm/allo-katana-codec.c -@@ -0,0 +1,388 @@ +@@ -0,0 +1,386 @@ +/* + * Driver for the ALLO KATANA CODEC + * @@ -186360,8 +242906,7 @@ + .cache_type = REGCACHE_RBTREE, +}; + -+static int allo_katana_component_probe(struct i2c_client *i2c, -+ const struct i2c_device_id *id) ++static int allo_katana_component_probe(struct i2c_client *i2c) +{ + struct regmap *regmap; + struct regmap_config config = katana_codec_regmap; @@ -186400,10 +242945,9 @@ + return 0; +} + -+static int allo_katana_component_remove(struct i2c_client *i2c) ++static void allo_katana_component_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_component(&i2c->dev); -+ return 0; +} + +static const struct i2c_device_id allo_katana_component_id = { @@ -186435,10 +242979,10 @@ +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/allo-piano-dac-plus.c b/sound/soc/bcm/allo-piano-dac-plus.c new file mode 100644 -index 000000000000..fd0fe58421b0 +index 000000000000..df167325a85e --- /dev/null +++ b/sound/soc/bcm/allo-piano-dac-plus.c -@@ -0,0 +1,1063 @@ +@@ -0,0 +1,1064 @@ +/* + * ALSA ASoC Machine Driver for Allo Piano DAC Plus Subwoofer + * @@ -186504,7 +243048,7 @@ + "2.2", +}; + -+static const SOC_ENUM_SINGLE_DECL(allo_piano_mode_enum, ++static SOC_ENUM_SINGLE_DECL(allo_piano_mode_enum, + 0, 0, allo_piano_mode_texts); + +static const char * const allo_piano_dual_mode_texts = { @@ -186513,7 +243057,7 @@ + "Dual-Stereo", +}; + -+static const SOC_ENUM_SINGLE_DECL(allo_piano_dual_mode_enum, ++static SOC_ENUM_SINGLE_DECL(allo_piano_dual_mode_enum, + 0, 0, allo_piano_dual_mode_texts); + +static const char * const allo_piano_dsp_low_pass_texts = { @@ -186534,7 +243078,7 @@ + "200", +}; + -+static const SOC_ENUM_SINGLE_DECL(allo_piano_enum, ++static SOC_ENUM_SINGLE_DECL(allo_piano_enum, + 0, 0, allo_piano_dsp_low_pass_texts); + +static int __snd_allo_piano_dsp_program(struct snd_soc_pcm_runtime *rtd, @@ -186594,7 +243138,7 @@ + PCM512x_MUTE, P_DAC_UNMUTE); + } + -+ for (dac = 0; dac < rtd->num_codecs; dac++) { ++ for (dac = 0; dac < rtd->dai_link->num_codecs; dac++) { + struct dsp_code *dsp_code_read; + int i = 1; + @@ -187477,7 +244021,8 @@ + + kfree(&card->drvdata); + snd_allo_piano_gpio_mute(&snd_allo_piano_dac); -+ return snd_soc_unregister_card(&snd_allo_piano_dac); ++ snd_soc_unregister_card(&snd_allo_piano_dac); ++ return 0; +} + +static const struct of_device_id snd_allo_piano_dac_of_match = { @@ -187632,7 +244177,7 @@ +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/audioinjector-isolated-soundcard.c b/sound/soc/bcm/audioinjector-isolated-soundcard.c new file mode 100644 -index 000000000000..e3cf29eef812 +index 000000000000..127d49691935 --- /dev/null +++ b/sound/soc/bcm/audioinjector-isolated-soundcard.c @@ -0,0 +1,183 @@ @@ -187728,7 +244273,7 @@ + .stream_name = "AI-HIFI", + .ops = &audioinjector_isolated_ops, + .init = audioinjector_isolated_dai_init, -+ .symmetric_rates = 1, ++ .symmetric_rate = 1, + .symmetric_channels = 1, + .dai_fmt = SND_SOC_DAIFMT_CBM_CFM|SND_SOC_DAIFMT_I2S|SND_SOC_DAIFMT_NB_NF, + SND_SOC_DAILINK_REG(audioinjector_isolated), @@ -187821,10 +244366,10 @@ +MODULE_ALIAS("platform:audioinjector-isolated-soundcard"); diff --git a/sound/soc/bcm/audioinjector-octo-soundcard.c b/sound/soc/bcm/audioinjector-octo-soundcard.c new file mode 100644 -index 000000000000..2da73a46c0f8 +index 000000000000..b6395f04d1e3 --- /dev/null +++ b/sound/soc/bcm/audioinjector-octo-soundcard.c -@@ -0,0 +1,346 @@ +@@ -0,0 +1,347 @@ +/* + * ASoC Driver for AudioInjector Pi octo channel soundcard (hat) + * @@ -187970,40 +244515,40 @@ + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (!non_stop_clocks) + break; -+ /* fall through */ ++ fallthrough; + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + switch (audioinjector_octo_rate) { + case 96000: + __assign_bit(3, mult, 1); -+ /* fall through */ ++ fallthrough; + case 88200: + __assign_bit(1, mult, 1); + __assign_bit(2, mult, 1); + break; + case 48000: + __assign_bit(3, mult, 1); -+ /* fall through */ ++ fallthrough; + case 44100: + __assign_bit(2, mult, 1); + break; + case 32000: + __assign_bit(3, mult, 1); -+ /* fall through */ ++ fallthrough; + case 29400: + __assign_bit(0, mult, 1); + __assign_bit(1, mult, 1); + break; + case 24000: + __assign_bit(3, mult, 1); -+ /* fall through */ ++ fallthrough; + case 22050: + __assign_bit(1, mult, 1); + break; + case 16000: + __assign_bit(3, mult, 1); -+ /* fall through */ ++ fallthrough; + case 14700: + __assign_bit(0, mult, 1); + break; @@ -188041,7 +244586,7 @@ + .stream_name = "AudioInject-HIFI", + .ops = &audioinjector_octo_ops, + .init = audioinjector_octo_dai_init, -+ .symmetric_rates = 1, ++ .symmetric_rate = 1, + .symmetric_channels = 1, + SND_SOC_DAILINK_REG(audioinjector_octo), + }, @@ -188079,6 +244624,7 @@ + +static struct snd_soc_card snd_soc_audioinjector_octo = { + .name = "audioinjector-octo-soundcard", ++ .owner = THIS_MODULE, + .dai_link = audioinjector_octo_dai, + .num_links = ARRAY_SIZE(audioinjector_octo_dai), + @@ -188173,10 +244719,10 @@ +MODULE_ALIAS("platform:audioinjector-octo-soundcard"); diff --git a/sound/soc/bcm/audioinjector-pi-soundcard.c b/sound/soc/bcm/audioinjector-pi-soundcard.c new file mode 100644 -index 000000000000..3f24fa739081 +index 000000000000..ad337201c558 --- /dev/null +++ b/sound/soc/bcm/audioinjector-pi-soundcard.c -@@ -0,0 +1,187 @@ +@@ -0,0 +1,189 @@ +/* + * ASoC Driver for AudioInjector Pi add on soundcard + * @@ -188337,9 +244883,11 @@ + } + } + -+ if ((ret = devm_snd_soc_register_card(&pdev->dev, card))) { -+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); -+ } ++ if ((ret = devm_snd_soc_register_card(&pdev->dev, card))) ++ return dev_err_probe(&pdev->dev, ret, "%s\n", __func__); ++ ++ dev_info(&pdev->dev, "successfully loaded\n"); ++ + return ret; +} + @@ -188366,7 +244914,7 @@ + diff --git a/sound/soc/bcm/audiosense-pi.c b/sound/soc/bcm/audiosense-pi.c new file mode 100644 -index 000000000000..b76d97488a44 +index 000000000000..870d24bf67a3 --- /dev/null +++ b/sound/soc/bcm/audiosense-pi.c @@ -0,0 +1,248 @@ @@ -188591,8 +245139,8 @@ +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + -+ return snd_soc_unregister_card(card); -+ ++ snd_soc_unregister_card(card); ++ return 0; +} + +static const struct of_device_id audiosense_pi_card_of_match = { @@ -188618,6 +245166,59 @@ +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:audiosense-pi"); + +diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c +index 9bda6499e66e..2d0fe53245f0 100644 +--- a/sound/soc/bcm/bcm2835-i2s.c ++++ b/sound/soc/bcm/bcm2835-i2s.c +@@ -30,7 +30,6 @@ + #include <linux/init.h> + #include <linux/io.h> + #include <linux/module.h> +-#include <linux/of_address.h> + #include <linux/slab.h> + + #include <sound/core.h> +@@ -830,8 +829,7 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) + struct bcm2835_i2s_dev *dev; + int ret; + void __iomem *base; +- const __be32 *addr; +- dma_addr_t dma_base; ++ struct resource *res; + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), + GFP_KERNEL); +@@ -846,7 +844,7 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) + "could not get clk\n"); + + /* Request ioarea */ +- base = devm_platform_ioremap_resource(pdev, 0); ++ base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(base)) + return PTR_ERR(base); + +@@ -855,19 +853,11 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) + if (IS_ERR(dev->i2s_regmap)) + return PTR_ERR(dev->i2s_regmap); + +- /* Set the DMA address - we have to parse DT ourselves */ +- addr = of_get_address(pdev->dev.of_node, 0, NULL, NULL); +- if (!addr) { +- dev_err(&pdev->dev, "could not get DMA-register address\n"); +- return -EINVAL; +- } +- dma_base = be32_to_cpup(addr); +- + dev->dma_dataSNDRV_PCM_STREAM_PLAYBACK.addr = +- dma_base + BCM2835_I2S_FIFO_A_REG; ++ res->start + BCM2835_I2S_FIFO_A_REG; + + dev->dma_dataSNDRV_PCM_STREAM_CAPTURE.addr = +- dma_base + BCM2835_I2S_FIFO_A_REG; ++ res->start + BCM2835_I2S_FIFO_A_REG; + + /* Set the bus width */ + dev->dma_dataSNDRV_PCM_STREAM_PLAYBACK.addr_width = diff --git a/sound/soc/bcm/chipdip-dac.c b/sound/soc/bcm/chipdip-dac.c new file mode 100644 index 000000000000..6cb53692b3c5 @@ -188899,6 +245500,271 @@ +MODULE_AUTHOR("Evgenij Sapunov <evgenij.sapunov@chipdip.ru>"); +MODULE_DESCRIPTION("ASoC Driver for ChipDip DAC"); +MODULE_LICENSE("GPL v2"); +diff --git a/sound/soc/bcm/dacberry400.c b/sound/soc/bcm/dacberry400.c +new file mode 100644 +index 000000000000..284459320102 +--- /dev/null ++++ b/sound/soc/bcm/dacberry400.c +@@ -0,0 +1,259 @@ ++/* ++ * ASoC Driver for Dacberry400 soundcard ++ * Author: ++ * Ashish Vara<ashishhvara@gmail.com> ++ * Copyright 2022 ++ * ++ * 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/module.h> ++#include <linux/gpio/consumer.h> ++#include <linux/platform_device.h> ++#include <sound/core.h> ++#include <sound/pcm.h> ++#include <sound/pcm_params.h> ++#include <sound/soc.h> ++#include <sound/jack.h> ++#include <linux/i2c.h> ++#include <linux/acpi.h> ++#include <linux/slab.h> ++#include "../sound/soc/codecs/tlv320aic3x.h" ++ ++static const struct snd_kcontrol_new dacberry400_controls = { ++ SOC_DAPM_PIN_SWITCH("MIC Jack"), ++ SOC_DAPM_PIN_SWITCH("Line In"), ++ SOC_DAPM_PIN_SWITCH("Line Out"), ++ SOC_DAPM_PIN_SWITCH("Headphone Jack"), ++}; ++ ++static const struct snd_soc_dapm_widget dacberry400_widgets = { ++ SND_SOC_DAPM_HP("Headphone Jack", NULL), ++ SND_SOC_DAPM_MIC("MIC Jack", NULL), ++ SND_SOC_DAPM_LINE("Line In", NULL), ++ SND_SOC_DAPM_LINE("Line Out", NULL), ++}; ++ ++static const struct snd_soc_dapm_route dacberry400_audio_map = { ++ {"Headphone Jack", NULL, "HPLOUT"}, ++ {"Headphone Jack", NULL, "HPROUT"}, ++ ++ {"LINE1L", NULL, "Line In"}, ++ {"LINE1R", NULL, "Line In"}, ++ ++ {"Line Out", NULL, "LLOUT"}, ++ {"Line Out", NULL, "RLOUT"}, ++ ++ {"MIC3L", NULL, "MIC Jack"}, ++ {"MIC3R", NULL, "MIC Jack"}, ++}; ++ ++static int snd_rpi_dacberry400_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); ++ struct snd_soc_component *component = codec_dai->component; ++ int ret; ++ ++ ret = snd_soc_dai_set_sysclk(codec_dai, 2, 12000000, ++ SND_SOC_CLOCK_OUT); ++ ++ if (ret && ret != -ENOTSUPP) ++ goto err; ++ ++ snd_soc_component_write(component, HPRCOM_CFG, 0x20); ++ snd_soc_component_write(component, DACL1_2_HPLOUT_VOL, 0x80); ++ snd_soc_component_write(component, DACR1_2_HPROUT_VOL, 0x80); ++err: ++ return ret; ++} ++ ++static int snd_rpi_dacberry400_set_bias_level(struct snd_soc_card *card, ++ struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) ++{ ++ struct snd_soc_pcm_runtime *rtd; ++ struct snd_soc_dai *codec_dai; ++ struct snd_soc_component *component; ++ struct dacberry_priv *aic3x; ++ u8 hpcom_reg = 0; ++ ++ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link0); ++ codec_dai = asoc_rtd_to_codec(rtd, 0); ++ component = codec_dai->component; ++ aic3x = snd_soc_component_get_drvdata(component); ++ if (dapm->dev != codec_dai->dev) ++ return 0; ++ ++ switch (level) { ++ case SND_SOC_BIAS_PREPARE: ++ if (dapm->bias_level != SND_SOC_BIAS_STANDBY) ++ break; ++ /* UNMUTE ADC/DAC */ ++ hpcom_reg = snd_soc_component_read(component, HPLCOM_CFG); ++ snd_soc_component_write(component, HPLCOM_CFG, hpcom_reg | 0x20); ++ snd_soc_component_write(component, LINE1R_2_RADC_CTRL, 0x04); ++ snd_soc_component_write(component, LINE1L_2_LADC_CTRL, 0x04); ++ snd_soc_component_write(component, LADC_VOL, 0x00); ++ snd_soc_component_write(component, RADC_VOL, 0x00); ++ pr_info("%s: unmute ADC/DAC\n", __func__); ++ break; ++ ++ case SND_SOC_BIAS_STANDBY: ++ if (dapm->bias_level != SND_SOC_BIAS_PREPARE) ++ break; ++ /* MUTE ADC/DAC */ ++ snd_soc_component_write(component, LDAC_VOL, 0x80); ++ snd_soc_component_write(component, RDAC_VOL, 0x80); ++ snd_soc_component_write(component, LADC_VOL, 0x80); ++ snd_soc_component_write(component, RADC_VOL, 0x80); ++ snd_soc_component_write(component, LINE1R_2_RADC_CTRL, 0x00); ++ snd_soc_component_write(component, LINE1L_2_LADC_CTRL, 0x00); ++ snd_soc_component_write(component, HPLCOM_CFG, 0x00); ++ pr_info("%s: mute ADC/DAC\n", __func__); ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static int snd_rpi_dacberry400_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ int ret = 0; ++ u8 data; ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); ++ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); ++ struct snd_soc_component *component = codec_dai->component; ++ int fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000; ++ int channels = params_channels(params); ++ int width = 32; ++ u8 clock = 0; ++ ++ data = (LDAC2LCH | RDAC2RCH); ++ data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000; ++ if (params_rate(params) >= 64000) ++ data |= DUAL_RATE_MODE; ++ ret = snd_soc_component_write(component, 0x7, data); ++ width = params_width(params); ++ ++ clock = snd_soc_component_read(component, 2); ++ ++ ret = snd_soc_dai_set_bclk_ratio(cpu_dai, channels*width); ++ ++ return ret; ++} ++ ++static const struct snd_soc_ops snd_rpi_dacberry400_ops = { ++ .hw_params = snd_rpi_dacberry400_hw_params, ++}; ++ ++ ++SND_SOC_DAILINK_DEFS(rpi_dacberry400, ++ DAILINK_COMP_ARRAY(COMP_CPU("bcm2835-i2s.0")), ++ DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x.1-0018", "tlv320aic3x-hifi")), ++ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2835-i2s.0"))); ++ ++static struct snd_soc_dai_link snd_rpi_dacberry400_dai = { ++{ ++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ .init = snd_rpi_dacberry400_init, ++ .ops = &snd_rpi_dacberry400_ops, ++ .symmetric_rate = 1, ++ SND_SOC_DAILINK_REG(rpi_dacberry400), ++}, ++}; ++ ++static struct snd_soc_card snd_rpi_dacberry400 = { ++ .owner = THIS_MODULE, ++ .dai_link = snd_rpi_dacberry400_dai, ++ .num_links = ARRAY_SIZE(snd_rpi_dacberry400_dai), ++ .controls = dacberry400_controls, ++ .num_controls = ARRAY_SIZE(dacberry400_controls), ++ .dapm_widgets = dacberry400_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(dacberry400_widgets), ++ .dapm_routes = dacberry400_audio_map, ++ .num_dapm_routes = ARRAY_SIZE(dacberry400_audio_map), ++ .set_bias_level = snd_rpi_dacberry400_set_bias_level, ++}; ++ ++static int snd_rpi_dacberry400_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ snd_rpi_dacberry400.dev = &pdev->dev; ++ ++ if (pdev->dev.of_node) { ++ struct device_node *i2s_node; ++ struct snd_soc_card *card = &snd_rpi_dacberry400; ++ struct snd_soc_dai_link *dai = &snd_rpi_dacberry400_dai0; ++ ++ i2s_node = of_parse_phandle(pdev->dev.of_node, ++ "i2s-controller", 0); ++ if (i2s_node) { ++ dai->cpus->dai_name = NULL; ++ dai->cpus->of_node = i2s_node; ++ dai->platforms->name = NULL; ++ dai->platforms->of_node = i2s_node; ++ of_node_put(i2s_node); ++ } ++ ++ if (of_property_read_string(pdev->dev.of_node, "card_name", ++ &card->name)) ++ card->name = "tlvaudioCODEC"; ++ ++ if (of_property_read_string(pdev->dev.of_node, "dai_name", ++ &dai->name)) ++ dai->name = "tlvaudio CODEC"; ++ ++ } ++ ++ ret = snd_soc_register_card(&snd_rpi_dacberry400); ++ if (ret) { ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, ++ "snd_soc_register_card() failed: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int snd_rpi_dacberry400_remove(struct platform_device *pdev) ++{ ++ snd_soc_unregister_card(&snd_rpi_dacberry400); ++ return 0; ++} ++ ++static const struct of_device_id dacberry400_match_id = { ++ { .compatible = "osaelectronics,dacberry400",}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, dacberry400_match_id); ++ ++static struct platform_driver snd_rpi_dacberry400_driver = { ++ .driver = { ++ .name = "snd-rpi-dacberry400", ++ .owner = THIS_MODULE, ++ .of_match_table = dacberry400_match_id, ++ }, ++ .probe = snd_rpi_dacberry400_probe, ++ .remove = snd_rpi_dacberry400_remove, ++}; ++ ++module_platform_driver(snd_rpi_dacberry400_driver); ++ ++MODULE_AUTHOR("Ashish Vara"); ++MODULE_DESCRIPTION("Dacberry400 sound card driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:dacberry400"); ++MODULE_SOFTDEP("pre: snd-soc-tlv320aic3x"); diff --git a/sound/soc/bcm/digidac1-soundcard.c b/sound/soc/bcm/digidac1-soundcard.c new file mode 100644 index 000000000000..4649c6f75c59 @@ -189451,7 +246317,7 @@ +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/dionaudio_loco.c b/sound/soc/bcm/dionaudio_loco.c new file mode 100644 -index 000000000000..b19a06afb6af +index 000000000000..48deb4cd3c8e --- /dev/null +++ b/sound/soc/bcm/dionaudio_loco.c @@ -0,0 +1,117 @@ @@ -189489,7 +246355,7 @@ + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + + unsigned int sample_bits = -+ snd_pcm_format_physical_width(params_format(params)); ++ snd_pcm_format_width(params_format(params)); + + return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2); +} @@ -189734,7 +246600,7 @@ +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/googlevoicehat-codec.c b/sound/soc/bcm/googlevoicehat-codec.c new file mode 100644 -index 000000000000..67e937425cff +index 000000000000..a2015896966c --- /dev/null +++ b/sound/soc/bcm/googlevoicehat-codec.c @@ -0,0 +1,214 @@ @@ -189842,14 +246708,14 @@ + return 0; + + dev_dbg(dai->dev, "CMD %d", cmd); -+ dev_dbg(dai->dev, "Playback Active %d", dai->stream_activeSNDRV_PCM_STREAM_PLAYBACK); -+ dev_dbg(dai->dev, "Capture Active %d", dai->stream_activeSNDRV_PCM_STREAM_CAPTURE); ++ dev_dbg(dai->dev, "Playback Active %d", dai->streamSNDRV_PCM_STREAM_PLAYBACK.active); ++ dev_dbg(dai->dev, "Capture Active %d", dai->streamSNDRV_PCM_STREAM_CAPTURE.active); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -+ if (dai->stream_activeSNDRV_PCM_STREAM_PLAYBACK) { ++ if (dai->streamSNDRV_PCM_STREAM_PLAYBACK.active) { + dev_info(dai->dev, "Enabling audio amp...\n"); + queue_delayed_work( + system_power_efficient_wq, @@ -189860,7 +246726,7 @@ + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+ if (dai->stream_activeSNDRV_PCM_STREAM_PLAYBACK) { ++ if (dai->streamSNDRV_PCM_STREAM_PLAYBACK.active) { + cancel_delayed_work(&voicehat->enable_sdmode_work); + dev_info(dai->dev, "Disabling audio amp...\n"); + gpiod_set_value(voicehat->sdmode_gpio, 0); @@ -189891,7 +246757,7 @@ + .formats = SNDRV_PCM_FMTBIT_S32_LE + }, + .ops = &voicehat_dai_ops, -+ .symmetric_rates = 1 ++ .symmetric_rate = 1 +}; + +#ifdef CONFIG_OF @@ -189954,10 +246820,10 @@ +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/hifiberry_dacplus.c b/sound/soc/bcm/hifiberry_dacplus.c new file mode 100644 -index 000000000000..1d8985468be4 +index 000000000000..0cd7979dee54 --- /dev/null +++ b/sound/soc/bcm/hifiberry_dacplus.c -@@ -0,0 +1,527 @@ +@@ -0,0 +1,560 @@ +/* + * ASoC Driver for HiFiBerry DAC+ / DAC Pro / AMP100 + * @@ -190018,10 +246884,21 @@ +static bool auto_mute; +static int mute_ext_ctl; +static int mute_ext; ++static bool tas_device; +static struct gpio_desc *snd_mute_gpio; +static struct gpio_desc *snd_reset_gpio; +static struct snd_soc_card snd_rpi_hifiberry_dacplus; + ++static const u32 master_dai_rates = { ++ 44100, 48000, 88200, 96000, ++ 176400, 192000, 352800, 384000, ++}; ++ ++static const struct snd_pcm_hw_constraint_list constraints_master = { ++ .count = ARRAY_SIZE(master_dai_rates), ++ .list = master_dai_rates, ++}; ++ +static int snd_rpi_hifiberry_dacplus_mute_set(int mute) +{ + gpiod_set_value_cansleep(snd_mute_gpio, mute); @@ -190157,8 +247034,13 @@ + if (snd_rpi_hifiberry_is_dacpro) { + struct snd_soc_dai_link *dai = rtd->dai_link; + -+ dai->name = "HiFiBerry DAC+ Pro"; -+ dai->stream_name = "HiFiBerry DAC+ Pro HiFi"; ++ if (tas_device) { ++ dai->name = "HiFiBerry AMP4 Pro"; ++ dai->stream_name = "HiFiBerry AMP4 Pro HiFi"; ++ } else { ++ dai->name = "HiFiBerry DAC+ Pro"; ++ dai->stream_name = "HiFiBerry DAC+ Pro HiFi"; ++ } + dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM; + @@ -190239,13 +247121,11 @@ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int channels = params_channels(params); -+ int width = 32; ++ int width = snd_pcm_format_width(params_format(params)); + + if (snd_rpi_hifiberry_is_dacpro) { + struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; + -+ width = snd_pcm_format_physical_width(params_format(params)); -+ + snd_rpi_hifiberry_dacplus_set_sclk(component, + params_rate(params)); + @@ -190265,6 +247145,18 @@ +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; ++ int ret; ++ ++ if (tas_device && !slave) { ++ ret = snd_pcm_hw_constraint_list(substream->runtime, 0, ++ SNDRV_PCM_HW_PARAM_RATE, ++ &constraints_master); ++ if (ret < 0) { ++ dev_err(rtd->card->dev, ++ "Cannot apply constraints for sample rates\n"); ++ return ret; ++ } ++ } + + if (auto_mute) + gpiod_set_value_cansleep(snd_mute_gpio, 0); @@ -190286,7 +247178,7 @@ +} + +/* machine stream operations */ -+static struct snd_soc_ops snd_rpi_hifiberry_dacplus_ops = { ++static const struct snd_soc_ops snd_rpi_hifiberry_dacplus_ops = { + .hw_params = snd_rpi_hifiberry_dacplus_hw_params, + .startup = snd_rpi_hifiberry_dacplus_startup, + .shutdown = snd_rpi_hifiberry_dacplus_shutdown, @@ -190356,6 +247248,7 @@ + struct snd_soc_card *card = &snd_rpi_hifiberry_dacplus; + int len; + struct device_node *tpa_node; ++ struct device_node *tas_node; + struct property *tpa_prop; + struct of_changeset ocs; + struct property *pp; @@ -190392,6 +247285,12 @@ + } + } + ++ tas_node = of_find_compatible_node(NULL, NULL, "ti,tas5756"); ++ if (tas_node) { ++ tas_device = true; ++ dev_info(&pdev->dev, "TAS5756 device found!\n"); ++ }; ++ + snd_rpi_hifiberry_dacplus.dev = &pdev->dev; + if (pdev->dev.of_node) { + struct device_node *i2s_node; @@ -190487,10 +247386,10 @@ +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/hifiberry_dacplusadc.c b/sound/soc/bcm/hifiberry_dacplusadc.c new file mode 100644 -index 000000000000..5fe6fd220556 +index 000000000000..55e8e3eb00da --- /dev/null +++ b/sound/soc/bcm/hifiberry_dacplusadc.c -@@ -0,0 +1,398 @@ +@@ -0,0 +1,396 @@ +/* + * ASoC Driver for HiFiBerry DAC+ / DAC Pro with ADC + * @@ -190722,13 +247621,11 @@ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int channels = params_channels(params); -+ int width = 32; ++ int width = snd_pcm_format_width(params_format(params)); + + if (snd_rpi_hifiberry_is_dacpro) { + struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; + -+ width = snd_pcm_format_physical_width(params_format(params)); -+ + snd_rpi_hifiberry_dacplusadc_set_sclk(component, + params_rate(params)); + @@ -190891,10 +247788,10 @@ +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/hifiberry_dacplusadcpro.c b/sound/soc/bcm/hifiberry_dacplusadcpro.c new file mode 100644 -index 000000000000..517a70fba7d7 +index 000000000000..17ca9dfe5442 --- /dev/null +++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c -@@ -0,0 +1,605 @@ +@@ -0,0 +1,603 @@ +/* + * ASoC Driver for HiFiBerry DAC+ / DAC Pro with ADC PRO Version (SW control) + * @@ -191280,15 +248177,13 @@ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int channels = params_channels(params); -+ int width = 32; ++ int width = snd_pcm_format_width(params_format(params)); + struct snd_soc_component *dac = asoc_rtd_to_codec(rtd, 0)->component; + struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_dai_driver *drv = dai->driver; + const struct snd_soc_dai_ops *ops = drv->ops; + + if (snd_rpi_hifiberry_is_dacpro) { -+ width = snd_pcm_format_physical_width(params_format(params)); -+ + snd_rpi_hifiberry_dacplusadcpro_set_sclk(dac, + params_rate(params)); + @@ -191502,7 +248397,7 @@ +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/hifiberry_dacplusdsp.c b/sound/soc/bcm/hifiberry_dacplusdsp.c new file mode 100644 -index 000000000000..cda7ee519093 +index 000000000000..e5919f839dc2 --- /dev/null +++ b/sound/soc/bcm/hifiberry_dacplusdsp.c @@ -0,0 +1,90 @@ @@ -191551,7 +248446,7 @@ + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, -+ .symmetric_rates = 1}; ++ .symmetric_rate = 1}; + +#ifdef CONFIG_OF +static const struct of_device_id dacplusdsp_ids = { @@ -191842,10 +248737,10 @@ +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/i-sabre-q2m.c b/sound/soc/bcm/i-sabre-q2m.c new file mode 100644 -index 000000000000..6809232e28cb +index 000000000000..dfd1644cb94a --- /dev/null +++ b/sound/soc/bcm/i-sabre-q2m.c -@@ -0,0 +1,158 @@ +@@ -0,0 +1,159 @@ +/* + * ASoC Driver for I-Sabre Q2M + * @@ -191901,7 +248796,7 @@ + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + int bclk_ratio; + -+ bclk_ratio = snd_pcm_format_physical_width( ++ bclk_ratio = snd_pcm_format_width( + params_format(params)) * params_channels(params); + return snd_soc_dai_set_bclk_ratio(cpu_dai, bclk_ratio); +} @@ -191981,7 +248876,8 @@ + +static int snd_rpi_i_sabre_q2m_remove(struct platform_device *pdev) +{ -+ return snd_soc_unregister_card(&snd_rpi_i_sabre_q2m); ++ snd_soc_unregister_card(&snd_rpi_i_sabre_q2m); ++ return 0; +} + +static const struct of_device_id snd_rpi_i_sabre_q2m_of_match = { @@ -192006,10 +248902,10 @@ +MODULE_LICENSE("GPL"); diff --git a/sound/soc/bcm/iqaudio-codec.c b/sound/soc/bcm/iqaudio-codec.c new file mode 100644 -index 000000000000..e0c2e3c5d2ea +index 000000000000..1486318a7c91 --- /dev/null +++ b/sound/soc/bcm/iqaudio-codec.c -@@ -0,0 +1,274 @@ +@@ -0,0 +1,278 @@ +/* + * ASoC Driver for IQaudIO Raspberry Pi Codec board + * @@ -192155,6 +249051,7 @@ + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + unsigned int samplerate = params_rate(params); + + switch (samplerate) { @@ -192164,15 +249061,17 @@ + case 48000: + case 96000: + pll_out = DA7213_PLL_FREQ_OUT_98304000; -+ return 0; ++ break; + case 44100: + case 88200: + pll_out = DA7213_PLL_FREQ_OUT_90316800; -+ return 0; ++ break; + default: + dev_err(rtd->dev,"Unsupported samplerate %d\n", samplerate); + return -EINVAL; + } ++ ++ return snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_PLL, 0, pll_out); +} + +static const struct snd_soc_ops snd_rpi_iqaudio_codec_ops = { @@ -192190,9 +249089,9 @@ + SND_SOC_DAIFMT_CBM_CFM, + .init = snd_rpi_iqaudio_codec_init, + .ops = &snd_rpi_iqaudio_codec_ops, -+ .symmetric_rates = 1, ++ .symmetric_rate = 1, + .symmetric_channels = 1, -+ .symmetric_samplebits = 1, ++ .symmetric_sample_bits = 1, + SND_SOC_DAILINK_REG(rpi_iqaudio), +}, +}; @@ -192257,7 +249156,8 @@ + +static int snd_rpi_iqaudio_codec_remove(struct platform_device *pdev) +{ -+ return snd_soc_unregister_card(&snd_rpi_iqaudio_codec); ++ snd_soc_unregister_card(&snd_rpi_iqaudio_codec); ++ return 0; +} + +static const struct of_device_id iqaudio_of_match = { @@ -192286,10 +249186,10 @@ +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/iqaudio-dac.c b/sound/soc/bcm/iqaudio-dac.c new file mode 100644 -index 000000000000..62f64c843219 +index 000000000000..f65eda9b4033 --- /dev/null +++ b/sound/soc/bcm/iqaudio-dac.c -@@ -0,0 +1,223 @@ +@@ -0,0 +1,224 @@ +/* + * ASoC Driver for IQaudIO DAC + * @@ -192489,7 +249389,8 @@ +{ + snd_rpi_iqaudio_gpio_mute(&snd_rpi_iqaudio_dac); + -+ return snd_soc_unregister_card(&snd_rpi_iqaudio_dac); ++ snd_soc_unregister_card(&snd_rpi_iqaudio_dac); ++ return 0; +} + +static const struct of_device_id iqaudio_of_match = { @@ -192515,10 +249416,10 @@ +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/justboom-both.c b/sound/soc/bcm/justboom-both.c new file mode 100644 -index 000000000000..471ecebddcaa +index 000000000000..dddb0a3cbdef --- /dev/null +++ b/sound/soc/bcm/justboom-both.c -@@ -0,0 +1,266 @@ +@@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rpi--wm8804.c -- ALSA SoC Raspberry Pi soundcard. @@ -192761,7 +249662,8 @@ + +static int snd_rpi_justboom_both_remove(struct platform_device *pdev) +{ -+ return snd_soc_unregister_card(&snd_rpi_justboom_both); ++ snd_soc_unregister_card(&snd_rpi_justboom_both); ++ return 0; +} + +static const struct of_device_id snd_rpi_justboom_both_of_match = { @@ -192940,10 +249842,10 @@ +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/pifi-40.c b/sound/soc/bcm/pifi-40.c new file mode 100644 -index 000000000000..ae699fb0485c +index 000000000000..20f384222fc5 --- /dev/null +++ b/sound/soc/bcm/pifi-40.c -@@ -0,0 +1,283 @@ +@@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ALSA ASoC Machine Driver for PiFi-40 @@ -193086,9 +249988,7 @@ +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); -+ unsigned int sample_bits; + -+ sample_bits = snd_pcm_format_physical_width(params_format(params)); + return snd_soc_dai_set_bclk_ratio(cpu_dai, 64); +} + @@ -193200,7 +250100,8 @@ + + kfree(&card->drvdata); + snd_pifi_40_pdn(&snd_pifi_40, 0); -+ return snd_soc_unregister_card(&snd_pifi_40); ++ snd_soc_unregister_card(&snd_pifi_40); ++ return 0; +} + +static const struct of_device_id snd_pifi_40_of_match = { @@ -193229,13 +250130,13 @@ +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/pisound.c b/sound/soc/bcm/pisound.c new file mode 100644 -index 000000000000..4c9c9c6c2511 +index 000000000000..688be6e189c6 --- /dev/null +++ b/sound/soc/bcm/pisound.c -@@ -0,0 +1,1238 @@ +@@ -0,0 +1,1255 @@ +/* + * Pisound Linux kernel module. -+ * Copyright (C) 2016-2020 Vilniaus Blokas UAB, https://blokas.io/pisound ++ * Copyright (C) 2016-2024 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 @@ -193377,14 +250278,14 @@ + } +} + -+static struct snd_rawmidi_ops pisnd_output_ops = { ++static const struct snd_rawmidi_ops pisnd_output_ops = { + .open = pisnd_output_open, + .close = pisnd_output_close, + .trigger = pisnd_output_trigger, + .drain = pisnd_output_drain, +}; + -+static struct snd_rawmidi_ops pisnd_input_ops = { ++static const struct snd_rawmidi_ops pisnd_input_ops = { + .open = pisnd_input_open, + .close = pisnd_input_close, + .trigger = pisnd_input_trigger, @@ -193461,6 +250362,7 @@ +enum { MAX_VERSION_STR_LEN = 6 }; +static char g_fw_versionMAX_VERSION_STR_LEN; +static char g_hw_versionMAX_VERSION_STR_LEN; ++static u32 g_spi_speed_hz; + +static uint8_t g_ledFlashDuration; +static bool g_ledFlashDurationChanged; @@ -193564,8 +250466,10 @@ + transfer.tx_buf = txbuf; + transfer.rx_buf = rxbuf; + transfer.len = len; -+ transfer.speed_hz = 150000; -+ transfer.delay_usecs = 10; ++ transfer.speed_hz = g_spi_speed_hz; ++ transfer.delay.value = 10; ++ transfer.delay.unit = SPI_DELAY_UNIT_USECS; ++ + spi_message_add_tail(&transfer, &msg); + + err = spi_sync(pisnd_spi_device, &msg); @@ -193879,6 +250783,26 @@ + memset(g_fw_version, 0, sizeof(g_fw_version)); + memset(g_hw_version, 0, sizeof(g_hw_version)); + ++ g_spi_speed_hz = 150000; ++ if (dev->of_node) { ++ struct device_node *spi_node; ++ ++ spi_node = of_parse_phandle( ++ dev->of_node, ++ "spi-controller", ++ 0 ++ ); ++ ++ if (spi_node) { ++ ret = of_property_read_u32(spi_node, "spi-speed-hz", &g_spi_speed_hz); ++ if (ret != 0) ++ printe("Failed reading spi-speed-hz! (%d)\n", ret); ++ ++ of_node_put(spi_node); ++ } ++ } ++ printi("Using SPI speed: %u\n", g_spi_speed_hz); ++ + spi = pisnd_spi_find_device(); + + if (spi != NULL) { @@ -194090,7 +251014,6 @@ + +static struct gpio_desc *osr0, *osr1, *osr2; +static struct gpio_desc *reset; -+static struct gpio_desc *button; + +static int pisnd_hw_params( + struct snd_pcm_substream *substream, @@ -194108,7 +251031,7 @@ + printd("rate = %d\n", params_rate(params)); + printd("ch = %d\n", params_channels(params)); + printd("bits = %u\n", -+ snd_pcm_format_physical_width(params_format(params))); ++ snd_pcm_format_width(params_format(params))); + printd("format = %d\n", params_format(params)); + + gpiod_set_value(reset, false); @@ -194184,7 +251107,7 @@ + return 0; +} + -+static struct snd_soc_ops pisnd_ops = { ++static const struct snd_soc_ops pisnd_ops = { + .startup = pisnd_startup, + .hw_params = pisnd_hw_params, +}; @@ -194249,8 +251172,6 @@ + + reset = gpiod_get_index(dev, "reset", 0, GPIOD_ASIS); + -+ button = gpiod_get_index(dev, "button", 0, GPIOD_ASIS); -+ + gpiod_direction_output(osr0, 1); + gpiod_direction_output(osr1, 1); + gpiod_direction_output(osr2, 1); @@ -194262,8 +251183,6 @@ + gpiod_set_value(osr2, false); + gpiod_set_value(reset, true); + -+ gpiod_export(button, false); -+ + return 0; +} + @@ -194272,11 +251191,9 @@ + int i; + + struct gpio_desc **gpios = { -+ &osr0, &osr1, &osr2, &reset, &button, ++ &osr0, &osr1, &osr2, &reset, + }; + -+ gpiod_unexport(button); -+ + for (i = 0; i < ARRAY_SIZE(gpios); ++i) { + if (*gpiosi == NULL) { + printd("weird, GPIO%d is NULL already\n", i); @@ -194451,7 +251368,8 @@ + gpiod_set_value(reset, false); + pisnd_uninit_gpio(); + -+ return snd_soc_unregister_card(&pisnd_card); ++ snd_soc_unregister_card(&pisnd_card); ++ return 0; +} + +MODULE_DEVICE_TABLE(of, pisound_of_match); @@ -194473,10 +251391,10 @@ +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/rpi-cirrus.c b/sound/soc/bcm/rpi-cirrus.c new file mode 100644 -index 000000000000..227a528d59bd +index 000000000000..6e317b31d9ac --- /dev/null +++ b/sound/soc/bcm/rpi-cirrus.c -@@ -0,0 +1,1025 @@ +@@ -0,0 +1,1024 @@ +/* + * ASoC machine driver for Cirrus Logic Audio Card + * (with WM5102 and WM8804 codecs) @@ -195183,8 +252101,7 @@ + + int ret; + -+ unsigned int width = snd_pcm_format_physical_width( -+ params_format(params)); ++ unsigned int width = snd_pcm_format_width(params_format(params)); + unsigned int rate = params_rate(params); + unsigned int clk_freq = calc_sysclk(rate); + @@ -195383,7 +252300,7 @@ + | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .ignore_suspend = 1, -+ .params = &rpi_cirrus_dai_link2_params, ++ .c2c_params = &rpi_cirrus_dai_link2_params, + .init = rpi_cirrus_init_wm8804, + SND_SOC_DAILINK_REG(wm8804), + }, @@ -195657,10 +252574,10 @@ +MODULE_LICENSE("GPL"); diff --git a/sound/soc/bcm/rpi-simple-soundcard.c b/sound/soc/bcm/rpi-simple-soundcard.c new file mode 100644 -index 000000000000..c25351e6ee90 +index 000000000000..1c6b55b80cae --- /dev/null +++ b/sound/soc/bcm/rpi-simple-soundcard.c -@@ -0,0 +1,419 @@ +@@ -0,0 +1,520 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rpi-simple-soundcard.c -- ALSA SoC Raspberry Pi soundcard. @@ -195800,7 +252717,7 @@ + * hard-code this for now. More complex drivers could just replace + * the hw_params routine. + */ -+ sample_bits = snd_pcm_format_physical_width(params_format(params)); ++ sample_bits = snd_pcm_format_width(params_format(params)); + return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2); +} + @@ -195808,6 +252725,26 @@ + .hw_params = snd_rpi_simple_hw_params, +}; + ++static int snd_merus_amp_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); ++ int rate; ++ ++ rate = params_rate(params); ++ if (rate > 48000) { ++ dev_err(rtd->card->dev, ++ "Unsupported samplerate %d\n", ++ rate); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static struct snd_soc_ops snd_merus_amp_ops = { ++ .hw_params = snd_merus_amp_hw_params, ++}; ++ +enum adau1977_clk_id { + ADAU1977_SYSCLK, +}; @@ -195916,6 +252853,28 @@ + .fixed_bclk_ratio = 64, +}; + ++SND_SOC_DAILINK_DEFS(hifiberry_amp3, ++ DAILINK_COMP_ARRAY(COMP_EMPTY()), ++ DAILINK_COMP_ARRAY(COMP_CODEC("ma120x0p.1-0020", "ma120x0p-amp")), ++ DAILINK_COMP_ARRAY(COMP_EMPTY())); ++ ++static struct snd_soc_dai_link snd_hifiberry_amp3_dai = { ++ { ++ .name = "HifiberryAmp3", ++ .stream_name = "Hifiberry Amp3", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | ++ SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ SND_SOC_DAILINK_REG(hifiberry_amp3), ++ }, ++}; ++ ++static struct snd_rpi_simple_drvdata drvdata_hifiberry_amp3 = { ++ .card_name = "snd_rpi_hifiberry_amp3", ++ .dai = snd_hifiberry_amp3_dai, ++ .fixed_bclk_ratio = 64, ++}; ++ +SND_SOC_DAILINK_DEFS(hifiberry_dac, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC("pcm5102a-codec", "pcm5102a-hifi")), @@ -195937,6 +252896,58 @@ + .dai = snd_hifiberry_dac_dai, +}; + ++static int hifiberry_dac8x_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); ++ ++ /* override the defaults to reflect 4 x PCM5102A on the card ++ * and limit the sample rate to 192ksps ++ */ ++ codec_dai->driver->playback.channels_max = 8; ++ codec_dai->driver->playback.rates = SNDRV_PCM_RATE_8000_192000; ++ ++ return 0; ++} ++ ++static struct snd_soc_dai_link snd_hifiberry_dac8x_dai = { ++ { ++ .name = "HifiBerry DAC8x", ++ .stream_name = "HifiBerry DAC8x HiFi", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | ++ SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ .init = hifiberry_dac8x_init, ++ SND_SOC_DAILINK_REG(hifiberry_dac), ++ }, ++}; ++ ++static struct snd_rpi_simple_drvdata drvdata_hifiberry_dac8x = { ++ .card_name = "snd_rpi_hifiberry_dac8x", ++ .dai = snd_hifiberry_dac8x_dai, ++ .fixed_bclk_ratio = 64, ++}; ++ ++SND_SOC_DAILINK_DEFS(dionaudio_kiwi, ++ DAILINK_COMP_ARRAY(COMP_EMPTY()), ++ DAILINK_COMP_ARRAY(COMP_CODEC("pcm1794a-codec", "pcm1794a-hifi")), ++ DAILINK_COMP_ARRAY(COMP_EMPTY())); ++ ++static struct snd_soc_dai_link snd_dionaudio_kiwi_dai = { ++{ ++ .name = "DionAudio KIWI", ++ .stream_name = "DionAudio KIWI STREAMER", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ SND_SOC_DAILINK_REG(dionaudio_kiwi), ++}, ++}; ++ ++static struct snd_rpi_simple_drvdata drvdata_dionaudio_kiwi = { ++ .card_name = "snd_rpi_dionaudio_kiwi", ++ .dai = snd_dionaudio_kiwi_dai, ++ .fixed_bclk_ratio = 64, ++}; ++ +SND_SOC_DAILINK_DEFS(rpi_dac, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC("pcm1794a-codec", "pcm1794a-hifi")), @@ -195960,13 +252971,14 @@ + +SND_SOC_DAILINK_DEFS(merus_amp, + DAILINK_COMP_ARRAY(COMP_EMPTY()), -+ DAILINK_COMP_ARRAY(COMP_CODEC("ma120x0p.1-0020","ma120x0p-amp")), ++ DAILINK_COMP_ARRAY(COMP_CODEC("ma120x0p.1-0020", "ma120x0p-amp")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link snd_merus_amp_dai = { + { + .name = "MerusAmp", + .stream_name = "Merus Audio Amp", ++ .ops = &snd_merus_amp_ops, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, @@ -196012,8 +253024,14 @@ + .data = (void *) &drvdata_hifiberrydacplusdsp }, + { .compatible = "hifiberry,hifiberry-amp", + .data = (void *) &drvdata_hifiberry_amp }, ++ { .compatible = "hifiberry,hifiberry-amp3", ++ .data = (void *) &drvdata_hifiberry_amp3 }, + { .compatible = "hifiberry,hifiberry-dac", + .data = (void *) &drvdata_hifiberry_dac }, ++ { .compatible = "hifiberry,hifiberry-dac8x", ++ .data = (void *) &drvdata_hifiberry_dac8x }, ++ { .compatible = "dionaudio,dionaudio-kiwi", ++ .data = (void *) &drvdata_dionaudio_kiwi }, + { .compatible = "rpi,rpi-dac", &drvdata_rpi_dac}, + { .compatible = "merus,merus-amp", + .data = (void *) &drvdata_merus_amp }, @@ -196082,10 +253100,10 @@ +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/rpi-wm8804-soundcard.c b/sound/soc/bcm/rpi-wm8804-soundcard.c new file mode 100644 -index 000000000000..835d0f9420e7 +index 000000000000..1a8f8e67e8a0 --- /dev/null +++ b/sound/soc/bcm/rpi-wm8804-soundcard.c -@@ -0,0 +1,410 @@ +@@ -0,0 +1,549 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rpi--wm8804.c -- ALSA SoC Raspberry Pi soundcard. @@ -196122,6 +253140,7 @@ +#include <linux/gpio/consumer.h> +#include <linux/platform_device.h> +#include <linux/module.h> ++#include <linux/delay.h> + +#include <sound/core.h> +#include <sound/pcm.h> @@ -196153,6 +253172,10 @@ +static struct gpio_desc *snd_clk44gpio; +static struct gpio_desc *snd_clk48gpio; +static int wm8804_samplerate = 0; ++static struct gpio_desc *led_gpio_1; ++static struct gpio_desc *led_gpio_2; ++static struct gpio_desc *led_gpio_3; ++static struct gpio_desc *custom_reset; + +/* Forward declarations */ +static struct snd_soc_dai_link snd_allo_digione_dai; @@ -196162,6 +253185,37 @@ +#define CLK_44EN_RATE 22579200UL +#define CLK_48EN_RATE 24576000UL + ++static const char * const wm8805_input_select_text = { ++ "Rx 0", ++ "Rx 1", ++ "Rx 2", ++ "Rx 3", ++ "Rx 4", ++ "Rx 5", ++ "Rx 6", ++ "Rx 7" ++}; ++ ++static const unsigned int wm8805_input_channel_select_value = { ++ 0, 1, 2, 3, 4, 5, 6, 7 ++}; ++ ++static const struct soc_enum wm8805_input_channel_sel = { ++ SOC_VALUE_ENUM_SINGLE(WM8804_PLL6, 0, 7, ARRAY_SIZE(wm8805_input_select_text), ++ wm8805_input_select_text, wm8805_input_channel_select_value), ++}; ++ ++static const struct snd_kcontrol_new wm8805_input_controls_card = { ++ SOC_ENUM("Select Input Channel", wm8805_input_channel_sel0), ++}; ++ ++static int wm8805_add_input_controls(struct snd_soc_component *component) ++{ ++ snd_soc_add_component_controls(component, wm8805_input_controls_card, ++ ARRAY_SIZE(wm8805_input_controls_card)); ++ return 0; ++} ++ +static unsigned int snd_rpi_wm8804_enable_clock(unsigned int samplerate) +{ + switch (samplerate) { @@ -196275,6 +253329,53 @@ + .hw_params = snd_rpi_wm8804_hw_params, +}; + ++static int snd_interlude_audio_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ int ret = snd_rpi_wm8804_hw_params(substream, params); ++ int samplerate = params_rate(params); ++ ++ switch (samplerate) { ++ case 44100: ++ gpiod_set_value_cansleep(led_gpio_1, 1); ++ gpiod_set_value_cansleep(led_gpio_2, 0); ++ gpiod_set_value_cansleep(led_gpio_3, 0); ++ break; ++ case 48000: ++ gpiod_set_value_cansleep(led_gpio_1, 1); ++ gpiod_set_value_cansleep(led_gpio_2, 0); ++ gpiod_set_value_cansleep(led_gpio_3, 0); ++ break; ++ case 88200: ++ gpiod_set_value_cansleep(led_gpio_1, 0); ++ gpiod_set_value_cansleep(led_gpio_2, 1); ++ gpiod_set_value_cansleep(led_gpio_3, 0); ++ break; ++ case 96000: ++ gpiod_set_value_cansleep(led_gpio_1, 0); ++ gpiod_set_value_cansleep(led_gpio_2, 1); ++ gpiod_set_value_cansleep(led_gpio_3, 0); ++ break; ++ case 176400: ++ gpiod_set_value_cansleep(led_gpio_1, 0); ++ gpiod_set_value_cansleep(led_gpio_2, 0); ++ gpiod_set_value_cansleep(led_gpio_3, 1); ++ break; ++ case 192000: ++ gpiod_set_value_cansleep(led_gpio_1, 0); ++ gpiod_set_value_cansleep(led_gpio_2, 0); ++ gpiod_set_value_cansleep(led_gpio_3, 1); ++ break; ++ default: ++ break; ++ } ++ return ret; ++} ++ ++const struct snd_soc_ops interlude_audio_digital_dai_ops = { ++ .hw_params = snd_interlude_audio_hw_params, ++}; ++ +SND_SOC_DAILINK_DEFS(justboom_digi, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_EMPTY()), @@ -196375,6 +253476,60 @@ + .probe = snd_hifiberry_digi_probe, +}; + ++SND_SOC_DAILINK_DEFS(interlude_audio_digital, ++ DAILINK_COMP_ARRAY(COMP_EMPTY()), ++ DAILINK_COMP_ARRAY(COMP_EMPTY()), ++ DAILINK_COMP_ARRAY(COMP_EMPTY())); ++ ++static int snd_interlude_audio_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; ++ int ret; ++ ++ ret = wm8805_add_input_controls(component); ++ if (ret != 0) ++ pr_err("failed to add input controls"); ++ ++ return 0; ++} ++ ++ ++static struct snd_soc_dai_link snd_interlude_audio_digital_dai = { ++{ ++ .name = "Interlude Audio Digital", ++ .stream_name = "Interlude Audio Digital HiFi", ++ .init = snd_interlude_audio_init, ++ .ops = &interlude_audio_digital_dai_ops, ++ SND_SOC_DAILINK_REG(interlude_audio_digital), ++}, ++}; ++ ++ ++static int snd_interlude_audio_digital_probe(struct platform_device *pdev) ++{ ++ if (IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio)) ++ return 0; ++ ++ custom_reset = devm_gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW); ++ gpiod_set_value_cansleep(custom_reset, 0); ++ mdelay(10); ++ gpiod_set_value_cansleep(custom_reset, 1); ++ ++ snd_interlude_audio_digital_dai->name = "Interlude Audio Digital"; ++ snd_interlude_audio_digital_dai->stream_name = "Interlude Audio Digital HiFi"; ++ led_gpio_1 = devm_gpiod_get(&pdev->dev, "led1", GPIOD_OUT_LOW); ++ led_gpio_2 = devm_gpiod_get(&pdev->dev, "led2", GPIOD_OUT_LOW); ++ led_gpio_3 = devm_gpiod_get(&pdev->dev, "led3", GPIOD_OUT_LOW); ++ return 0; ++} ++ ++ ++static struct snd_rpi_wm8804_drvdata drvdata_interlude_audio_digital = { ++ .card_name = "snd_IA_Digital_Hat", ++ .dai = snd_interlude_audio_digital_dai, ++ .probe = snd_interlude_audio_digital_probe, ++}; ++ +static const struct of_device_id snd_rpi_wm8804_of_match = { + { .compatible = "justboom,justboom-digi", + .data = (void *) &drvdata_justboom_digi }, @@ -196384,6 +253539,8 @@ + .data = (void *) &drvdata_allo_digione }, + { .compatible = "hifiberry,hifiberry-digi", + .data = (void *) &drvdata_hifiberry_digi }, ++ { .compatible = "interludeaudio,interludeaudio-digital", ++ .data = (void *) &drvdata_interlude_audio_digital }, + {}, +}; + @@ -196497,17 +253654,18 @@ +MODULE_DESCRIPTION("ASoC Raspberry Pi Hat generic digi driver for WM8804 based cards"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index 34c6dd04b85a..e9be75318723 100644 +index f1e1dbc509f6..e2777a369e2d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig -@@ -100,12 +100,14 @@ config SND_SOC_ALL_CODECS - imply SND_SOC_ICS43432 +@@ -119,6 +119,7 @@ config SND_SOC_ALL_CODECS + imply SND_SOC_IDT821034 imply SND_SOC_INNO_RK3036 imply SND_SOC_ISABELLE + imply SND_SOC_I_SABRE_CODEC imply SND_SOC_JZ4740_CODEC imply SND_SOC_JZ4725B_CODEC - imply SND_SOC_JZ4770_CODEC + imply SND_SOC_JZ4760_CODEC +@@ -126,6 +127,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_LM4857 imply SND_SOC_LM49453 imply SND_SOC_LOCHNAGAR_SC @@ -196515,7 +253673,7 @@ imply SND_SOC_MAX98088 imply SND_SOC_MAX98090 imply SND_SOC_MAX98095 -@@ -142,6 +144,7 @@ config SND_SOC_ALL_CODECS +@@ -168,6 +170,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_PCM179X_SPI imply SND_SOC_PCM186X_I2C imply SND_SOC_PCM186X_SPI @@ -196523,7 +253681,7 @@ imply SND_SOC_PCM3008 imply SND_SOC_PCM3060_I2C imply SND_SOC_PCM3060_SPI -@@ -206,6 +209,7 @@ config SND_SOC_ALL_CODECS +@@ -255,6 +258,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_TLV320ADCX140 imply SND_SOC_TLV320AIC23_I2C imply SND_SOC_TLV320AIC23_SPI @@ -196531,7 +253689,7 @@ imply SND_SOC_TLV320AIC26 imply SND_SOC_TLV320AIC31XX imply SND_SOC_TLV320AIC32X4_I2C -@@ -343,12 +347,12 @@ config SND_SOC_AD193X +@@ -410,12 +414,12 @@ config SND_SOC_AD193X tristate config SND_SOC_AD193X_SPI @@ -196546,16 +253704,7 @@ depends on I2C select SND_SOC_AD193X -@@ -804,7 +808,7 @@ config SND_SOC_HDAC_HDA - select SND_HDA - - config SND_SOC_ICS43432 -- tristate -+ tristate "InvenSense ICS43432 I2S microphone codec" - - config SND_SOC_INNO_RK3036 - tristate "Inno codec driver for RK3036 SoC" -@@ -825,6 +829,13 @@ config SND_SOC_LOCHNAGAR_SC +@@ -1126,6 +1130,13 @@ config SND_SOC_LOCHNAGAR_SC This driver support the sound card functionality of the Cirrus Logic Lochnagar audio development board. @@ -196569,7 +253718,7 @@ config SND_SOC_MADERA tristate default y if SND_SOC_CS47L15=y -@@ -1125,6 +1136,10 @@ config SND_SOC_RT5616 +@@ -1503,6 +1514,10 @@ config SND_SOC_RT5616 tristate "Realtek RT5616 CODEC" depends on I2C @@ -196580,19 +253729,19 @@ config SND_SOC_RT5631 tristate "Realtek ALC5631/RT5631 CODEC" depends on I2C -@@ -1346,6 +1361,9 @@ config SND_SOC_TFA9879 +@@ -1846,6 +1861,9 @@ config SND_SOC_TFA9879 tristate "NXP Semiconductors TFA9879 amplifier" depends on I2C +config SND_SOC_TAS5713 + tristate + - config SND_SOC_TLV320AIC23 - tristate - -@@ -1784,4 +1802,8 @@ config SND_SOC_TPA6130A2 - tristate "Texas Instruments TPA6130A2 headphone amplifier" + config SND_SOC_TFA989X + tristate "NXP/Goodix TFA989X (TFA1) amplifiers" depends on I2C +@@ -2404,4 +2422,8 @@ config SND_SOC_LPASS_TX_MACRO + select SND_SOC_LPASS_MACRO_COMMON + tristate "Qualcomm TX Macro in LPASS(Low Power Audio SubSystem)" +config SND_SOC_I_SABRE_CODEC + tristate "Audiophonics I-SABRE Codec" @@ -196600,26 +253749,26 @@ + endmenu diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile -index 11ce98c25d6c..42dbabda8e14 100644 +index a87e56938ce5..f45b2102ce42 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile -@@ -96,6 +96,7 @@ snd-soc-hdac-hda-objs := hdac_hda.o - snd-soc-ics43432-objs := ics43432.o +@@ -127,6 +127,7 @@ snd-soc-ics43432-objs := ics43432.o + snd-soc-idt821034-objs := idt821034.o snd-soc-inno-rk3036-objs := inno_rk3036.o snd-soc-isabelle-objs := isabelle.o +snd-soc-i-sabre-codec-objs := i-sabre-codec.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-jz4725b-codec-objs := jz4725b.o - snd-soc-jz4770-codec-objs := jz4770.o -@@ -103,6 +104,7 @@ snd-soc-l3-objs := l3.o - snd-soc-lm4857-objs := lm4857.o - snd-soc-lm49453-objs := lm49453.o - snd-soc-lochnagar-sc-objs := lochnagar-sc.o + snd-soc-jz4760-codec-objs := jz4760.o +@@ -139,6 +140,7 @@ snd-soc-lpass-rx-macro-objs := lpass-rx-macro.o + snd-soc-lpass-tx-macro-objs := lpass-tx-macro.o + snd-soc-lpass-wsa-macro-objs := lpass-wsa-macro.o + snd-soc-lpass-va-macro-objs := lpass-va-macro.o +snd-soc-ma120x0p-objs := ma120x0p.o snd-soc-madera-objs := madera.o snd-soc-max9759-objs := max9759.o snd-soc-max9768-objs := max9768.o -@@ -144,6 +146,7 @@ snd-soc-pcm179x-spi-objs := pcm179x-spi.o +@@ -187,6 +189,7 @@ snd-soc-pcm179x-spi-objs := pcm179x-spi.o snd-soc-pcm186x-objs := pcm186x.o snd-soc-pcm186x-i2c-objs := pcm186x-i2c.o snd-soc-pcm186x-spi-objs := pcm186x-spi.o @@ -196627,23 +253776,23 @@ snd-soc-pcm3008-objs := pcm3008.o snd-soc-pcm3060-objs := pcm3060.o snd-soc-pcm3060-i2c-objs := pcm3060-i2c.o -@@ -216,6 +219,7 @@ snd-soc-tas6424-objs := tas6424.o - snd-soc-tda7419-objs := tda7419.o - snd-soc-tas2770-objs := tas2770.o - snd-soc-tfa9879-objs := tfa9879.o +@@ -271,6 +274,7 @@ snd-soc-sta529-objs := sta529.o + snd-soc-stac9766-objs := stac9766.o + snd-soc-sti-sas-objs := sti-sas.o + snd-soc-tas5086-objs := tas5086.o +snd-soc-tas5713-objs := tas5713.o - snd-soc-tlv320aic23-objs := tlv320aic23.o - snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o - snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o -@@ -405,6 +409,7 @@ obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o - obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o + snd-soc-tas571x-objs := tas571x.o + snd-soc-tas5720-objs := tas5720.o + snd-soc-tas5805m-objs := tas5805m.o +@@ -513,6 +517,7 @@ obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o + obj-$(CONFIG_SND_SOC_IDT821034) += snd-soc-idt821034.o obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o +obj-$(CONFIG_SND_SOC_I_SABRE_CODEC) += snd-soc-i-sabre-codec.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_JZ4725B_CODEC) += snd-soc-jz4725b-codec.o - obj-$(CONFIG_SND_SOC_JZ4770_CODEC) += snd-soc-jz4770-codec.o -@@ -412,6 +417,7 @@ obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o + obj-$(CONFIG_SND_SOC_JZ4760_CODEC) += snd-soc-jz4760-codec.o +@@ -520,6 +525,7 @@ obj-$(CONFIG_SND_SOC_JZ4770_CODEC) += snd-soc-jz4770-codec.o obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o obj-$(CONFIG_SND_SOC_LOCHNAGAR_SC) += snd-soc-lochnagar-sc.o @@ -196651,27 +253800,51 @@ obj-$(CONFIG_SND_SOC_MADERA) += snd-soc-madera.o obj-$(CONFIG_SND_SOC_MAX9759) += snd-soc-max9759.o obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o -@@ -465,6 +471,7 @@ obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o - obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o - obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o - obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o +@@ -563,6 +569,7 @@ obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o + obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o + obj-$(CONFIG_SND_SOC_PCM1789_I2C) += snd-soc-pcm1789-i2c.o + obj-$(CONFIG_SND_SOC_PCM1789) += snd-soc-pcm1789-codec.o +obj-$(CONFIG_SND_SOC_PCM1794A) += snd-soc-pcm1794a.o - obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o - obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o - obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o -@@ -526,6 +533,7 @@ obj-$(CONFIG_SND_SOC_TAS6424) += snd-soc-tas6424.o + obj-$(CONFIG_SND_SOC_PCM179X_I2C) += snd-soc-pcm179x-i2c.o + obj-$(CONFIG_SND_SOC_PCM179X_SPI) += snd-soc-pcm179x-spi.o + obj-$(CONFIG_SND_SOC_PCM186X) += snd-soc-pcm186x.o +@@ -663,6 +670,7 @@ obj-$(CONFIG_SND_SOC_TAS5805M) += snd-soc-tas5805m.o + obj-$(CONFIG_SND_SOC_TAS6424) += snd-soc-tas6424.o obj-$(CONFIG_SND_SOC_TDA7419) += snd-soc-tda7419.o obj-$(CONFIG_SND_SOC_TAS2770) += snd-soc-tas2770.o - obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o +obj-$(CONFIG_SND_SOC_TAS5713) += snd-soc-tas5713.o - obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o - obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o - obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o + obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o + obj-$(CONFIG_SND_SOC_TFA989X) += snd-soc-tfa989x.o + obj-$(CONFIG_SND_SOC_TLV320ADC3XXX) += snd-soc-tlv320adc3xxx.o +diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c +index 24c7b9c84c19..328dfdc3f475 100644 +--- a/sound/soc/codecs/adau1977-i2c.c ++++ b/sound/soc/codecs/adau1977-i2c.c +@@ -38,9 +38,19 @@ static const struct i2c_device_id adau1977_i2c_ids = { + }; + MODULE_DEVICE_TABLE(i2c, adau1977_i2c_ids); + ++static const struct of_device_id adau1977_of_ids = { ++ { .compatible = "adi,adau1977", }, ++ { .compatible = "adi,adau1978", }, ++ { .compatible = "adi,adau1979", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, adau1977_of_ids); ++ ++ + static struct i2c_driver adau1977_i2c_driver = { + .driver = { + .name = "adau1977", ++ .of_match_table = adau1977_of_ids, + }, + .probe = adau1977_i2c_probe, + .id_table = adau1977_i2c_ids, diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c -index 0214e3ab9da0..b8b15b886c22 100644 +index a422472820fb..9d6874dc1252 100644 --- a/sound/soc/codecs/cs42xx8-i2c.c +++ b/sound/soc/codecs/cs42xx8-i2c.c -@@ -45,11 +45,18 @@ static struct i2c_device_id cs42xx8_i2c_id = { +@@ -64,11 +64,18 @@ static const struct i2c_device_id cs42xx8_i2c_id = { }; MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id); @@ -196692,333 +253865,32 @@ .probe = cs42xx8_i2c_probe, .remove = cs42xx8_i2c_remove, diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c -index 5d6ef660f851..7d840313bccb 100644 +index 9c44b6283b8f..8e3b88d7d3af 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c -@@ -517,8 +517,10 @@ const struct of_device_id cs42xx8_of_match = { - { .compatible = "cirrus,cs42888", .data = &cs42888_data, }, - { /* sentinel */ } +@@ -510,6 +510,16 @@ const struct cs42xx8_driver_data cs42888_data = { }; + EXPORT_SYMBOL_GPL(cs42888_data); + ++const struct of_device_id cs42xx8_of_match = { ++ { .compatible = "cirrus,cs42448", .data = &cs42448_data, }, ++ { .compatible = "cirrus,cs42888", .data = &cs42888_data, }, ++ { /* sentinel */ } ++}; +#if !IS_ENABLED(CONFIG_SND_SOC_CS42XX8_I2C) - MODULE_DEVICE_TABLE(of, cs42xx8_of_match); - EXPORT_SYMBOL_GPL(cs42xx8_of_match); ++MODULE_DEVICE_TABLE(of, cs42xx8_of_match); ++EXPORT_SYMBOL_GPL(cs42xx8_of_match); +#endif - - int cs42xx8_probe(struct device *dev, struct regmap *regmap) - { -diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c -index 403d4c6a49a8..b9e96d7ed00b 100644 ---- a/sound/soc/codecs/hdmi-codec.c -+++ b/sound/soc/codecs/hdmi-codec.c -@@ -278,6 +278,7 @@ struct hdmi_codec_priv { - bool busy; - struct snd_soc_jack *jack; - unsigned int jack_status; -+ u8 iec_status5; - }; - - static const struct snd_soc_dapm_widget hdmi_widgets = { -@@ -385,6 +386,47 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, - return 0; - } - -+static int hdmi_codec_iec958_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; -+ uinfo->count = 1; -+ return 0; -+} -+ -+static int hdmi_codec_iec958_default_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); -+ -+ memcpy(ucontrol->value.iec958.status, hcp->iec_status, -+ sizeof(hcp->iec_status)); -+ -+ return 0; -+} -+ -+static int hdmi_codec_iec958_default_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); -+ -+ memcpy(hcp->iec_status, ucontrol->value.iec958.status, -+ sizeof(hcp->iec_status)); -+ -+ return 0; -+} + -+static int hdmi_codec_iec958_mask_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ memset(ucontrol->value.iec958.status, 0xff, -+ sizeof_field(struct hdmi_codec_priv, iec_status)); -+ -+ return 0; -+} -+ - static int hdmi_codec_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) + int cs42xx8_probe(struct device *dev, struct regmap *regmap, struct cs42xx8_driver_data *drvdata) { -@@ -438,6 +480,42 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, - mutex_unlock(&hcp->lock); - } - -+static int hdmi_codec_fill_codec_params(struct snd_soc_dai *dai, -+ unsigned int sample_width, -+ unsigned int sample_rate, -+ unsigned int channels, -+ struct hdmi_codec_params *hp) -+{ -+ struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); -+ int idx; -+ -+ /* Select a channel allocation that matches with ELD and pcm channels */ -+ idx = hdmi_codec_get_ch_alloc_table_idx(hcp, channels); -+ if (idx < 0) { -+ dev_err(dai->dev, "Not able to map channels to speakers (%d)\n", -+ idx); -+ hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; -+ return idx; -+ } -+ -+ memset(hp, 0, sizeof(*hp)); -+ -+ hdmi_audio_infoframe_init(&hp->cea); -+ hp->cea.channels = channels; -+ hp->cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; -+ hp->cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; -+ hp->cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; -+ hp->cea.channel_allocation = hdmi_codec_channel_allocidx.ca_id; -+ -+ hp->sample_width = sample_width; -+ hp->sample_rate = sample_rate; -+ hp->channels = channels; -+ -+ hcp->chmap_idx = hdmi_codec_channel_allocidx.ca_id; -+ -+ return 0; -+} -+ - static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -@@ -452,43 +530,71 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, - .dig_subframe = { 0 }, - } - }; -- int ret, idx; -+ int ret; -+ -+ if (!hcp->hcd.ops->hw_params) -+ return 0; - - dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__, - params_width(params), params_rate(params), - params_channels(params)); - -- ret = snd_pcm_create_iec958_consumer_hw_params(params, hp.iec.status, -- sizeof(hp.iec.status)); -+ ret = hdmi_codec_fill_codec_params(dai, -+ params_width(params), -+ params_rate(params), -+ params_channels(params), -+ &hp); -+ if (ret < 0) -+ return ret; -+ -+ memcpy(hp.iec.status, hcp->iec_status, sizeof(hp.iec.status)); -+ ret = snd_pcm_fill_iec958_consumer_hw_params(params, hp.iec.status, -+ sizeof(hp.iec.status)); - if (ret < 0) { - dev_err(dai->dev, "Creating IEC958 channel status failed %d\n", - ret); - return ret; - } - -- hdmi_audio_infoframe_init(&hp.cea); -- hp.cea.channels = params_channels(params); -- hp.cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; -- hp.cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; -- hp.cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; -+ cf->bit_fmt = params_format(params); -+ return hcp->hcd.ops->hw_params(dai->dev->parent, hcp->hcd.data, -+ cf, &hp); -+} -+ -+static int hdmi_codec_prepare(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); -+ struct hdmi_codec_daifmt *cf = dai->playback_dma_data; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ unsigned int channels = runtime->channels; -+ unsigned int width = snd_pcm_format_width(runtime->format); -+ unsigned int rate = runtime->rate; -+ struct hdmi_codec_params hp; -+ int ret; - -- /* Select a channel allocation that matches with ELD and pcm channels */ -- idx = hdmi_codec_get_ch_alloc_table_idx(hcp, hp.cea.channels); -- if (idx < 0) { -- dev_err(dai->dev, "Not able to map channels to speakers (%d)\n", -- idx); -- hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; -- return idx; -- } -- hp.cea.channel_allocation = hdmi_codec_channel_allocidx.ca_id; -- hcp->chmap_idx = hdmi_codec_channel_allocidx.ca_id; -+ if (!hcp->hcd.ops->prepare) -+ return 0; - -- hp.sample_width = params_width(params); -- hp.sample_rate = params_rate(params); -- hp.channels = params_channels(params); -+ dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__, -+ width, rate, channels); - -- return hcp->hcd.ops->hw_params(dai->dev->parent, hcp->hcd.data, -- cf, &hp); -+ ret = hdmi_codec_fill_codec_params(dai, width, rate, channels, &hp); -+ if (ret < 0) -+ return ret; -+ -+ memcpy(hp.iec.status, hcp->iec_status, sizeof(hp.iec.status)); -+ ret = snd_pcm_fill_iec958_consumer(runtime, hp.iec.status, -+ sizeof(hp.iec.status)); -+ if (ret < 0) { -+ dev_err(dai->dev, "Creating IEC958 channel status failed %d\n", -+ ret); -+ return ret; -+ } -+ -+ cf->bit_fmt = runtime->format; -+ return hcp->hcd.ops->prepare(dai->dev->parent, hcp->hcd.data, -+ cf, &hp); - } - - static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai, -@@ -582,6 +688,7 @@ static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { - .startup = hdmi_codec_startup, - .shutdown = hdmi_codec_shutdown, - .hw_params = hdmi_codec_hw_params, -+ .prepare = hdmi_codec_prepare, - .set_fmt = hdmi_codec_i2s_set_fmt, - .mute_stream = hdmi_codec_mute, - }; -@@ -615,23 +722,40 @@ static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE |\ - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ -- SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) -+ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\ -+ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) -+ -+struct snd_kcontrol_new hdmi_codec_controls = { -+ { -+ .access = SNDRV_CTL_ELEM_ACCESS_READ, -+ .iface = SNDRV_CTL_ELEM_IFACE_PCM, -+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), -+ .info = hdmi_codec_iec958_info, -+ .get = hdmi_codec_iec958_mask_get, -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_PCM, -+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), -+ .info = hdmi_codec_iec958_info, -+ .get = hdmi_codec_iec958_default_get, -+ .put = hdmi_codec_iec958_default_put, -+ }, -+ { -+ .access = (SNDRV_CTL_ELEM_ACCESS_READ | -+ SNDRV_CTL_ELEM_ACCESS_VOLATILE), -+ .iface = SNDRV_CTL_ELEM_IFACE_PCM, -+ .name = "ELD", -+ .info = hdmi_eld_ctl_info, -+ .get = hdmi_eld_ctl_get, -+ }, -+}; - - static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *dai) - { - struct snd_soc_dai_driver *drv = dai->driver; - struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); -- struct snd_kcontrol *kctl; -- struct snd_kcontrol_new hdmi_eld_ctl = { -- .access = SNDRV_CTL_ELEM_ACCESS_READ | -- SNDRV_CTL_ELEM_ACCESS_VOLATILE, -- .iface = SNDRV_CTL_ELEM_IFACE_PCM, -- .name = "ELD", -- .info = hdmi_eld_ctl_info, -- .get = hdmi_eld_ctl_get, -- .device = rtd->pcm->device, -- }; -+ unsigned int i; - int ret; - - ret = snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK, -@@ -648,12 +772,21 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, - hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps; - hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; - -- /* add ELD ctl with the device number corresponding to the PCM stream */ -- kctl = snd_ctl_new1(&hdmi_eld_ctl, dai->component); -- if (!kctl) -- return -ENOMEM; -+ for (i = 0; i < ARRAY_SIZE(hdmi_codec_controls); i++) { -+ struct snd_kcontrol *kctl; -+ -+ /* add ELD ctl with the device number corresponding to the PCM stream */ -+ kctl = snd_ctl_new1(&hdmi_codec_controlsi, dai->component); -+ if (!kctl) -+ return -ENOMEM; - -- return snd_ctl_add(rtd->card->snd_card, kctl); -+ kctl->id.device = rtd->pcm->device; -+ ret = snd_ctl_add(rtd->card->snd_card, kctl); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; - } - - static int hdmi_dai_probe(struct snd_soc_dai *dai) -@@ -819,7 +952,8 @@ static int hdmi_codec_probe(struct platform_device *pdev) - } - - dai_count = hcd->i2s + hcd->spdif; -- if (dai_count < 1 || !hcd->ops || !hcd->ops->hw_params || -+ if (dai_count < 1 || !hcd->ops || -+ (!hcd->ops->hw_params && !hcd->ops->prepare) || - !hcd->ops->audio_shutdown) { - dev_err(dev, "%s: Invalid parameters\n", __func__); - return -EINVAL; -@@ -832,6 +966,11 @@ static int hdmi_codec_probe(struct platform_device *pdev) - hcp->hcd = *hcd; - mutex_init(&hcp->lock); - -+ ret = snd_pcm_create_iec958_consumer_default(hcp->iec_status, -+ sizeof(hcp->iec_status)); -+ if (ret < 0) -+ return ret; -+ - daidrv = devm_kcalloc(dev, dai_count, sizeof(*daidrv), GFP_KERNEL); - if (!daidrv) - return -ENOMEM; + struct cs42xx8_priv *cs42xx8; diff --git a/sound/soc/codecs/i-sabre-codec.c b/sound/soc/codecs/i-sabre-codec.c new file mode 100644 -index 000000000000..714e1f5852cb +index 000000000000..518c57f4558e --- /dev/null +++ b/sound/soc/codecs/i-sabre-codec.c -@@ -0,0 +1,392 @@ +@@ -0,0 +1,389 @@ +/* + * Driver for I-Sabre Q2M + * @@ -197362,8 +254234,7 @@ +} + + -+static int i_sabre_codec_i2c_probe( -+ struct i2c_client *i2c, const struct i2c_device_id *id) ++static int i_sabre_codec_i2c_probe(struct i2c_client *i2c) +{ + struct regmap *regmap; + @@ -197375,11 +254246,9 @@ + return i_sabre_codec_probe(&i2c->dev, regmap); +} + -+static int i_sabre_codec_i2c_remove(struct i2c_client *i2c) ++static void i_sabre_codec_i2c_remove(struct i2c_client *i2c) +{ + i_sabre_codec_remove(&i2c->dev); -+ -+ return 0; +} + + @@ -197461,10 +254330,10 @@ +#endif /* _SND_SOC_ISABRECODEC */ diff --git a/sound/soc/codecs/ma120x0p.c b/sound/soc/codecs/ma120x0p.c new file mode 100644 -index 000000000000..c447d37450b7 +index 000000000000..3df7e759ace1 --- /dev/null +++ b/sound/soc/codecs/ma120x0p.c -@@ -0,0 +1,1384 @@ +@@ -0,0 +1,1380 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * ASoC Driver for Infineon Merus(TM) ma120x0p multi-level class-D amplifier @@ -198355,19 +255224,19 @@ + 0x70, + }; + -+static const SOC_VALUE_ENUM_SINGLE_DECL(pwr_mode_ctrl, ++static SOC_VALUE_ENUM_SINGLE_DECL(pwr_mode_ctrl, + ma_pm_man__a, 0, 0x70, + pwr_mode_texts, + pwr_mode_values); + -+static const DECLARE_TLV_DB_SCALE(ma120x0p_vol_tlv, -5000, 100, 0); ++static const DECLARE_TLV_DB_SCALE(ma120x0p_vol_tlv, -14400, 100, 0); +static const DECLARE_TLV_DB_SCALE(ma120x0p_lim_tlv, -5000, 100, 0); +static const DECLARE_TLV_DB_SCALE(ma120x0p_lr_tlv, -5000, 100, 0); + +static const struct snd_kcontrol_new ma120x0p_snd_controls = { + //Master Volume + SOC_SINGLE_RANGE_TLV("A.Mstr Vol Volume", -+ ma_vol_db_master__a, 0, 0x18, 0x4a, 1, ma120x0p_vol_tlv), ++ ma_vol_db_master__a, 0, 0x18, 0xa8, 1, ma120x0p_vol_tlv), + + //L-R Volume ch0 + SOC_SINGLE_RANGE_TLV("B.L Vol Volume", @@ -198646,7 +255515,6 @@ + .num_controls = ARRAY_SIZE(ma120x0p_snd_controls), + .use_pmdown_time = 1, + .endianness = 1, -+ .non_legacy_dai_naming = 1, +}; + +//I2C Driver @@ -198683,8 +255551,7 @@ + .num_reg_defaults = ARRAY_SIZE(ma120x0p_reg_defaults), +}; + -+static int ma120x0p_i2c_probe(struct i2c_client *i2c, -+ const struct i2c_device_id *id) ++static int ma120x0p_i2c_probe(struct i2c_client *i2c) +{ + int ret; + @@ -198776,7 +255643,7 @@ + return IRQ_HANDLED; +} + -+static int ma120x0p_i2c_remove(struct i2c_client *i2c) ++static void ma120x0p_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_component(&i2c->dev); + i2c_set_clientdata(i2c, NULL); @@ -198789,8 +255656,6 @@ + msleep(200); + + kfree(priv_data); -+ -+ return 0; +} + +static void ma120x0p_i2c_shutdown(struct i2c_client *i2c) @@ -198924,11 +255789,41 @@ +MODULE_DESCRIPTION("ASoC PCM1794A codec driver"); +MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>"); +MODULE_LICENSE("GPL v2"); +diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c +index 5cd2b64b9337..4be476a280e1 100644 +--- a/sound/soc/codecs/pcm512x-i2c.c ++++ b/sound/soc/codecs/pcm512x-i2c.c +@@ -39,6 +39,8 @@ static const struct i2c_device_id pcm512x_i2c_id = { + { "pcm5122", }, + { "pcm5141", }, + { "pcm5142", }, ++ { "tas5754", }, ++ { "tas5756", }, + { } + }; + MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id); +@@ -49,6 +51,8 @@ static const struct of_device_id pcm512x_of_match = { + { .compatible = "ti,pcm5122", }, + { .compatible = "ti,pcm5141", }, + { .compatible = "ti,pcm5142", }, ++ { .compatible = "ti,tas5754", }, ++ { .compatible = "ti,tas5756", }, + { } + }; + MODULE_DEVICE_TABLE(of, pcm512x_of_match); diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c -index 8153d3d01654..7a5b716c8add 100644 +index 89059a673cf0..6fb35e656455 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c -@@ -534,7 +534,7 @@ static unsigned long pcm512x_ncp_target(struct pcm512x_priv *pcm512x, +@@ -48,6 +48,7 @@ struct pcm512x_priv { + int mute; + struct mutex mutex; + unsigned int bclk_ratio; ++ int force_pll_on; + }; + + /* +@@ -536,7 +537,7 @@ static unsigned long pcm512x_ncp_target(struct pcm512x_priv *pcm512x, static const u32 pcm512x_dai_rates = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, @@ -198937,12 +255832,62 @@ }; static const struct snd_pcm_hw_constraint_list constraints_slave = { +@@ -1258,10 +1259,34 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, + return ret; + } + +- ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN, +- PCM512x_PLLE, 0); ++ if (!pcm512x->force_pll_on) { ++ ret = regmap_update_bits(pcm512x->regmap, ++ PCM512x_PLL_EN, PCM512x_PLLE, 0); ++ } else { ++ /* provide minimum PLL config for TAS575x clocking ++ * and leave PLL enabled ++ */ ++ ret = regmap_write(pcm512x->regmap, ++ PCM512x_PLL_COEFF_0, 0x01); ++ if (ret != 0) { ++ dev_err(component->dev, ++ "Failed to set pll coefficient: %d\n", ret); ++ return ret; ++ } ++ ret = regmap_write(pcm512x->regmap, ++ PCM512x_PLL_COEFF_1, 0x04); ++ if (ret != 0) { ++ dev_err(component->dev, ++ "Failed to set pll coefficient: %d\n", ret); ++ return ret; ++ } ++ ret = regmap_write(pcm512x->regmap, ++ PCM512x_PLL_EN, 0x01); ++ dev_dbg(component->dev, "Enabling PLL for TAS575x\n"); ++ } ++ + if (ret != 0) { +- dev_err(component->dev, "Failed to disable pll: %d\n", ret); ++ dev_err(component->dev, "Failed to set pll mode: %d\n", ret); + return ret; + } + } +@@ -1659,6 +1684,11 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap) + ret = -EINVAL; + goto err_pm; + } ++ ++ if (!strcmp(np->name, "tas5756") || ++ !strcmp(np->name, "tas5754")) ++ pcm512x->force_pll_on = 1; ++ dev_dbg(dev, "Device ID: %s\n", np->name); + } + #endif + diff --git a/sound/soc/codecs/tas5713.c b/sound/soc/codecs/tas5713.c new file mode 100644 -index 000000000000..53acd2b355d6 +index 000000000000..01dd21a1d7a2 --- /dev/null +++ b/sound/soc/codecs/tas5713.c -@@ -0,0 +1,363 @@ +@@ -0,0 +1,360 @@ +/* + * ASoC Driver for TAS5713 + * @@ -199226,8 +256171,7 @@ +}; + + -+static int tas5713_i2c_probe(struct i2c_client *i2c, -+ const struct i2c_device_id *id) ++static int tas5713_i2c_probe(struct i2c_client *i2c) +{ + int ret; + @@ -199250,14 +256194,12 @@ +} + + -+static int tas5713_i2c_remove(struct i2c_client *i2c) ++static void tas5713_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_component(&i2c->dev); + i2c_set_clientdata(i2c, NULL); + + kfree(priv_data); -+ -+ return 0; +} + + @@ -199522,11 +256464,379 @@ + + +#endif /* _TAS5713_H */ +diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c +index 9ea4be56d3b7..e45c31741cc6 100644 +--- a/sound/soc/dwc/dwc-i2s.c ++++ b/sound/soc/dwc/dwc-i2s.c +@@ -21,7 +21,7 @@ + #include <linux/reset.h> + #include <linux/slab.h> + #include <linux/pm_runtime.h> +-#include <sound/designware_i2s.h> ++#include <sound/designware_i2s.h> + #include <sound/pcm.h> + #include <sound/pcm_params.h> + #include <sound/soc.h> +@@ -208,15 +208,10 @@ static void i2s_start(struct dw_i2s_dev *dev, + i2s_write_reg(dev->i2s_base, CER, 1); + } + +-static void i2s_stop(struct dw_i2s_dev *dev, +- struct snd_pcm_substream *substream) ++static void i2s_pause(struct dw_i2s_dev *dev, struct snd_pcm_substream *substream) + { + + i2s_clear_irqs(dev, substream->stream); +- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) +- i2s_write_reg(dev->i2s_base, ITER, 0); +- else +- i2s_write_reg(dev->i2s_base, IRER, 0); + + if (dev->use_pio || dev->is_jh7110) + i2s_disable_irqs(dev, substream->stream, 8); +@@ -225,33 +220,32 @@ static void i2s_stop(struct dw_i2s_dev *dev, + + if (!dev->active) { + i2s_write_reg(dev->i2s_base, CER, 0); +- i2s_write_reg(dev->i2s_base, IER, 0); ++ /* Keep the device enabled until the shutdown - do not clear IER */ + } + } + +-static int dw_i2s_startup(struct snd_pcm_substream *substream, +- struct snd_soc_dai *cpu_dai) ++static void i2s_stop(struct dw_i2s_dev *dev, struct snd_pcm_substream *substream) + { +- struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); +- +- if (dev->is_jh7110) { +- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); +- struct snd_soc_dai_link *dai_link = rtd->dai_link; +- +- dai_link->trigger_stop = SND_SOC_TRIGGER_ORDER_LDC; +- } ++ i2s_clear_irqs(dev, substream->stream); + +- return 0; ++ i2s_disable_irqs(dev, substream->stream, 8); + } + + static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) + { + u32 ch_reg; + struct i2s_clk_config_data *config = &dev->config; +- ++ u32 dmacr; + + i2s_disable_channels(dev, stream); + ++ dmacr = i2s_read_reg(dev->i2s_base, I2S_DMACR); ++ ++ if (stream == SNDRV_PCM_STREAM_PLAYBACK) ++ dmacr &= ~(DMACR_DMAEN_TXCH0 * 0xf); ++ else ++ dmacr &= ~(DMACR_DMAEN_RXCH0 * 0xf); ++ + for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + i2s_write_reg(dev->i2s_base, TCR(ch_reg), +@@ -260,6 +254,7 @@ static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) + dev->fifo_th - 1); + i2s_write_reg(dev->i2s_base, TER(ch_reg), TER_TXCHEN | + dev->tdm_mask << TER_TXSLOT_SHIFT); ++ dmacr |= (DMACR_DMAEN_TXCH0 << ch_reg); + } else { + i2s_write_reg(dev->i2s_base, RCR(ch_reg), + dev->xfer_resolution); +@@ -267,9 +262,11 @@ static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) + dev->fifo_th - 1); + i2s_write_reg(dev->i2s_base, RER(ch_reg), RER_RXCHEN | + dev->tdm_mask << RER_RXSLOT_SHIFT); ++ dmacr |= (DMACR_DMAEN_RXCH0 << ch_reg); + } +- + } ++ ++ i2s_write_reg(dev->i2s_base, I2S_DMACR, dmacr); + } + + static int dw_i2s_hw_params(struct snd_pcm_substream *substream, +@@ -277,24 +274,32 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, + { + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + struct i2s_clk_config_data *config = &dev->config; ++ union dw_i2s_snd_dma_data *dma_data = NULL; + int ret; + ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ dma_data = &dev->play_dma_data; ++ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ++ dma_data = &dev->capture_dma_data; ++ else ++ return -1; ++ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + config->data_width = 16; +- dev->ccr = 0x00; ++ dma_data->dt.addr_width = 2; + dev->xfer_resolution = 0x02; + break; + + case SNDRV_PCM_FORMAT_S24_LE: + config->data_width = 24; +- dev->ccr = 0x08; ++ dma_data->dt.addr_width = 4; + dev->xfer_resolution = 0x04; + break; + + case SNDRV_PCM_FORMAT_S32_LE: + config->data_width = 32; +- dev->ccr = 0x10; ++ dma_data->dt.addr_width = 4; + dev->xfer_resolution = 0x05; + break; + +@@ -315,17 +320,37 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, + case TWO_CHANNEL_SUPPORT: + break; + default: +- dev_err(dev->dev, "channel not supported\n"); ++ dev_err(dev->dev, "channel count %d not supported\n", config->chan_nr); + return -EINVAL; + } + + dw_i2s_config(dev, substream->stream); + +- i2s_write_reg(dev->i2s_base, CCR, dev->ccr); +- + config->sample_rate = params_rate(params); + + if (dev->capability & DW_I2S_MASTER) { ++ u32 frame_length = config->data_width * 2; ++ ++ if (dev->bclk_ratio) ++ frame_length = dev->bclk_ratio; ++ ++ switch (frame_length) { ++ case 32: ++ dev->ccr = 0x00; ++ break; ++ ++ case 48: ++ dev->ccr = 0x08; ++ break; ++ ++ case 64: ++ dev->ccr = 0x10; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ + if (dev->i2s_clk_cfg) { + ret = dev->i2s_clk_cfg(config); + if (ret < 0) { +@@ -333,8 +358,7 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, + return ret; + } + } else { +- u32 bitclk = config->sample_rate * +- config->data_width * 2; ++ u32 bitclk = config->sample_rate * frame_length; + + ret = clk_set_rate(dev->clk, bitclk); + if (ret) { +@@ -343,10 +367,71 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, + return ret; + } + } ++ ++ i2s_write_reg(dev->i2s_base, CCR, dev->ccr); + } + return 0; + } + ++static int dw_i2s_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *cpu_dai) ++{ ++ struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); ++ union dw_i2s_snd_dma_data *dma_data = NULL; ++ u32 dmacr; ++ ++ dev_dbg(dev->dev, "%s(%s)\n", __func__, substream->name); ++ if (!(dev->capability & DWC_I2S_RECORD) && ++ substream->stream == SNDRV_PCM_STREAM_CAPTURE) ++ return -EINVAL; ++ ++ if (!(dev->capability & DWC_I2S_PLAY) && ++ substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ return -EINVAL; ++ ++ dw_i2s_config(dev, substream->stream); ++ dmacr = i2s_read_reg(dev->i2s_base, I2S_DMACR); ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ dma_data = &dev->play_dma_data; ++ dmacr |= DMACR_DMAEN_TX; ++ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { ++ dma_data = &dev->capture_dma_data; ++ dmacr |= DMACR_DMAEN_RX; ++ } ++ ++ snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data); ++ i2s_write_reg(dev->i2s_base, I2S_DMACR, dmacr); ++ ++ if (dev->is_jh7110) { ++ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); ++ struct snd_soc_dai_link *dai_link = rtd->dai_link; ++ ++ dai_link->trigger_stop = SND_SOC_TRIGGER_ORDER_LDC; ++ } ++ ++ return 0; ++} ++ ++static void dw_i2s_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ ++ dev_dbg(dev->dev, "%s(%s)\n", __func__, substream->name); ++ i2s_disable_channels(dev, substream->stream); ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ i2s_write_reg(dev->i2s_base, ITER, 0); ++ else ++ i2s_write_reg(dev->i2s_base, IRER, 0); ++ ++ i2s_disable_irqs(dev, substream->stream, 8); ++ ++ if (!dev->active) { ++ i2s_write_reg(dev->i2s_base, CER, 0); ++ i2s_write_reg(dev->i2s_base, IER, 0); ++ } ++} ++ + static int dw_i2s_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) + { +@@ -374,9 +459,12 @@ static int dw_i2s_trigger(struct snd_pcm_substream *substream, + i2s_start(dev, substream); + break; + ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ dev->active--; ++ i2s_pause(dev, substream); ++ break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: +- case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + dev->active--; + i2s_stop(dev, substream); + break; +@@ -460,6 +548,18 @@ static int dw_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, unsigned int tx_mask + return 0; + } + ++static int dw_i2s_set_bclk_ratio(struct snd_soc_dai *cpu_dai, ++ unsigned int ratio) ++{ ++ struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); ++ ++ dev_dbg(dev->dev, "%s(%d)\n", __func__, ratio); ++ ++ dev->bclk_ratio = ratio; ++ ++ return 0; ++} ++ + static int dw_i2s_dai_probe(struct snd_soc_dai *dai) + { + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); +@@ -471,11 +571,13 @@ static int dw_i2s_dai_probe(struct snd_soc_dai *dai) + static const struct snd_soc_dai_ops dw_i2s_dai_ops = { + .probe = dw_i2s_dai_probe, + .startup = dw_i2s_startup, ++ .shutdown = dw_i2s_shutdown, + .hw_params = dw_i2s_hw_params, + .prepare = dw_i2s_prepare, + .trigger = dw_i2s_trigger, + .set_fmt = dw_i2s_set_fmt, + .set_tdm_slot = dw_i2s_set_tdm_slot, ++ .set_bclk_ratio = dw_i2s_set_bclk_ratio, + }; + + #ifdef CONFIG_PM +@@ -606,7 +708,7 @@ static int dw_configure_dai(struct dw_i2s_dev *dev, + idx = 1; + dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM; + dw_i2s_dai->playback.channels_max = +- 1 << (COMP1_TX_CHANNELS(comp1) + 1); ++ 2 * (COMP1_TX_CHANNELS(comp1) + 1); + dw_i2s_dai->playback.formats = formatsidx; + dw_i2s_dai->playback.rates = rates; + } +@@ -620,7 +722,7 @@ static int dw_configure_dai(struct dw_i2s_dev *dev, + idx = 1; + dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM; + dw_i2s_dai->capture.channels_max = +- 1 << (COMP1_RX_CHANNELS(comp1) + 1); ++ 2 * (COMP1_RX_CHANNELS(comp1) + 1); + dw_i2s_dai->capture.formats = formatsidx; + dw_i2s_dai->capture.rates = rates; + } +@@ -702,7 +804,7 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, + u32 idx2; + int ret; + +- ret = dw_configure_dai(dev, dw_i2s_dai, SNDRV_PCM_RATE_8000_192000); ++ ret = dw_configure_dai(dev, dw_i2s_dai, SNDRV_PCM_RATE_8000_384000); + if (ret < 0) + return ret; + +@@ -968,6 +1070,7 @@ static int dw_i2s_probe(struct platform_device *pdev) + } + } + ++ dev->bclk_ratio = 0; + dev->i2s_reg_comp1 = I2S_COMP_PARAM_1; + dev->i2s_reg_comp2 = I2S_COMP_PARAM_2; + if (pdata) { +diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h +index dce88c9ad5f3..9f21eb68bd6c 100644 +--- a/sound/soc/dwc/local.h ++++ b/sound/soc/dwc/local.h +@@ -63,6 +63,17 @@ + #define TER_TXSLOT_SHIFT 8 + #define TER_TXCHEN BIT(0) + ++#define DMACR_DMAEN_TX BIT(17) ++#define DMACR_DMAEN_RX BIT(16) ++#define DMACR_DMAEN_TXCH3 BIT(11) ++#define DMACR_DMAEN_TXCH2 BIT(10) ++#define DMACR_DMAEN_TXCH1 BIT(9) ++#define DMACR_DMAEN_TXCH0 BIT(8) ++#define DMACR_DMAEN_RXCH3 BIT(3) ++#define DMACR_DMAEN_RXCH2 BIT(2) ++#define DMACR_DMAEN_RXCH1 BIT(1) ++#define DMACR_DMAEN_RXCH0 BIT(0) ++ + /* I2SCOMPRegisters */ + #define I2S_COMP_PARAM_2 0x01F0 + #define I2S_COMP_PARAM_1 0x01F4 +@@ -117,6 +128,7 @@ struct dw_i2s_dev { + unsigned int quirks; + unsigned int i2s_reg_comp1; + unsigned int i2s_reg_comp2; ++ unsigned int bclk_ratio; + struct device *dev; + u32 ccr; + u32 xfer_resolution; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c -index 133296596864..cdea2d46bef8 100644 +index 9de98c01d815..25f695474209 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c -@@ -1016,7 +1016,7 @@ int snd_soc_add_pcm_runtime(struct snd_soc_card *card, +@@ -1080,7 +1080,7 @@ static int snd_soc_add_pcm_runtime(struct snd_soc_card *card, for_each_link_cpus(dai_link, i, cpu) { asoc_rtd_to_cpu(rtd, i) = snd_soc_find_dai(cpu); if (!asoc_rtd_to_cpu(rtd, i)) { @@ -199535,7 +256845,7 @@ cpu->dai_name); goto _err_defer; } -@@ -1027,7 +1027,7 @@ int snd_soc_add_pcm_runtime(struct snd_soc_card *card, +@@ -1091,7 +1091,7 @@ static int snd_soc_add_pcm_runtime(struct snd_soc_card *card, for_each_link_codecs(dai_link, i, codec) { asoc_rtd_to_codec(rtd, i) = snd_soc_find_dai(codec); if (!asoc_rtd_to_codec(rtd, i)) { @@ -199544,8 +256854,8 @@ codec->dai_name); goto _err_defer; } -@@ -1429,7 +1429,15 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, - int ret; +@@ -1313,7 +1313,15 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, + return 0; for_each_rtd_codec_dais(rtd, i, codec_dai) { - ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt); @@ -199558,53 +256868,42 @@ + } + + ret = snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); - if (ret != 0 && ret != -ENOTSUPP) { - dev_warn(codec_dai->dev, - "ASoC: Failed to set DAI format: %d\n", ret); -diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h -index aabd3a10ec5b..f45a570be4ab 100644 ---- a/sound/usb/quirks-table.h -+++ b/sound/usb/quirks-table.h -@@ -46,6 +46,15 @@ - } - }, - -+{ -+ /* A4Tech FHD 1080p webcam */ -+ USB_DEVICE(0x09da, 0x2695), -+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { -+ .ifnum = QUIRK_ANY_INTERFACE, -+ .type = QUIRK_SETUP_DISABLE_AUTOSUSPEND + if (ret != 0 && ret != -ENOTSUPP) + return ret; + } +diff --git a/sound/usb/card.c b/sound/usb/card.c +index 1b2edc0fd2e9..297d6ad1d8c0 100644 +--- a/sound/usb/card.c ++++ b/sound/usb/card.c +@@ -857,8 +857,14 @@ static int usb_audio_probe(struct usb_interface *intf, + if (ignore_ctl_error) + chip->quirk_flags |= QUIRK_FLAG_IGNORE_CTL_ERROR; + +- if (chip->quirk_flags & QUIRK_FLAG_DISABLE_AUTOSUSPEND) ++ if (chip->quirk_flags & QUIRK_FLAG_DISABLE_AUTOSUSPEND) { ++ /* ++ * Grab the interface, because on a webcam uvcvideo may race ++ * with snd-usb-audio during probe and re-enable autosuspend. ++ */ ++ usb_autopm_get_interface(intf); + usb_disable_autosuspend(interface_to_usbdev(intf)); + } -+}, -+ - { - /* Creative BT-D1 */ - USB_DEVICE(0x041e, 0x0005), + + /* + * For devices with more than one control interface, we assume the diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c -index 6333a2ecb848..e5cb6daf2747 100644 +index 09712e61c606..48e0226b2d34 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c -@@ -531,6 +531,11 @@ static int setup_disable_autosuspend(struct snd_usb_audio *chip, - struct usb_driver *driver, - const struct snd_usb_audio_quirk *quirk) - { -+ /* -+ * Grab the interface, because on a webcam uvcvideo may race -+ * with snd-usb-audio during probe and re-enable autosuspend. -+ */ -+ usb_autopm_get_interface(iface); - usb_disable_autosuspend(interface_to_usbdev(iface)); - return 1; /* Continue with creating streams and mixer */ - } -@@ -1530,6 +1535,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) - case USB_ID(0x2912, 0x30c8): /* Audioengine D1 */ - case USB_ID(0x413c, 0xa506): /* Dell AE515 sound bar */ - case USB_ID(0x046d, 0x084c): /* Logitech ConferenceCam Connect */ -+ case USB_ID(0x09da, 0x2695): /* A4Tech FHD 1080p webcam */ - return true; - } +@@ -2185,6 +2185,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table = { + QUIRK_FLAG_ALIGN_TRANSFER), + DEVICE_FLG(0x534d, 0x2109, /* MacroSilicon MS2109 */ + QUIRK_FLAG_ALIGN_TRANSFER), ++ DEVICE_FLG(0x09da, 0x2695, /* A4Tech FHD 1080p webcam */ ++ QUIRK_FLAG_DISABLE_AUTOSUSPEND | QUIRK_FLAG_GET_SAMPLE_RATE), + /* Vendor matches */ + VENDOR_FLG(0x045e, /* MS Lifecam */ -- -2.27.0 +2.33.0
View file
_service:tar_scm:SOURCE
Changed
@@ -1,1 +1,1 @@ -6.6.0-19.0.0 +6.6.0-20.0.0
View file
_service:tar_scm:_multibuild
Added
@@ -0,0 +1,3 @@ +<multibuild> + <flavor>raspberrypi-kernel</flavor> +</multibuild>
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2